Index: webrtc/voice_engine/channel.cc |
diff --git a/webrtc/voice_engine/channel.cc b/webrtc/voice_engine/channel.cc |
index 695aa1dee2434f85d6a1730771056b6ed9067fb6..11af45edc837fb8f94eb9da43edf9ba2be86dde9 100644 |
--- a/webrtc/voice_engine/channel.cc |
+++ b/webrtc/voice_engine/channel.cc |
@@ -40,10 +40,12 @@ |
#include "webrtc/voice_engine/transmit_mixer.h" |
#include "webrtc/voice_engine/utility.h" |
+#if defined(_WIN32) |
+#include <Qos.h> |
+#endif |
+ |
namespace webrtc { |
namespace voe { |
- |
-const int kTelephoneEventAttenuationdB = 10; |
class TransportFeedbackProxy : public TransportFeedbackObserver { |
public: |
@@ -361,7 +363,7 @@ |
" 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 @@ |
_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 @@ |
_panLeft(1.0f), |
_panRight(1.0f), |
_outputGain(1.0f), |
+ _playOutbandDtmfEvent(false), |
+ _playInbandDtmfEvent(false), |
_lastLocalTimeStamp(0), |
_lastPayloadType(0), |
_includeAudioLevelIndication(false), |
@@ -823,6 +830,8 @@ |
config.Get<NetEqFastAccelerate>().enabled; |
audio_coding_.reset(AudioCodingModule::Create(acm_config)); |
+ _inbandDtmfQueue.ResetDtmf(); |
+ _inbandDtmfGenerator.Init(); |
_outputAudioLevel.Clear(); |
RtpRtcp::Configuration configuration; |
@@ -2203,18 +2212,21 @@ |
return 0; |
} |
-int Channel::SendTelephoneEventOutband(int event, int duration_ms) { |
- 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); |
+int Channel::SendTelephoneEventOutband(unsigned char eventCode, |
+ int lengthMs, |
+ int attenuationDb, |
+ bool playDtmfEvent) { |
+ WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId), |
+ "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 @@ |
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 @@ |
return -1; |
} |
} |
+ _sendTelephoneEventPayloadType = type; |
+ return 0; |
+} |
+ |
+int Channel::GetSendTelephoneEventPayloadType(unsigned char& type) { |
+ type = _sendTelephoneEventPayloadType; |
return 0; |
} |
@@ -2991,6 +3027,8 @@ |
} |
} |
+ InsertInbandDtmfTone(); |
+ |
if (_includeAudioLevelIndication) { |
size_t length = |
_audioFrame.samples_per_channel_ * _audioFrame.num_channels_; |
@@ -3307,6 +3345,64 @@ |
return -1; |
} |
+ 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; |
} |