Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / voice_engine / voe_dtmf_impl.cc
1 /*
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
11 #include "webrtc/voice_engine/voe_dtmf_impl.h"
12
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"
20
21 namespace webrtc {
22
23 VoEDtmf* 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     }
32     VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
33     s->AddRef();
34     return s;
35 #endif
36 }
37
38 #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
39
40 VoEDtmfImpl::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
49 VoEDtmfImpl::~VoEDtmfImpl()
50 {
51     WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
52                  "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
53 }
54
55 int 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     }
70     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
71     voe::Channel* channelPtr = ch.channel();
72     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
153 int 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     }
164     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
165     voe::Channel* channelPtr = ch.channel();
166     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
175 int 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     }
185     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
186     voe::Channel* channelPtr = ch.channel();
187     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
196 int 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
230 int VoEDtmfImpl::StartPlayingDtmfTone(int eventCode,
231                                       int attenuationDb)
232 {
233     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
234                  "StartPlayingDtmfTone(eventCode=%d, attenuationDb=%d)",
235                  eventCode, attenuationDb);
236
237     if (!_shared->statistics().Initialized())
238     {
239         _shared->SetLastError(VE_NOT_INITED, kTraceError);
240         return -1;
241     }
242     if (!_shared->audio_device()->Playing())
243     {
244         _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
245             "StartPlayingDtmfTone() no channel is playing out");
246         return -1;
247     }
248     if ((eventCode < kMinDtmfEventCode) ||
249         (eventCode > kMaxDtmfEventCode) ||
250         (attenuationDb < kMinTelephoneEventAttenuation) ||
251         (attenuationDb > kMaxTelephoneEventAttenuation))
252     {
253         _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
254             "StartPlayingDtmfTone() invalid tone parameter(s)");
255         return -1;
256     }
257     return _shared->output_mixer()->StartPlayingDtmfTone(eventCode,
258                                                        attenuationDb);
259 }
260
261 int VoEDtmfImpl::StopPlayingDtmfTone()
262 {
263     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
264                  "StopPlayingDtmfTone()");
265
266     if (!_shared->statistics().Initialized())
267     {
268         _shared->SetLastError(VE_NOT_INITED, kTraceError);
269         return -1;
270     }
271     return _shared->output_mixer()->StopPlayingDtmfTone();
272 }
273
274 int VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback)
275 {
276     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
277                  "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
278                  (int)enable, (int)directFeedback);
279
280     CriticalSectionScoped sc(_shared->crit_sec());
281
282     _dtmfFeedback = enable;
283     _dtmfDirectFeedback = directFeedback;
284
285     return 0;
286 }
287
288 int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback)
289 {
290     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
291                  "GetDtmfFeedbackStatus()");
292
293     CriticalSectionScoped sc(_shared->crit_sec());
294
295     enabled = _dtmfFeedback;
296     directFeedback = _dtmfDirectFeedback;
297
298     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
299         VoEId(_shared->instance_id(), -1),
300         "GetDtmfFeedbackStatus() => enabled=%d, directFeedback=%d",
301         enabled, directFeedback);
302     return 0;
303 }
304
305 int VoEDtmfImpl::SetDtmfPlayoutStatus(int channel, bool enable)
306 {
307     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
308                  "SetDtmfPlayoutStatus(channel=%d, enable=%d)",
309                  channel, enable);
310
311     if (!_shared->statistics().Initialized())
312     {
313         _shared->SetLastError(VE_NOT_INITED, kTraceError);
314         return -1;
315     }
316     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
317     voe::Channel* channelPtr = ch.channel();
318     if (channelPtr == NULL)
319     {
320         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
321             "SetDtmfPlayoutStatus() failed to locate channel");
322         return -1;
323     }
324     return channelPtr->SetDtmfPlayoutStatus(enable);
325 }
326
327 int VoEDtmfImpl::GetDtmfPlayoutStatus(int channel, bool& enabled)
328 {
329     WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
330                  "GetDtmfPlayoutStatus(channel=%d, enabled=?)", channel);
331     if (!_shared->statistics().Initialized())
332     {
333         _shared->SetLastError(VE_NOT_INITED, kTraceError);
334         return -1;
335     }
336     voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
337     voe::Channel* channelPtr = ch.channel();
338     if (channelPtr == NULL)
339     {
340         _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
341             "GetDtmfPlayoutStatus() failed to locate channel");
342         return -1;
343     }
344     enabled = channelPtr->DtmfPlayoutStatus();
345     WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
346         VoEId(_shared->instance_id(), -1),
347         "GetDtmfPlayoutStatus() => enabled=%d", enabled);
348     return 0;
349 }
350
351 #endif  // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
352
353 }  // namespace webrtc