blob: 70872c694c1111d31da011676d4e4a8507b4b7dc [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.
9 */
10
turaj@webrtc.org15a03fd2013-03-12 22:27:27 +000011#include "webrtc/voice_engine/voe_dtmf_impl.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
turaj@webrtc.org15a03fd2013-03-12 22:27:27 +000013#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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000020
21namespace webrtc {
22
23VoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine)
24{
25#ifndef WEBRTC_VOICE_ENGINE_DTMF_API
26 return NULL;
27#else
28 if (NULL == voiceEngine)
29 {
30 return NULL;
31 }
tommi@webrtc.orgb9e5a3d2013-02-15 15:07:32 +000032 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000033 s->AddRef();
34 return s;
35#endif
36}
37
38#ifdef WEBRTC_VOICE_ENGINE_DTMF_API
39
40VoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared) :
41 _dtmfFeedback(true),
42 _dtmfDirectFeedback(false),
43 _shared(shared)
44{
45 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
46 "VoEDtmfImpl::VoEDtmfImpl() - ctor");
47}
48
49VoEDtmfImpl::~VoEDtmfImpl()
50{
51 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
52 "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
53}
54
55int VoEDtmfImpl::SendTelephoneEvent(int channel,
56 int eventCode,
57 bool outOfBand,
58 int lengthMs,
59 int attenuationDb)
60{
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())
66 {
67 _shared->SetLastError(VE_NOT_INITED, kTraceError);
68 return -1;
69 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +000070 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
71 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000072 if (channelPtr == NULL)
73 {
74 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
75 "SendTelephoneEvent() failed to locate channel");
76 return -1;
77 }
78 if (!channelPtr->Sending())
79 {
80 _shared->SetLastError(VE_NOT_SENDING, kTraceError,
81 "SendTelephoneEvent() sending is not active");
82 return -1;
83 }
84
85 // Sanity check
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));
95 if (testFailed)
96 {
97 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
98 "SendTelephoneEvent() invalid parameter(s)");
99 return -1;
100 }
101
102 const bool isDtmf =
103 (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode);
104 const bool playDtmfToneDirect =
105 isDtmf && (_dtmfFeedback && _dtmfDirectFeedback);
106
107 if (playDtmfToneDirect)
108 {
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);
112
113 // Play out local feedback tone directly (same approach for both inband
114 // and outband).
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
117 // differently.
118 _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80,
119 attenuationDb);
120 }
121
122 if (outOfBand)
123 {
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);
130
131 return channelPtr->SendTelephoneEventOutband(eventCode,
132 lengthMs,
133 attenuationDb,
134 playDTFMEvent);
135 }
136 else
137 {
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);
145
146 return channelPtr->SendTelephoneEventInband(eventCode,
147 lengthMs,
148 attenuationDb,
149 playDTFMEvent);
150 }
151}
152
153int VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel,
154 unsigned char type)
155{
156 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
157 "SetSendTelephoneEventPayloadType(channel=%d, type=%u)",
158 channel, type);
159 if (!_shared->statistics().Initialized())
160 {
161 _shared->SetLastError(VE_NOT_INITED, kTraceError);
162 return -1;
163 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000164 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
165 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000166 if (channelPtr == NULL)
167 {
168 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
169 "SetSendTelephoneEventPayloadType() failed to locate channel");
170 return -1;
171 }
172 return channelPtr->SetSendTelephoneEventPayloadType(type);
173}
174
175int VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel,
176 unsigned char& type)
177{
178 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
179 "GetSendTelephoneEventPayloadType(channel=%d)", channel);
180 if (!_shared->statistics().Initialized())
181 {
182 _shared->SetLastError(VE_NOT_INITED, kTraceError);
183 return -1;
184 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000185 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
186 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000187 if (channelPtr == NULL)
188 {
189 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
190 "GetSendTelephoneEventPayloadType() failed to locate channel");
191 return -1;
192 }
193 return channelPtr->GetSendTelephoneEventPayloadType(type);
194}
195
196int VoEDtmfImpl::PlayDtmfTone(int eventCode,
197 int lengthMs,
198 int attenuationDb)
199{
200 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
201 "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)",
202 eventCode, lengthMs, attenuationDb);
203
204 if (!_shared->statistics().Initialized())
205 {
206 _shared->SetLastError(VE_NOT_INITED, kTraceError);
207 return -1;
208 }
209 if (!_shared->audio_device()->Playing())
210 {
211 _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
212 "PlayDtmfTone() no channel is playing out");
213 return -1;
214 }
215 if ((eventCode < kMinDtmfEventCode) ||
216 (eventCode > kMaxDtmfEventCode) ||
217 (lengthMs < kMinTelephoneEventDuration) ||
218 (lengthMs > kMaxTelephoneEventDuration) ||
219 (attenuationDb <kMinTelephoneEventAttenuation) ||
220 (attenuationDb > kMaxTelephoneEventAttenuation))
221 {
222 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
223 "PlayDtmfTone() invalid tone parameter(s)");
224 return -1;
225 }
226 return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs,
227 attenuationDb);
228}
229
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000230int VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback)
231{
232 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
233 "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
234 (int)enable, (int)directFeedback);
235
236 CriticalSectionScoped sc(_shared->crit_sec());
237
238 _dtmfFeedback = enable;
239 _dtmfDirectFeedback = directFeedback;
240
241 return 0;
242}
243
244int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback)
245{
246 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
247 "GetDtmfFeedbackStatus()");
248
249 CriticalSectionScoped sc(_shared->crit_sec());
250
251 enabled = _dtmfFeedback;
252 directFeedback = _dtmfDirectFeedback;
253
254 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
255 VoEId(_shared->instance_id(), -1),
256 "GetDtmfFeedbackStatus() => enabled=%d, directFeedback=%d",
257 enabled, directFeedback);
258 return 0;
259}
260
261int VoEDtmfImpl::SetDtmfPlayoutStatus(int channel, bool enable)
262{
263 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
264 "SetDtmfPlayoutStatus(channel=%d, enable=%d)",
265 channel, enable);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000266
267 if (!_shared->statistics().Initialized())
268 {
269 _shared->SetLastError(VE_NOT_INITED, kTraceError);
270 return -1;
271 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000272 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
273 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000274 if (channelPtr == NULL)
275 {
276 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
277 "SetDtmfPlayoutStatus() failed to locate channel");
278 return -1;
279 }
280 return channelPtr->SetDtmfPlayoutStatus(enable);
281}
282
283int VoEDtmfImpl::GetDtmfPlayoutStatus(int channel, bool& enabled)
284{
285 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
286 "GetDtmfPlayoutStatus(channel=%d, enabled=?)", channel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000287 if (!_shared->statistics().Initialized())
288 {
289 _shared->SetLastError(VE_NOT_INITED, kTraceError);
290 return -1;
291 }
pbos@webrtc.orgb3ada152013-08-07 17:57:36 +0000292 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
293 voe::Channel* channelPtr = ch.channel();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000294 if (channelPtr == NULL)
295 {
296 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
297 "GetDtmfPlayoutStatus() failed to locate channel");
298 return -1;
299 }
300 enabled = channelPtr->DtmfPlayoutStatus();
301 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
302 VoEId(_shared->instance_id(), -1),
303 "GetDtmfPlayoutStatus() => enabled=%d", enabled);
304 return 0;
305}
306
307#endif // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
308
309} // namespace webrtc