diff --git a/talk/media/webrtc/fakewebrtccall.cc b/talk/media/webrtc/fakewebrtccall.cc index d86bfb553c..bf51fb30d8 100644 --- a/talk/media/webrtc/fakewebrtccall.cc +++ b/talk/media/webrtc/fakewebrtccall.cc @@ -39,14 +39,27 @@ FakeAudioSendStream::FakeAudioSendStream( 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 2e7039014c..024c50dd19 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 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { } // 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 92098634fc..65c3debdf0 100644 --- a/talk/media/webrtc/fakewebrtcvoiceengine.h +++ b/talk/media/webrtc/fakewebrtcvoiceengine.h @@ -145,20 +145,11 @@ class FakeAudioProcessing : public webrtc::AudioProcessing { 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 @@ class FakeWebRtcVoiceEngine 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 @@ class FakeWebRtcVoiceEngine 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 recv_codecs; webrtc::CodecInst send_codec; webrtc::PacketTime last_rtp_packet_time; @@ -281,9 +269,6 @@ class FakeWebRtcVoiceEngine 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 @@ class FakeWebRtcVoiceEngine 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 @@ class FakeWebRtcVoiceEngine 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 @@ class FakeWebRtcVoiceEngine 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 1e104b438b..aa705a014d 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 @@ class VoEWrapper { 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 @@ class VoEWrapper { processing_(processing), base_(base), codec_(codec), - dtmf_(dtmf), hw_(hw), network_(network), rtp_(rtp), @@ -118,7 +115,6 @@ class VoEWrapper { 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 @@ class VoEWrapper { scoped_voe_ptr processing_; scoped_voe_ptr base_; scoped_voe_ptr codec_; - scoped_voe_ptr dtmf_; scoped_voe_ptr hw_; scoped_voe_ptr network_; scoped_voe_ptr rtp_; diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc index d1f76ef4b2..d70c86495d 100644 --- a/talk/media/webrtc/webrtcvoiceengine.cc +++ b/talk/media/webrtc/webrtcvoiceengine.cc @@ -134,6 +134,12 @@ const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; 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 @@ bool WebRtcVoiceEngine::InitInternal() { 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 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream 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 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( 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 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( 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 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs( 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( bool WebRtcVoiceMediaChannel::SetSendCodecs( const std::vector& 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(); for (const AudioCodec& codec : codecs) { - // Find the DTMF telephone event "codec". if (IsCodec(codec, kDtmfCodecName)) { - dtmf_allowed_ = true; + dtmf_payload_type_ = rtc::Optional(codec.id); + break; } } @@ -2282,38 +2285,34 @@ bool WebRtcVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) { } 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 843ff797de..89cf25c25f 100644 --- a/talk/media/webrtc/webrtcvoiceengine.h +++ b/talk/media/webrtc/webrtcvoiceengine.h @@ -265,7 +265,7 @@ class WebRtcVoiceMediaChannel final : public VoiceMediaChannel, bool send_bitrate_setting_ = false; int send_bitrate_bps_ = 0; AudioOptions options_; - bool dtmf_allowed_ = false; + rtc::Optional 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 61f17db927..1a27a4c5cc 100644 --- a/talk/media/webrtc/webrtcvoiceengine_unittest.cc +++ b/talk/media/webrtc/webrtcvoiceengine_unittest.cc @@ -64,7 +64,6 @@ class FakeVoEWrapper : public cricket::VoEWrapper { : cricket::VoEWrapper(engine, // processing engine, // base engine, // codec - engine, // dtmf engine, // hw engine, // network engine, // rtp @@ -121,6 +120,12 @@ class WebRtcVoiceEngineTestFake : public testing::Test { 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 @@ class WebRtcVoiceEngineTestFake : public testing::Test { // 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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) { 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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsDTMFOnTop) { 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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCaller) { 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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCallee) { 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 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCaseInsensitive) { 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 4dd9522956..2ff388bbca 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc @@ -102,6 +102,13 @@ bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { 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 b670efee3c..88304fd702 100644 --- a/webrtc/audio/audio_send_stream.h +++ b/webrtc/audio/audio_send_stream.h @@ -37,6 +37,8 @@ class AudioSendStream final : public webrtc::AudioSendStream { 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 8dc6da7a82..c3620b294c 100644 --- a/webrtc/audio/audio_send_stream_unittest.cc +++ b/webrtc/audio/audio_send_stream_unittest.cc @@ -40,6 +40,9 @@ const CallStatistics kCallStats = { 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 @@ struct ConfigHelper { AudioSendStream::Config& config() { return stream_config_; } rtc::scoped_refptr 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 @@ TEST(AudioSendStreamTest, ConstructDestruct) { 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 7069c377d3..dd8d9e96ea 100644 --- a/webrtc/audio_send_stream.h +++ b/webrtc/audio_send_stream.h @@ -89,6 +89,9 @@ class AudioSendStream : public SendStream { 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 401a87a01e..a0f0464111 100644 --- a/webrtc/test/mock_voe_channel_proxy.h +++ b/webrtc/test/mock_voe_channel_proxy.h @@ -33,6 +33,9 @@ class MockVoEChannelProxy : public voe::ChannelProxy { 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 54aa802d73..fb9835664a 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -2372,6 +2372,9 @@ int Channel::SendTelephoneEventOutband(unsigned char eventCode, 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 614b7b72fe..1772ad5549 100644 --- a/webrtc/voice_engine/channel_proxy.cc +++ b/webrtc/voice_engine/channel_proxy.cc @@ -108,6 +108,18 @@ uint32_t ChannelProxy::GetDelayEstimate() const { 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 6b916a54c0..3668de4339 100644 --- a/webrtc/voice_engine/channel_proxy.h +++ b/webrtc/voice_engine/channel_proxy.h @@ -51,6 +51,9 @@ class ChannelProxy { 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;