2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
11 #include "webrtc/voice_engine/voe_dtmf_impl.h"
13 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
14 #include "webrtc/system_wrappers/interface/trace.h"
15 #include "webrtc/voice_engine/channel.h"
16 #include "webrtc/voice_engine/include/voe_errors.h"
17 #include "webrtc/voice_engine/output_mixer.h"
18 #include "webrtc/voice_engine/transmit_mixer.h"
19 #include "webrtc/voice_engine/voice_engine_impl.h"
23 VoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine)
25 #ifndef WEBRTC_VOICE_ENGINE_DTMF_API
28 if (NULL == voiceEngine)
32 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
38 #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
40 VoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared) :
42 _dtmfDirectFeedback(false),
45 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
46 "VoEDtmfImpl::VoEDtmfImpl() - ctor");
49 VoEDtmfImpl::~VoEDtmfImpl()
51 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
52 "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
55 int VoEDtmfImpl::SendTelephoneEvent(int channel,
61 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
62 "SendTelephoneEvent(channel=%d, eventCode=%d, outOfBand=%d,"
63 "length=%d, attenuationDb=%d)",
64 channel, eventCode, (int)outOfBand, lengthMs, attenuationDb);
65 if (!_shared->statistics().Initialized())
67 _shared->SetLastError(VE_NOT_INITED, kTraceError);
70 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
71 voe::Channel* channelPtr = ch.channel();
72 if (channelPtr == NULL)
74 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
75 "SendTelephoneEvent() failed to locate channel");
78 if (!channelPtr->Sending())
80 _shared->SetLastError(VE_NOT_SENDING, kTraceError,
81 "SendTelephoneEvent() sending is not active");
86 const int maxEventCode = outOfBand ?
87 static_cast<int>(kMaxTelephoneEventCode) :
88 static_cast<int>(kMaxDtmfEventCode);
89 const bool testFailed = ((eventCode < 0) ||
90 (eventCode > maxEventCode) ||
91 (lengthMs < kMinTelephoneEventDuration) ||
92 (lengthMs > kMaxTelephoneEventDuration) ||
93 (attenuationDb < kMinTelephoneEventAttenuation) ||
94 (attenuationDb > kMaxTelephoneEventAttenuation));
97 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
98 "SendTelephoneEvent() invalid parameter(s)");
103 (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode);
104 const bool playDtmfToneDirect =
105 isDtmf && (_dtmfFeedback && _dtmfDirectFeedback);
107 if (playDtmfToneDirect)
109 // Mute the microphone signal while playing back the tone directly.
110 // This is to reduce the risk of introducing echo from the added output.
111 _shared->transmit_mixer()->UpdateMuteMicrophoneTime(lengthMs);
113 // Play out local feedback tone directly (same approach for both inband
115 // Reduce the length of the the tone with 80ms to reduce risk of echo.
116 // For non-direct feedback, outband and inband cases are handled
118 _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80,
124 // The RTP/RTCP module will always deliver OnPlayTelephoneEvent when
125 // an event is transmitted. It is up to the VoE to utilize it or not.
126 // This flag ensures that feedback/playout is enabled; however, the
127 // channel object must still parse out the Dtmf events (0-15) from
128 // all possible events (0-255).
129 const bool playDTFMEvent = (_dtmfFeedback && !_dtmfDirectFeedback);
131 return channelPtr->SendTelephoneEventOutband(eventCode,
138 // For Dtmf tones, we want to ensure that inband tones are played out
139 // in sync with the transmitted audio. This flag is utilized by the
140 // channel object to determine if the queued Dtmf e vent shall also
141 // be fed to the output mixer in the same step as input audio is
142 // replaced by inband Dtmf tones.
143 const bool playDTFMEvent =
144 (isDtmf && _dtmfFeedback && !_dtmfDirectFeedback);
146 return channelPtr->SendTelephoneEventInband(eventCode,
153 int VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel,
156 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
157 "SetSendTelephoneEventPayloadType(channel=%d, type=%u)",
159 if (!_shared->statistics().Initialized())
161 _shared->SetLastError(VE_NOT_INITED, kTraceError);
164 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
165 voe::Channel* channelPtr = ch.channel();
166 if (channelPtr == NULL)
168 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
169 "SetSendTelephoneEventPayloadType() failed to locate channel");
172 return channelPtr->SetSendTelephoneEventPayloadType(type);
175 int VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel,
178 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
179 "GetSendTelephoneEventPayloadType(channel=%d)", channel);
180 if (!_shared->statistics().Initialized())
182 _shared->SetLastError(VE_NOT_INITED, kTraceError);
185 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
186 voe::Channel* channelPtr = ch.channel();
187 if (channelPtr == NULL)
189 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
190 "GetSendTelephoneEventPayloadType() failed to locate channel");
193 return channelPtr->GetSendTelephoneEventPayloadType(type);
196 int VoEDtmfImpl::PlayDtmfTone(int eventCode,
200 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
201 "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)",
202 eventCode, lengthMs, attenuationDb);
204 if (!_shared->statistics().Initialized())
206 _shared->SetLastError(VE_NOT_INITED, kTraceError);
209 if (!_shared->audio_device()->Playing())
211 _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
212 "PlayDtmfTone() no channel is playing out");
215 if ((eventCode < kMinDtmfEventCode) ||
216 (eventCode > kMaxDtmfEventCode) ||
217 (lengthMs < kMinTelephoneEventDuration) ||
218 (lengthMs > kMaxTelephoneEventDuration) ||
219 (attenuationDb <kMinTelephoneEventAttenuation) ||
220 (attenuationDb > kMaxTelephoneEventAttenuation))
222 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
223 "PlayDtmfTone() invalid tone parameter(s)");
226 return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs,
230 int VoEDtmfImpl::StartPlayingDtmfTone(int eventCode,
233 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
234 "StartPlayingDtmfTone(eventCode=%d, attenuationDb=%d)",
235 eventCode, attenuationDb);
237 if (!_shared->statistics().Initialized())
239 _shared->SetLastError(VE_NOT_INITED, kTraceError);
242 if (!_shared->audio_device()->Playing())
244 _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
245 "StartPlayingDtmfTone() no channel is playing out");
248 if ((eventCode < kMinDtmfEventCode) ||
249 (eventCode > kMaxDtmfEventCode) ||
250 (attenuationDb < kMinTelephoneEventAttenuation) ||
251 (attenuationDb > kMaxTelephoneEventAttenuation))
253 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
254 "StartPlayingDtmfTone() invalid tone parameter(s)");
257 return _shared->output_mixer()->StartPlayingDtmfTone(eventCode,
261 int VoEDtmfImpl::StopPlayingDtmfTone()
263 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
264 "StopPlayingDtmfTone()");
266 if (!_shared->statistics().Initialized())
268 _shared->SetLastError(VE_NOT_INITED, kTraceError);
271 return _shared->output_mixer()->StopPlayingDtmfTone();
274 int VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback)
276 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
277 "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
278 (int)enable, (int)directFeedback);
280 CriticalSectionScoped sc(_shared->crit_sec());
282 _dtmfFeedback = enable;
283 _dtmfDirectFeedback = directFeedback;
288 int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback)
290 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
291 "GetDtmfFeedbackStatus()");
293 CriticalSectionScoped sc(_shared->crit_sec());
295 enabled = _dtmfFeedback;
296 directFeedback = _dtmfDirectFeedback;
298 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
299 VoEId(_shared->instance_id(), -1),
300 "GetDtmfFeedbackStatus() => enabled=%d, directFeedback=%d",
301 enabled, directFeedback);
305 int VoEDtmfImpl::SetDtmfPlayoutStatus(int channel, bool enable)
307 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
308 "SetDtmfPlayoutStatus(channel=%d, enable=%d)",
311 if (!_shared->statistics().Initialized())
313 _shared->SetLastError(VE_NOT_INITED, kTraceError);
316 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
317 voe::Channel* channelPtr = ch.channel();
318 if (channelPtr == NULL)
320 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
321 "SetDtmfPlayoutStatus() failed to locate channel");
324 return channelPtr->SetDtmfPlayoutStatus(enable);
327 int VoEDtmfImpl::GetDtmfPlayoutStatus(int channel, bool& enabled)
329 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
330 "GetDtmfPlayoutStatus(channel=%d, enabled=?)", channel);
331 if (!_shared->statistics().Initialized())
333 _shared->SetLastError(VE_NOT_INITED, kTraceError);
336 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
337 voe::Channel* channelPtr = ch.channel();
338 if (channelPtr == NULL)
340 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
341 "GetDtmfPlayoutStatus() failed to locate channel");
344 enabled = channelPtr->DtmfPlayoutStatus();
345 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
346 VoEId(_shared->instance_id(), -1),
347 "GetDtmfPlayoutStatus() => enabled=%d", enabled);
351 #endif // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
353 } // namespace webrtc