- Remove calls to VoEDtmf from WVoE/MC.
- Flatten logic and make the relevant calls on VoE::Channel from AudioSendStream::SendTelephoneEvent().
- Store current payload type for telephone events in WVoMC, instead of setting it on the Channel. This should be refactored to be an AudioSendStream::Config parameter when we redo WVoMC::SetSendCodecs().
BUG=webrtc:4690
R=pthatcher@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1491743004 .
Cr-Commit-Position: refs/heads/master@{#10895}
diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc
index d86bfb5..bf51fb3 100644
--- a/talk/media/webrtc/fakewebrtccall.cc
+++ b/talk/media/webrtc/fakewebrtccall.cc
@@ -39,14 +39,27 @@
RTC_DCHECK(config.voe_channel_id != -1);
}
+const webrtc::AudioSendStream::Config&
+ FakeAudioSendStream::GetConfig() const {
+ return config_;
+}
+
void FakeAudioSendStream::SetStats(
const webrtc::AudioSendStream::Stats& stats) {
stats_ = stats;
}
-const webrtc::AudioSendStream::Config&
- FakeAudioSendStream::GetConfig() const {
- return config_;
+FakeAudioSendStream::TelephoneEvent
+ FakeAudioSendStream::GetLatestTelephoneEvent() const {
+ return latest_telephone_event_;
+}
+
+bool FakeAudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) {
+ latest_telephone_event_.payload_type = payload_type;
+ latest_telephone_event_.event_code = event;
+ latest_telephone_event_.duration_ms = duration_ms;
+ return true;
}
webrtc::AudioSendStream::Stats FakeAudioSendStream::GetStats() const {
diff --git a/talk/media/webrtc/fakewebrtccall.h b/talk/media/webrtc/fakewebrtccall.h
index 2e70390..024c50d 100644
--- a/talk/media/webrtc/fakewebrtccall.h
+++ b/talk/media/webrtc/fakewebrtccall.h
@@ -49,10 +49,17 @@
namespace cricket {
class FakeAudioSendStream final : public webrtc::AudioSendStream {
public:
+ struct TelephoneEvent {
+ int payload_type = -1;
+ uint8_t event_code = 0;
+ uint32_t duration_ms = 0;
+ };
+
explicit FakeAudioSendStream(const webrtc::AudioSendStream::Config& config);
const webrtc::AudioSendStream::Config& GetConfig() const;
void SetStats(const webrtc::AudioSendStream::Stats& stats);
+ TelephoneEvent GetLatestTelephoneEvent() const;
private:
// webrtc::SendStream implementation.
@@ -64,8 +71,11 @@
}
// webrtc::AudioSendStream implementation.
+ bool SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) override;
webrtc::AudioSendStream::Stats GetStats() const override;
+ TelephoneEvent latest_telephone_event_;
webrtc::AudioSendStream::Config config_;
webrtc::AudioSendStream::Stats stats_;
};
diff --git a/talk/media/webrtc/fakewebrtcvoiceengine.h b/talk/media/webrtc/fakewebrtcvoiceengine.h
index 9209863..65c3deb 100644
--- a/talk/media/webrtc/fakewebrtcvoiceengine.h
+++ b/talk/media/webrtc/fakewebrtcvoiceengine.h
@@ -145,20 +145,11 @@
class FakeWebRtcVoiceEngine
: public webrtc::VoEAudioProcessing,
- public webrtc::VoEBase, public webrtc::VoECodec, public webrtc::VoEDtmf,
+ public webrtc::VoEBase, public webrtc::VoECodec,
public webrtc::VoEHardware,
public webrtc::VoENetwork, public webrtc::VoERTP_RTCP,
public webrtc::VoEVolumeControl {
public:
- struct DtmfInfo {
- DtmfInfo()
- : dtmf_event_code(-1),
- dtmf_out_of_band(false),
- dtmf_length_ms(-1) {}
- int dtmf_event_code;
- bool dtmf_out_of_band;
- int dtmf_length_ms;
- };
struct Channel {
explicit Channel()
: external_transport(false),
@@ -173,7 +164,6 @@
nack(false),
cn8_type(13),
cn16_type(105),
- dtmf_type(106),
red_type(117),
nack_max_packets(0),
send_ssrc(0),
@@ -195,12 +185,10 @@
bool nack;
int cn8_type;
int cn16_type;
- int dtmf_type;
int red_type;
int nack_max_packets;
uint32_t send_ssrc;
int associate_send_channel;
- DtmfInfo dtmf_info;
std::vector<webrtc::CodecInst> recv_codecs;
webrtc::CodecInst send_codec;
webrtc::PacketTime last_rtp_packet_time;
@@ -281,9 +269,6 @@
channels_[channel]->cn16_type :
channels_[channel]->cn8_type;
}
- int GetSendTelephoneEventPayloadType(int channel) {
- return channels_[channel]->dtmf_type;
- }
int GetSendREDPayloadType(int channel) {
return channels_[channel]->red_type;
}
@@ -552,26 +537,6 @@
return 0;
}
- // webrtc::VoEDtmf
- WEBRTC_FUNC(SendTelephoneEvent, (int channel, int event_code,
- bool out_of_band = true, int length_ms = 160, int attenuation_db = 10)) {
- channels_[channel]->dtmf_info.dtmf_event_code = event_code;
- channels_[channel]->dtmf_info.dtmf_out_of_band = out_of_band;
- channels_[channel]->dtmf_info.dtmf_length_ms = length_ms;
- return 0;
- }
- WEBRTC_FUNC(SetSendTelephoneEventPayloadType,
- (int channel, unsigned char type)) {
- channels_[channel]->dtmf_type = type;
- return 0;
- };
- WEBRTC_STUB(GetSendTelephoneEventPayloadType,
- (int channel, unsigned char& type));
- WEBRTC_STUB(SetDtmfFeedbackStatus, (bool enable, bool directFeedback));
- WEBRTC_STUB(GetDtmfFeedbackStatus, (bool& enabled, bool& directFeedback));
- WEBRTC_STUB(PlayDtmfTone,
- (int event_code, int length_ms = 200, int attenuation_db = 10));
-
// webrtc::VoEHardware
WEBRTC_FUNC(GetNumOfRecordingDevices, (int& num)) {
return GetNumDevices(num);
@@ -831,15 +796,6 @@
void EnableStereoChannelSwapping(bool enable) {
stereo_swapping_enabled_ = enable;
}
- bool WasSendTelephoneEventCalled(int channel, int event_code, int length_ms) {
- return (channels_[channel]->dtmf_info.dtmf_event_code == event_code &&
- channels_[channel]->dtmf_info.dtmf_out_of_band == true &&
- channels_[channel]->dtmf_info.dtmf_length_ms == length_ms);
- }
- bool WasPlayDtmfToneCalled(int event_code, int length_ms) {
- return (dtmf_info_.dtmf_event_code == event_code &&
- dtmf_info_.dtmf_length_ms == length_ms);
- }
int GetNetEqCapacity() const {
auto ch = channels_.find(last_channel_);
ASSERT(ch != channels_.end());
@@ -910,7 +866,6 @@
int send_fail_channel_;
int recording_sample_rate_;
int playout_sample_rate_;
- DtmfInfo dtmf_info_;
FakeAudioProcessing audio_processing_;
};
diff --git a/talk/media/webrtc/webrtcvoe.h b/talk/media/webrtc/webrtcvoe.h
index 1e104b4..aa705a0 100644
--- a/talk/media/webrtc/webrtcvoe.h
+++ b/talk/media/webrtc/webrtcvoe.h
@@ -36,7 +36,6 @@
#include "webrtc/voice_engine/include/voe_audio_processing.h"
#include "webrtc/voice_engine/include/voe_base.h"
#include "webrtc/voice_engine/include/voe_codec.h"
-#include "webrtc/voice_engine/include/voe_dtmf.h"
#include "webrtc/voice_engine/include/voe_errors.h"
#include "webrtc/voice_engine/include/voe_hardware.h"
#include "webrtc/voice_engine/include/voe_network.h"
@@ -91,14 +90,13 @@
public:
VoEWrapper()
: engine_(webrtc::VoiceEngine::Create()), processing_(engine_),
- base_(engine_), codec_(engine_), dtmf_(engine_),
+ base_(engine_), codec_(engine_),
hw_(engine_), network_(engine_),
rtp_(engine_), volume_(engine_) {
}
VoEWrapper(webrtc::VoEAudioProcessing* processing,
webrtc::VoEBase* base,
webrtc::VoECodec* codec,
- webrtc::VoEDtmf* dtmf,
webrtc::VoEHardware* hw,
webrtc::VoENetwork* network,
webrtc::VoERTP_RTCP* rtp,
@@ -107,7 +105,6 @@
processing_(processing),
base_(base),
codec_(codec),
- dtmf_(dtmf),
hw_(hw),
network_(network),
rtp_(rtp),
@@ -118,7 +115,6 @@
webrtc::VoEAudioProcessing* processing() const { return processing_.get(); }
webrtc::VoEBase* base() const { return base_.get(); }
webrtc::VoECodec* codec() const { return codec_.get(); }
- webrtc::VoEDtmf* dtmf() const { return dtmf_.get(); }
webrtc::VoEHardware* hw() const { return hw_.get(); }
webrtc::VoENetwork* network() const { return network_.get(); }
webrtc::VoERTP_RTCP* rtp() const { return rtp_.get(); }
@@ -130,7 +126,6 @@
scoped_voe_ptr<webrtc::VoEAudioProcessing> processing_;
scoped_voe_ptr<webrtc::VoEBase> base_;
scoped_voe_ptr<webrtc::VoECodec> codec_;
- scoped_voe_ptr<webrtc::VoEDtmf> dtmf_;
scoped_voe_ptr<webrtc::VoEHardware> hw_;
scoped_voe_ptr<webrtc::VoENetwork> network_;
scoped_voe_ptr<webrtc::VoERTP_RTCP> rtp_;
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index d1f76ef..d70c864 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -134,6 +134,12 @@
const char kAecDumpByAudioOptionFilename[] = "audio.aecdump";
#endif
+// Constants from voice_engine_defines.h.
+const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1)
+const int kMaxTelephoneEventCode = 255;
+const int kMinTelephoneEventDuration = 100;
+const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16
+
bool ValidateStreamParams(const StreamParams& sp) {
if (sp.ssrcs.empty()) {
LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString();
@@ -582,12 +588,6 @@
LOG(LS_INFO) << ToString(codec);
}
- // Disable the DTMF playout when a tone is sent.
- // PlayDtmfTone will be used if local playout is needed.
- if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) {
- LOG_RTCERR1(SetDtmfFeedbackStatus, false);
- }
-
initialized_ = true;
return true;
}
@@ -1258,6 +1258,13 @@
RTC_CHECK(stream_);
}
+ bool SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) {
+ RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+ RTC_DCHECK(stream_);
+ return stream_->SendTelephoneEvent(payload_type, event, duration_ms);
+ }
+
webrtc::AudioSendStream::Stats GetStats() const {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
RTC_DCHECK(stream_);
@@ -1612,7 +1619,7 @@
engine()->voe()->codec()->SetFECStatus(channel, false);
// Scan through the list to figure out the codec to use for sending, along
- // with the proper configuration for VAD and DTMF.
+ // with the proper configuration for VAD.
bool found_send_codec = false;
webrtc::CodecInst send_codec;
memset(&send_codec, 0, sizeof(send_codec));
@@ -1741,7 +1748,7 @@
SetSendBitrateInternal(send_bitrate_bps_);
}
- // Loop through the codecs list again to config the telephone-event/CN codec.
+ // Loop through the codecs list again to config the CN codec.
for (const AudioCodec& codec : codecs) {
// Ignore codecs we don't know about. The negotiation step should prevent
// this, but double-check to be sure.
@@ -1751,15 +1758,7 @@
continue;
}
- // Find the DTMF telephone event "codec" and tell VoiceEngine channels
- // about it.
- if (IsCodec(codec, kDtmfCodecName)) {
- if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType(
- channel, codec.id) == -1) {
- LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, codec.id);
- return false;
- }
- } else if (IsCodec(codec, kCnCodecName)) {
+ if (IsCodec(codec, kCnCodecName)) {
// Turn voice activity detection/comfort noise on if supported.
// Set the wideband CN payload type appropriately.
// (narrowband always uses the static payload type 13).
@@ -1814,12 +1813,16 @@
bool WebRtcVoiceMediaChannel::SetSendCodecs(
const std::vector<AudioCodec>& codecs) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
+ // TODO(solenberg): Validate input - that payload types don't overlap, are
+ // within range, filter out codecs we don't support,
+ // redundant codecs etc.
- dtmf_allowed_ = false;
+ // Find the DTMF telephone event "codec" payload type.
+ dtmf_payload_type_ = rtc::Optional<int>();
for (const AudioCodec& codec : codecs) {
- // Find the DTMF telephone event "codec".
if (IsCodec(codec, kDtmfCodecName)) {
- dtmf_allowed_ = true;
+ dtmf_payload_type_ = rtc::Optional<int>(codec.id);
+ break;
}
}
@@ -2282,38 +2285,34 @@
}
bool WebRtcVoiceMediaChannel::CanInsertDtmf() {
- return dtmf_allowed_;
+ return dtmf_payload_type_ ? true : false;
}
bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event,
int duration) {
RTC_DCHECK(worker_thread_checker_.CalledOnValidThread());
- if (!dtmf_allowed_) {
+ LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf";
+ if (!dtmf_payload_type_) {
return false;
}
- // Send the event.
- int channel = -1;
- if (ssrc == 0) {
- if (send_streams_.size() > 0) {
- channel = send_streams_.begin()->second->channel();
- }
- } else {
- channel = GetSendChannelId(ssrc);
- }
- if (channel == -1) {
- LOG(LS_WARNING) << "InsertDtmf - The specified ssrc "
- << ssrc << " is not in use.";
+ // Figure out which WebRtcAudioSendStream to send the event on.
+ auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin();
+ if (it == send_streams_.end()) {
+ LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use.";
return false;
}
- // Send DTMF using out-of-band DTMF. ("true", as 3rd arg)
- if (engine()->voe()->dtmf()->SendTelephoneEvent(
- channel, event, true, duration) == -1) {
- LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration);
+ if (event < kMinTelephoneEventCode ||
+ event > kMaxTelephoneEventCode) {
+ LOG(LS_WARNING) << "DTMF event code " << event << " out of range.";
return false;
}
-
- return true;
+ if (duration < kMinTelephoneEventDuration ||
+ duration > kMaxTelephoneEventDuration) {
+ LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range.";
+ return false;
+ }
+ return it->second->SendTelephoneEvent(*dtmf_payload_type_, event, duration);
}
void WebRtcVoiceMediaChannel::OnPacketReceived(
diff --git a/talk/media/webrtc/webrtcvoiceengine.h b/talk/media/webrtc/webrtcvoiceengine.h
index 843ff79..89cf25c 100644
--- a/talk/media/webrtc/webrtcvoiceengine.h
+++ b/talk/media/webrtc/webrtcvoiceengine.h
@@ -265,7 +265,7 @@
bool send_bitrate_setting_ = false;
int send_bitrate_bps_ = 0;
AudioOptions options_;
- bool dtmf_allowed_ = false;
+ rtc::Optional<int> dtmf_payload_type_;
bool desired_playout_ = false;
bool nack_enabled_ = false;
bool playout_ = false;
diff --git a/talk/media/webrtc/webrtcvoiceengine_unittest.cc b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
index 61f17db..1a27a4c 100644
--- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -64,7 +64,6 @@
: cricket::VoEWrapper(engine, // processing
engine, // base
engine, // codec
- engine, // dtmf
engine, // hw
engine, // network
engine, // rtp
@@ -121,6 +120,12 @@
engine_.Terminate();
}
+ const cricket::FakeAudioSendStream& GetSendStream(uint32_t ssrc) {
+ const auto* send_stream = call_.GetAudioSendStream(ssrc);
+ EXPECT_TRUE(send_stream);
+ return *send_stream;
+ }
+
const webrtc::AudioSendStream::Config& GetSendStreamConfig(uint32_t ssrc) {
const auto* send_stream = call_.GetAudioSendStream(ssrc);
EXPECT_TRUE(send_stream);
@@ -163,11 +168,15 @@
// Check we fail if the ssrc is invalid.
EXPECT_FALSE(channel_->InsertDtmf(-1, 1, 111));
- // Test send
- int channel_id = voe_.GetLastChannel();
- EXPECT_FALSE(voe_.WasSendTelephoneEventCalled(channel_id, 2, 123));
+ // Test send.
+ cricket::FakeAudioSendStream::TelephoneEvent telephone_event =
+ GetSendStream(kSsrc1).GetLatestTelephoneEvent();
+ EXPECT_EQ(-1, telephone_event.payload_type);
EXPECT_TRUE(channel_->InsertDtmf(ssrc, 2, 123));
- EXPECT_TRUE(voe_.WasSendTelephoneEventCalled(channel_id, 2, 123));
+ telephone_event = GetSendStream(kSsrc1).GetLatestTelephoneEvent();
+ EXPECT_EQ(kTelephoneEventCodec.id, telephone_event.payload_type);
+ EXPECT_EQ(2, telephone_event.event_code);
+ EXPECT_EQ(123, telephone_event.duration_ms);
}
// Test that send bandwidth is set correctly.
@@ -766,7 +775,7 @@
EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(105, voe_.GetSendCNPayloadType(channel_num, true));
- EXPECT_EQ(106, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_FALSE(channel_->CanInsertDtmf());
}
// Test that VoE Channel doesn't call SetSendCodec again if same codec is tried
@@ -1607,7 +1616,7 @@
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_TRUE(channel_->CanInsertDtmf());
}
// Test that we can set send codecs even with CN codec as the first
@@ -1653,7 +1662,7 @@
EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
- EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_TRUE(channel_->CanInsertDtmf());
}
// Test that we set VAD and DTMF types correctly as callee.
@@ -1686,7 +1695,7 @@
EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
- EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_TRUE(channel_->CanInsertDtmf());
}
// Test that we only apply VAD if we have a CN codec that matches the
@@ -1750,7 +1759,7 @@
EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
- EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
+ EXPECT_TRUE(channel_->CanInsertDtmf());
}
// Test that we set up RED correctly as caller.
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
index 4dd9522..2ff388b 100644
--- a/webrtc/audio/audio_send_stream.cc
+++ b/webrtc/audio/audio_send_stream.cc
@@ -102,6 +102,13 @@
return false;
}
+bool AudioSendStream::SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return channel_proxy_->SetSendTelephoneEventPayloadType(payload_type) &&
+ channel_proxy_->SendTelephoneEventOutband(event, duration_ms);
+}
+
webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
RTC_DCHECK(thread_checker_.CalledOnValidThread());
webrtc::AudioSendStream::Stats stats;
diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h
index b670efe..88304fd 100644
--- a/webrtc/audio/audio_send_stream.h
+++ b/webrtc/audio/audio_send_stream.h
@@ -37,6 +37,8 @@
bool DeliverRtcp(const uint8_t* packet, size_t length) override;
// webrtc::AudioSendStream implementation.
+ bool SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) override;
webrtc::AudioSendStream::Stats GetStats() const override;
const webrtc::AudioSendStream::Config& config() const;
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc
index 8dc6da7..c3620b2 100644
--- a/webrtc/audio/audio_send_stream_unittest.cc
+++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -40,6 +40,9 @@
1345, 1678, 1901, 1234, 112, 13456, 17890, 1567, -1890, -1123};
const CodecInst kCodecInst = {-121, "codec_name_send", 48000, -231, -451, -671};
const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354};
+const int kTelephoneEventPayloadType = 123;
+const uint8_t kTelephoneEventCode = 45;
+const uint32_t kTelephoneEventDuration = 6789;
struct ConfigHelper {
ConfigHelper() : stream_config_(nullptr) {
@@ -79,6 +82,16 @@
AudioSendStream::Config& config() { return stream_config_; }
rtc::scoped_refptr<AudioState> audio_state() { return audio_state_; }
+ void SetupMockForSendTelephoneEvent() {
+ EXPECT_TRUE(channel_proxy_);
+ EXPECT_CALL(*channel_proxy_,
+ SetSendTelephoneEventPayloadType(kTelephoneEventPayloadType))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*channel_proxy_,
+ SendTelephoneEventOutband(kTelephoneEventCode, kTelephoneEventDuration))
+ .WillOnce(Return(true));
+ }
+
void SetupMockForGetStats() {
using testing::DoAll;
using testing::SetArgReferee;
@@ -142,6 +155,14 @@
internal::AudioSendStream send_stream(helper.config(), helper.audio_state());
}
+TEST(AudioSendStreamTest, SendTelephoneEvent) {
+ ConfigHelper helper;
+ internal::AudioSendStream send_stream(helper.config(), helper.audio_state());
+ helper.SetupMockForSendTelephoneEvent();
+ EXPECT_TRUE(send_stream.SendTelephoneEvent(kTelephoneEventPayloadType,
+ kTelephoneEventCode, kTelephoneEventDuration));
+}
+
TEST(AudioSendStreamTest, GetStats) {
ConfigHelper helper;
internal::AudioSendStream send_stream(helper.config(), helper.audio_state());
diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h
index 7069c37..dd8d9e9 100644
--- a/webrtc/audio_send_stream.h
+++ b/webrtc/audio_send_stream.h
@@ -89,6 +89,9 @@
int red_payload_type = -1; // pt, or -1 to disable REDundant coding.
};
+ // TODO(solenberg): Make payload_type a config property instead.
+ virtual bool SendTelephoneEvent(int payload_type, uint8_t event,
+ uint32_t duration_ms) = 0;
virtual Stats GetStats() const = 0;
};
} // namespace webrtc
diff --git a/webrtc/test/mock_voe_channel_proxy.h b/webrtc/test/mock_voe_channel_proxy.h
index 401a87a..a0f0464 100644
--- a/webrtc/test/mock_voe_channel_proxy.h
+++ b/webrtc/test/mock_voe_channel_proxy.h
@@ -33,6 +33,9 @@
MOCK_CONST_METHOD0(GetDecodingCallStatistics, AudioDecodingCallStats());
MOCK_CONST_METHOD0(GetSpeechOutputLevelFullRange, int32_t());
MOCK_CONST_METHOD0(GetDelayEstimate, uint32_t());
+ MOCK_METHOD1(SetSendTelephoneEventPayloadType, bool(int payload_type));
+ MOCK_METHOD2(SendTelephoneEventOutband, bool(uint8_t event,
+ uint32_t duration_ms));
};
} // namespace test
} // namespace webrtc
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc
index 54aa802..fb98356 100644
--- a/webrtc/voice_engine/channel.cc
+++ b/webrtc/voice_engine/channel.cc
@@ -2372,6 +2372,9 @@
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
playDtmfEvent);
+ if (!Sending()) {
+ return -1;
+ }
_playOutbandDtmfEvent = playDtmfEvent;
diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc
index 614b7b7..1772ad5 100644
--- a/webrtc/voice_engine/channel_proxy.cc
+++ b/webrtc/voice_engine/channel_proxy.cc
@@ -108,6 +108,18 @@
return channel()->GetDelayEstimate();
}
+bool ChannelProxy::SetSendTelephoneEventPayloadType(int payload_type) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return channel()->SetSendTelephoneEventPayloadType(payload_type) == 0;
+}
+
+bool ChannelProxy::SendTelephoneEventOutband(uint8_t event,
+ uint32_t duration_ms) {
+ RTC_DCHECK(thread_checker_.CalledOnValidThread());
+ return
+ channel()->SendTelephoneEventOutband(event, duration_ms, 10, false) == 0;
+}
+
Channel* ChannelProxy::channel() const {
RTC_DCHECK(channel_owner_.channel());
return channel_owner_.channel();
diff --git a/webrtc/voice_engine/channel_proxy.h b/webrtc/voice_engine/channel_proxy.h
index 6b916a5..3668de4 100644
--- a/webrtc/voice_engine/channel_proxy.h
+++ b/webrtc/voice_engine/channel_proxy.h
@@ -51,6 +51,9 @@
virtual int32_t GetSpeechOutputLevelFullRange() const;
virtual uint32_t GetDelayEstimate() const;
+ virtual bool SetSendTelephoneEventPayloadType(int payload_type);
+ virtual bool SendTelephoneEventOutband(uint8_t event, uint32_t duration_ms);
+
private:
Channel* channel() const;