From 3ecb5c869842ddfccab35e3111a8e415a47e2b5b Mon Sep 17 00:00:00 2001 From: solenberg Date: Wed, 9 Mar 2016 07:31:58 -0800 Subject: [PATCH] Revert of - Clean up unused voice engine DTMF code. (patchset #4 id:60001 of https://codereview.webrtc.org/1722253002/ ) Reason for revert: Breaks Chromium FYI bots for Android. E.g. https://build.chromium.org/p/chromium.webrtc.fyi/builders/Android%20Tests%20%28dbg%29%20%28K%20Nexus5%29/builds/4486/steps/content_browsertests/logs/stdio Original issue's description: > - Clean up unused voice engine DTMF code following removal of VoEDtmf APIs. > - Use better types in AudioSendStream::SendTelephoneEvent() and related methods. > > BUG=webrtc:4690 > > Committed: https://crrev.com/8886c816582a7c6190c5429222cb8096fca302a6 > Cr-Commit-Position: refs/heads/master@{#11927} TBR=tina.legrand@webrtc.org,henrik.lundin@webrtc.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=webrtc:4690 Review URL: https://codereview.webrtc.org/1776243003 Cr-Commit-Position: refs/heads/master@{#11930} --- webrtc/audio/audio_send_stream.cc | 4 +- webrtc/audio/audio_send_stream.h | 4 +- webrtc/audio/audio_send_stream_unittest.cc | 4 +- webrtc/audio_send_stream.h | 4 +- webrtc/media/engine/fakewebrtccall.cc | 4 +- webrtc/media/engine/fakewebrtccall.h | 8 +- webrtc/media/engine/webrtcvoiceengine.cc | 3 +- .../audio_coding/test/TwoWayCommunication.cc | 8 ++ .../rtp_rtcp/test/testAPI/test_api_audio.cc | 2 +- webrtc/test/mock_voe_channel_proxy.h | 3 +- webrtc/voice_engine/BUILD.gn | 2 + webrtc/voice_engine/channel.cc | 128 +++++++++++++++--- webrtc/voice_engine/channel.h | 23 +++- webrtc/voice_engine/channel_proxy.cc | 6 +- webrtc/voice_engine/channel_proxy.h | 2 +- webrtc/voice_engine/dtmf_inband.h | 3 - webrtc/voice_engine/dtmf_inband_queue.cc | 86 ++++++++++++ webrtc/voice_engine/dtmf_inband_queue.h | 50 +++++++ webrtc/voice_engine/transmit_mixer.cc | 21 +++ webrtc/voice_engine/transmit_mixer.h | 4 + webrtc/voice_engine/voice_engine.gyp | 2 + 21 files changed, 329 insertions(+), 42 deletions(-) create mode 100644 webrtc/voice_engine/dtmf_inband_queue.cc create mode 100644 webrtc/voice_engine/dtmf_inband_queue.h diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc index 24afcbcf58..160a818323 100644 --- a/webrtc/audio/audio_send_stream.cc +++ b/webrtc/audio/audio_send_stream.cc @@ -125,8 +125,8 @@ bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) { return false; } -bool AudioSendStream::SendTelephoneEvent(int payload_type, int event, - int duration_ms) { +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); diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h index d463b3da30..cf0a19ca4b 100644 --- a/webrtc/audio/audio_send_stream.h +++ b/webrtc/audio/audio_send_stream.h @@ -40,8 +40,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, int event, - int duration_ms) override; + 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 c04a3de77c..6788699cd5 100644 --- a/webrtc/audio/audio_send_stream_unittest.cc +++ b/webrtc/audio/audio_send_stream_unittest.cc @@ -46,8 +46,8 @@ const CallStatistics kCallStats = { const CodecInst kCodecInst = {-121, "codec_name_send", 48000, -231, 0, -671}; const ReportBlock kReportBlock = {456, 780, 123, 567, 890, 132, 143, 13354}; const int kTelephoneEventPayloadType = 123; -const int kTelephoneEventCode = 45; -const int kTelephoneEventDuration = 6789; +const uint8_t kTelephoneEventCode = 45; +const uint32_t kTelephoneEventDuration = 6789; struct ConfigHelper { ConfigHelper() diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h index 24c3d77ab2..d1af9e0103 100644 --- a/webrtc/audio_send_stream.h +++ b/webrtc/audio_send_stream.h @@ -90,8 +90,8 @@ class AudioSendStream : public SendStream { }; // TODO(solenberg): Make payload_type a config property instead. - virtual bool SendTelephoneEvent(int payload_type, int event, - int duration_ms) = 0; + 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/media/engine/fakewebrtccall.cc b/webrtc/media/engine/fakewebrtccall.cc index 3277e75a64..aa94d48dfb 100644 --- a/webrtc/media/engine/fakewebrtccall.cc +++ b/webrtc/media/engine/fakewebrtccall.cc @@ -39,8 +39,8 @@ FakeAudioSendStream::TelephoneEvent return latest_telephone_event_; } -bool FakeAudioSendStream::SendTelephoneEvent(int payload_type, int event, - int duration_ms) { +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; diff --git a/webrtc/media/engine/fakewebrtccall.h b/webrtc/media/engine/fakewebrtccall.h index 41a92dfac0..89a644a296 100644 --- a/webrtc/media/engine/fakewebrtccall.h +++ b/webrtc/media/engine/fakewebrtccall.h @@ -35,8 +35,8 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { public: struct TelephoneEvent { int payload_type = -1; - int event_code = 0; - int duration_ms = 0; + uint8_t event_code = 0; + uint32_t duration_ms = 0; }; explicit FakeAudioSendStream(const webrtc::AudioSendStream::Config& config); @@ -56,8 +56,8 @@ class FakeAudioSendStream final : public webrtc::AudioSendStream { } // webrtc::AudioSendStream implementation. - bool SendTelephoneEvent(int payload_type, int event, - int duration_ms) override; + bool SendTelephoneEvent(int payload_type, uint8_t event, + uint32_t duration_ms) override; webrtc::AudioSendStream::Stats GetStats() const override; TelephoneEvent latest_telephone_event_; diff --git a/webrtc/media/engine/webrtcvoiceengine.cc b/webrtc/media/engine/webrtcvoiceengine.cc index a496316b42..f57db27a31 100644 --- a/webrtc/media/engine/webrtcvoiceengine.cc +++ b/webrtc/media/engine/webrtcvoiceengine.cc @@ -1178,7 +1178,8 @@ class WebRtcVoiceMediaChannel::WebRtcAudioSendStream RTC_CHECK(stream_); } - bool SendTelephoneEvent(int payload_type, int event, int duration_ms) { + 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); diff --git a/webrtc/modules/audio_coding/test/TwoWayCommunication.cc b/webrtc/modules/audio_coding/test/TwoWayCommunication.cc index 161491b061..3ca7fd217d 100644 --- a/webrtc/modules/audio_coding/test/TwoWayCommunication.cc +++ b/webrtc/modules/audio_coding/test/TwoWayCommunication.cc @@ -50,6 +50,14 @@ TwoWayCommunication::~TwoWayCommunication() { delete _channel_B2A; delete _channelRef_A2B; delete _channelRef_B2A; +#ifdef WEBRTC_DTMF_DETECTION + if (_dtmfDetectorA != NULL) { + delete _dtmfDetectorA; + } + if (_dtmfDetectorB != NULL) { + delete _dtmfDetectorB; + } +#endif _inFileA.Close(); _inFileB.Close(); _outFileA.Close(); diff --git a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc index 32ab9379ae..634969b311 100644 --- a/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc +++ b/webrtc/modules/rtp_rtcp/test/testAPI/test_api_audio.cc @@ -322,7 +322,7 @@ TEST_F(RtpRtcpAudioTest, DTMF) { (voice_codec.rate < 0) ? 0 : voice_codec.rate)); // Start DTMF test. - int timeStamp = 160; + uint32_t timeStamp = 160; // Send a DTMF tone using RFC 2833 (4733). for (int i = 0; i < 16; i++) { diff --git a/webrtc/test/mock_voe_channel_proxy.h b/webrtc/test/mock_voe_channel_proxy.h index c2211f8554..f5c87334cc 100644 --- a/webrtc/test/mock_voe_channel_proxy.h +++ b/webrtc/test/mock_voe_channel_proxy.h @@ -43,7 +43,8 @@ class MockVoEChannelProxy : public voe::ChannelProxy { MOCK_CONST_METHOD0(GetSpeechOutputLevelFullRange, int32_t()); MOCK_CONST_METHOD0(GetDelayEstimate, uint32_t()); MOCK_METHOD1(SetSendTelephoneEventPayloadType, bool(int payload_type)); - MOCK_METHOD2(SendTelephoneEventOutband, bool(int event, int duration_ms)); + MOCK_METHOD2(SendTelephoneEventOutband, bool(uint8_t event, + uint32_t duration_ms)); }; } // namespace test } // namespace webrtc diff --git a/webrtc/voice_engine/BUILD.gn b/webrtc/voice_engine/BUILD.gn index 899b7333b2..9ccc53bf45 100644 --- a/webrtc/voice_engine/BUILD.gn +++ b/webrtc/voice_engine/BUILD.gn @@ -18,6 +18,8 @@ source_set("voice_engine") { "channel_proxy.h", "dtmf_inband.cc", "dtmf_inband.h", + "dtmf_inband_queue.cc", + "dtmf_inband_queue.h", "include/voe_audio_processing.h", "include/voe_base.h", "include/voe_codec.h", diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc index 695aa1dee2..11af45edc8 100644 --- a/webrtc/voice_engine/channel.cc +++ b/webrtc/voice_engine/channel.cc @@ -40,11 +40,13 @@ #include "webrtc/voice_engine/transmit_mixer.h" #include "webrtc/voice_engine/utility.h" +#if defined(_WIN32) +#include +#endif + namespace webrtc { namespace voe { -const int kTelephoneEventAttenuationdB = 10; - class TransportFeedbackProxy : public TransportFeedbackObserver { public: TransportFeedbackProxy() : feedback_observer_(nullptr) { @@ -361,7 +363,7 @@ void Channel::OnPlayTelephoneEvent(uint8_t event, " volume=%u)", event, lengthMs, volume); - if (event > 15) { + if (!_playOutbandDtmfEvent || (event > 15)) { // Ignore callback since feedback is disabled or event is not a // Dtmf tone event. return; @@ -759,11 +761,14 @@ Channel::Channel(int32_t channelId, _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025), _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026), _outputFileRecording(false), + _inbandDtmfQueue(VoEModuleId(instanceId, channelId)), + _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)), _outputExternalMedia(false), _inputExternalMediaCallbackPtr(NULL), _outputExternalMediaCallbackPtr(NULL), _timeStamp(0), // This is just an offset, RTP module will add it's own // random offset + _sendTelephoneEventPayloadType(106), ntp_estimator_(Clock::GetRealTimeClock()), jitter_buffer_playout_timestamp_(0), playout_timestamp_rtp_(0), @@ -791,6 +796,8 @@ Channel::Channel(int32_t channelId, _panLeft(1.0f), _panRight(1.0f), _outputGain(1.0f), + _playOutbandDtmfEvent(false), + _playInbandDtmfEvent(false), _lastLocalTimeStamp(0), _lastPayloadType(0), _includeAudioLevelIndication(false), @@ -823,6 +830,8 @@ Channel::Channel(int32_t channelId, config.Get().enabled; audio_coding_.reset(AudioCodingModule::Create(acm_config)); + _inbandDtmfQueue.ResetDtmf(); + _inbandDtmfGenerator.Init(); _outputAudioLevel.Clear(); RtpRtcp::Configuration configuration; @@ -2203,18 +2212,21 @@ int Channel::GetChannelOutputVolumeScaling(float& scaling) const { return 0; } -int Channel::SendTelephoneEventOutband(int event, int duration_ms) { +int Channel::SendTelephoneEventOutband(unsigned char eventCode, + int lengthMs, + int attenuationDb, + bool playDtmfEvent) { WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId), - "Channel::SendTelephoneEventOutband(...)"); - RTC_DCHECK_LE(0, event); - RTC_DCHECK_GE(255, event); - RTC_DCHECK_LE(0, duration_ms); - RTC_DCHECK_GE(65535, duration_ms); + "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)", + playDtmfEvent); if (!Sending()) { return -1; } - if (_rtpRtcpModule->SendTelephoneEventOutband( - event, duration_ms, kTelephoneEventAttenuationdB) != 0) { + + _playOutbandDtmfEvent = playDtmfEvent; + + if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs, + attenuationDb) != 0) { _engineStatisticsPtr->SetLastError( VE_SEND_DTMF_FAILED, kTraceWarning, "SendTelephoneEventOutband() failed to send event"); @@ -2223,14 +2235,32 @@ int Channel::SendTelephoneEventOutband(int event, int duration_ms) { return 0; } -int Channel::SetSendTelephoneEventPayloadType(int payload_type) { +int Channel::SendTelephoneEventInband(unsigned char eventCode, + int lengthMs, + int attenuationDb, + bool playDtmfEvent) { + WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId), + "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)", + playDtmfEvent); + + _playInbandDtmfEvent = playDtmfEvent; + _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb); + + return 0; +} + +int Channel::SetSendTelephoneEventPayloadType(unsigned char type) { WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId), "Channel::SetSendTelephoneEventPayloadType()"); - RTC_DCHECK_LE(0, payload_type); - RTC_DCHECK_GE(127, payload_type); - CodecInst codec = {0}; + if (type > 127) { + _engineStatisticsPtr->SetLastError( + VE_INVALID_ARGUMENT, kTraceError, + "SetSendTelephoneEventPayloadType() invalid type"); + return -1; + } + CodecInst codec = {}; codec.plfreq = 8000; - codec.pltype = payload_type; + codec.pltype = type; memcpy(codec.plname, "telephone-event", 16); if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) { _rtpRtcpModule->DeRegisterSendPayload(codec.pltype); @@ -2242,6 +2272,12 @@ int Channel::SetSendTelephoneEventPayloadType(int payload_type) { return -1; } } + _sendTelephoneEventPayloadType = type; + return 0; +} + +int Channel::GetSendTelephoneEventPayloadType(unsigned char& type) { + type = _sendTelephoneEventPayloadType; return 0; } @@ -2991,6 +3027,8 @@ uint32_t Channel::PrepareEncodeAndSend(int mixingFrequency) { } } + InsertInbandDtmfTone(); + if (_includeAudioLevelIndication) { size_t length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_; @@ -3310,6 +3348,64 @@ int32_t Channel::MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency) { return 0; } +int Channel::InsertInbandDtmfTone() { + // Check if we should start a new tone. + if (_inbandDtmfQueue.PendingDtmf() && !_inbandDtmfGenerator.IsAddingTone() && + _inbandDtmfGenerator.DelaySinceLastTone() > + kMinTelephoneEventSeparationMs) { + int8_t eventCode(0); + uint16_t lengthMs(0); + uint8_t attenuationDb(0); + + eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb); + _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb); + if (_playInbandDtmfEvent) { + // Add tone to output mixer using a reduced length to minimize + // risk of echo. + _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80, attenuationDb); + } + } + + if (_inbandDtmfGenerator.IsAddingTone()) { + uint16_t frequency(0); + _inbandDtmfGenerator.GetSampleRate(frequency); + + if (frequency != _audioFrame.sample_rate_hz_) { + // Update sample rate of Dtmf tone since the mixing frequency + // has changed. + _inbandDtmfGenerator.SetSampleRate( + (uint16_t)(_audioFrame.sample_rate_hz_)); + // Reset the tone to be added taking the new sample rate into + // account. + _inbandDtmfGenerator.ResetTone(); + } + + int16_t toneBuffer[320]; + uint16_t toneSamples(0); + // Get 10ms tone segment and set time since last tone to zero + if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1) { + WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId), + "Channel::EncodeAndSend() inserting Dtmf failed"); + return -1; + } + + // Replace mixed audio with DTMF tone. + for (size_t sample = 0; sample < _audioFrame.samples_per_channel_; + sample++) { + for (size_t channel = 0; channel < _audioFrame.num_channels_; channel++) { + const size_t index = sample * _audioFrame.num_channels_ + channel; + _audioFrame.data_[index] = toneBuffer[sample]; + } + } + + assert(_audioFrame.samples_per_channel_ == toneSamples); + } else { + // Add 10ms to "delay-since-last-tone" counter + _inbandDtmfGenerator.UpdateDelaySinceLastTone(); + } + return 0; +} + void Channel::UpdatePlayoutTimestamp(bool rtcp) { uint32_t playout_timestamp = 0; diff --git a/webrtc/voice_engine/channel.h b/webrtc/voice_engine/channel.h index c89b0e0c8b..75c4fd87cb 100644 --- a/webrtc/voice_engine/channel.h +++ b/webrtc/voice_engine/channel.h @@ -25,6 +25,8 @@ #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" #include "webrtc/modules/utility/include/file_player.h" #include "webrtc/modules/utility/include/file_recorder.h" +#include "webrtc/voice_engine/dtmf_inband.h" +#include "webrtc/voice_engine/dtmf_inband_queue.h" #include "webrtc/voice_engine/include/voe_audio_processing.h" #include "webrtc/voice_engine/include/voe_network.h" #include "webrtc/voice_engine/level_indicator.h" @@ -294,9 +296,17 @@ class Channel // VoEVideoSyncExtended int GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const; - // DTMF - int SendTelephoneEventOutband(int event, int duration_ms); - int SetSendTelephoneEventPayloadType(int payload_type); + // VoEDtmf + int SendTelephoneEventOutband(unsigned char eventCode, + int lengthMs, + int attenuationDb, + bool playDtmfEvent); + int SendTelephoneEventInband(unsigned char eventCode, + int lengthMs, + int attenuationDb, + bool playDtmfEvent); + int SetSendTelephoneEventPayloadType(unsigned char type); + int GetSendTelephoneEventPayloadType(unsigned char& type); // VoEAudioProcessingImpl int UpdateRxVadDetection(AudioFrame& audioFrame); @@ -454,6 +464,7 @@ class Channel bool IsPacketInOrder(const RTPHeader& header) const; bool IsPacketRetransmitted(const RTPHeader& header, bool in_order) const; int ResendPackets(const uint16_t* sequence_numbers, int length); + int InsertInbandDtmfTone(); int32_t MixOrReplaceAudioWithFile(int mixingFrequency); int32_t MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency); void UpdatePlayoutTimestamp(bool rtcp); @@ -499,10 +510,13 @@ class Channel int _outputFilePlayerId; int _outputFileRecorderId; bool _outputFileRecording; + DtmfInbandQueue _inbandDtmfQueue; + DtmfInband _inbandDtmfGenerator; bool _outputExternalMedia; VoEMediaProcess* _inputExternalMediaCallbackPtr; VoEMediaProcess* _outputExternalMediaCallbackPtr; uint32_t _timeStamp; + uint8_t _sendTelephoneEventPayloadType; RemoteNtpTimeEstimator ntp_estimator_ GUARDED_BY(ts_stats_lock_); @@ -546,6 +560,9 @@ class Channel float _panLeft; float _panRight; float _outputGain; + // VoEDtmf + bool _playOutbandDtmfEvent; + bool _playInbandDtmfEvent; // VoeRTP_RTCP uint32_t _lastLocalTimeStamp; int8_t _lastPayloadType; diff --git a/webrtc/voice_engine/channel_proxy.cc b/webrtc/voice_engine/channel_proxy.cc index 10c8821202..da7864f15f 100644 --- a/webrtc/voice_engine/channel_proxy.cc +++ b/webrtc/voice_engine/channel_proxy.cc @@ -148,9 +148,11 @@ bool ChannelProxy::SetSendTelephoneEventPayloadType(int payload_type) { return channel()->SetSendTelephoneEventPayloadType(payload_type) == 0; } -bool ChannelProxy::SendTelephoneEventOutband(int event, int duration_ms) { +bool ChannelProxy::SendTelephoneEventOutband(uint8_t event, + uint32_t duration_ms) { RTC_DCHECK(thread_checker_.CalledOnValidThread()); - return channel()->SendTelephoneEventOutband(event, duration_ms) == 0; + return + channel()->SendTelephoneEventOutband(event, duration_ms, 10, false) == 0; } void ChannelProxy::SetSink(std::unique_ptr sink) { diff --git a/webrtc/voice_engine/channel_proxy.h b/webrtc/voice_engine/channel_proxy.h index dec726cb23..3461cf3e78 100644 --- a/webrtc/voice_engine/channel_proxy.h +++ b/webrtc/voice_engine/channel_proxy.h @@ -68,7 +68,7 @@ class ChannelProxy { virtual uint32_t GetDelayEstimate() const; virtual bool SetSendTelephoneEventPayloadType(int payload_type); - virtual bool SendTelephoneEventOutband(int event, int duration_ms); + virtual bool SendTelephoneEventOutband(uint8_t event, uint32_t duration_ms); virtual void SetSink(std::unique_ptr sink); diff --git a/webrtc/voice_engine/dtmf_inband.h b/webrtc/voice_engine/dtmf_inband.h index 795c5ce8fc..6000d99214 100644 --- a/webrtc/voice_engine/dtmf_inband.h +++ b/webrtc/voice_engine/dtmf_inband.h @@ -17,9 +17,6 @@ namespace webrtc { -// TODO(solenberg): Used as a DTMF tone generator in voe::OutputMixer. Pull out -// the one in NetEq and use that instead? We don't need several -// implemenations of this. class DtmfInband { public: diff --git a/webrtc/voice_engine/dtmf_inband_queue.cc b/webrtc/voice_engine/dtmf_inband_queue.cc new file mode 100644 index 0000000000..4ab74cdf70 --- /dev/null +++ b/webrtc/voice_engine/dtmf_inband_queue.cc @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/system_wrappers/include/trace.h" +#include "webrtc/voice_engine/dtmf_inband_queue.h" + +namespace webrtc { + +DtmfInbandQueue::DtmfInbandQueue(int32_t id): + _id(id), + _nextEmptyIndex(0) +{ + memset(_DtmfKey,0, sizeof(_DtmfKey)); + memset(_DtmfLen,0, sizeof(_DtmfLen)); + memset(_DtmfLevel,0, sizeof(_DtmfLevel)); +} + +DtmfInbandQueue::~DtmfInbandQueue() +{ +} + +int +DtmfInbandQueue::AddDtmf(uint8_t key, uint16_t len, uint8_t level) +{ + rtc::CritScope lock(&_DtmfCritsect); + + if (_nextEmptyIndex >= kDtmfInbandMax) + { + WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_id,-1), + "DtmfInbandQueue::AddDtmf() unable to add Dtmf tone"); + return -1; + } + int32_t index = _nextEmptyIndex; + _DtmfKey[index] = key; + _DtmfLen[index] = len; + _DtmfLevel[index] = level; + _nextEmptyIndex++; + return 0; +} + +int8_t +DtmfInbandQueue::NextDtmf(uint16_t* len, uint8_t* level) +{ + rtc::CritScope lock(&_DtmfCritsect); + + if(!PendingDtmf()) + { + return -1; + } + int8_t nextDtmf = _DtmfKey[0]; + *len=_DtmfLen[0]; + *level=_DtmfLevel[0]; + + memmove(&(_DtmfKey[0]), &(_DtmfKey[1]), + _nextEmptyIndex*sizeof(uint8_t)); + memmove(&(_DtmfLen[0]), &(_DtmfLen[1]), + _nextEmptyIndex*sizeof(uint16_t)); + memmove(&(_DtmfLevel[0]), &(_DtmfLevel[1]), + _nextEmptyIndex*sizeof(uint8_t)); + + _nextEmptyIndex--; + return nextDtmf; +} + +bool +DtmfInbandQueue::PendingDtmf() +{ + rtc::CritScope lock(&_DtmfCritsect); + return _nextEmptyIndex > 0; +} + +void +DtmfInbandQueue::ResetDtmf() +{ + rtc::CritScope lock(&_DtmfCritsect); + _nextEmptyIndex = 0; +} + +} // namespace webrtc diff --git a/webrtc/voice_engine/dtmf_inband_queue.h b/webrtc/voice_engine/dtmf_inband_queue.h new file mode 100644 index 0000000000..08e8018316 --- /dev/null +++ b/webrtc/voice_engine/dtmf_inband_queue.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_VOICE_ENGINE_DTMF_INBAND_QUEUE_H +#define WEBRTC_VOICE_ENGINE_DTMF_INBAND_QUEUE_H + +#include "webrtc/base/criticalsection.h" +#include "webrtc/typedefs.h" +#include "webrtc/voice_engine/voice_engine_defines.h" + + +namespace webrtc { + +class DtmfInbandQueue +{ +public: + + DtmfInbandQueue(int32_t id); + + virtual ~DtmfInbandQueue(); + + int AddDtmf(uint8_t DtmfKey, uint16_t len, uint8_t level); + + int8_t NextDtmf(uint16_t* len, uint8_t* level); + + bool PendingDtmf(); + + void ResetDtmf(); + +private: + enum {kDtmfInbandMax = 20}; + + int32_t _id; + rtc::CriticalSection _DtmfCritsect; + uint8_t _nextEmptyIndex; + uint8_t _DtmfKey[kDtmfInbandMax]; + uint16_t _DtmfLen[kDtmfInbandMax]; + uint8_t _DtmfLevel[kDtmfInbandMax]; +}; + +} // namespace webrtc + +#endif // WEBRTC_VOICE_ENGINE_DTMF_INBAND_QUEUE_H diff --git a/webrtc/voice_engine/transmit_mixer.cc b/webrtc/voice_engine/transmit_mixer.cc index 0240389be1..d6a5213217 100644 --- a/webrtc/voice_engine/transmit_mixer.cc +++ b/webrtc/voice_engine/transmit_mixer.cc @@ -205,6 +205,7 @@ TransmitMixer::TransmitMixer(uint32_t instanceId) : external_postproc_ptr_(NULL), external_preproc_ptr_(NULL), _mute(false), + _remainingMuteMicTimeMs(0), stereo_codec_(false), swap_stereo_channels_(false) { @@ -358,6 +359,17 @@ TransmitMixer::PrepareDemux(const void* audioSamples, TypingDetection(keyPressed); #endif + // --- Mute during DTMF tone if direct feedback is enabled + if (_remainingMuteMicTimeMs > 0) + { + AudioFrameOperations::Mute(_audioFrame); + _remainingMuteMicTimeMs -= 10; + if (_remainingMuteMicTimeMs < 0) + { + _remainingMuteMicTimeMs = 0; + } + } + // --- Mute signal if (_mute) { @@ -465,6 +477,15 @@ uint32_t TransmitMixer::CaptureLevel() const return _captureLevel; } +void +TransmitMixer::UpdateMuteMicrophoneTime(uint32_t lengthMs) +{ + WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1), + "TransmitMixer::UpdateMuteMicrophoneTime(lengthMs=%d)", + lengthMs); + _remainingMuteMicTimeMs = lengthMs; +} + int32_t TransmitMixer::StopSend() { diff --git a/webrtc/voice_engine/transmit_mixer.h b/webrtc/voice_engine/transmit_mixer.h index 483af0518a..b5c483aa4b 100644 --- a/webrtc/voice_engine/transmit_mixer.h +++ b/webrtc/voice_engine/transmit_mixer.h @@ -75,6 +75,9 @@ public: int32_t StopSend(); + // VoEDtmf + void UpdateMuteMicrophoneTime(uint32_t lengthMs); + // VoEExternalMedia int RegisterExternalMediaProcessing(VoEMediaProcess* object, ProcessingTypes type); @@ -223,6 +226,7 @@ private: VoEMediaProcess* external_postproc_ptr_; VoEMediaProcess* external_preproc_ptr_; bool _mute; + int32_t _remainingMuteMicTimeMs; bool stereo_codec_; bool swap_stereo_channels_; }; diff --git a/webrtc/voice_engine/voice_engine.gyp b/webrtc/voice_engine/voice_engine.gyp index a848d6c668..7935be89cf 100644 --- a/webrtc/voice_engine/voice_engine.gyp +++ b/webrtc/voice_engine/voice_engine.gyp @@ -54,6 +54,8 @@ 'channel_proxy.h', 'dtmf_inband.cc', 'dtmf_inband.h', + 'dtmf_inband_queue.cc', + 'dtmf_inband_queue.h', 'level_indicator.cc', 'level_indicator.h', 'monitor_module.cc',