• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/include/critical_section_wrapper.h"
14 #include "webrtc/system_wrappers/include/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 
GetInterface(VoiceEngine * voiceEngine)23 VoEDtmf* VoEDtmf::GetInterface(VoiceEngine* voiceEngine) {
24 #ifndef WEBRTC_VOICE_ENGINE_DTMF_API
25   return NULL;
26 #else
27   if (NULL == voiceEngine) {
28     return NULL;
29   }
30   VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
31   s->AddRef();
32   return s;
33 #endif
34 }
35 
36 #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
37 
VoEDtmfImpl(voe::SharedData * shared)38 VoEDtmfImpl::VoEDtmfImpl(voe::SharedData* shared)
39     : _dtmfFeedback(true), _dtmfDirectFeedback(false), _shared(shared) {
40   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
41                "VoEDtmfImpl::VoEDtmfImpl() - ctor");
42 }
43 
~VoEDtmfImpl()44 VoEDtmfImpl::~VoEDtmfImpl() {
45   WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1),
46                "VoEDtmfImpl::~VoEDtmfImpl() - dtor");
47 }
48 
SendTelephoneEvent(int channel,int eventCode,bool outOfBand,int lengthMs,int attenuationDb)49 int VoEDtmfImpl::SendTelephoneEvent(int channel,
50                                     int eventCode,
51                                     bool outOfBand,
52                                     int lengthMs,
53                                     int attenuationDb) {
54   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
55                "SendTelephoneEvent(channel=%d, eventCode=%d, outOfBand=%d,"
56                "length=%d, attenuationDb=%d)",
57                channel, eventCode, (int)outOfBand, lengthMs, attenuationDb);
58   if (!_shared->statistics().Initialized()) {
59     _shared->SetLastError(VE_NOT_INITED, kTraceError);
60     return -1;
61   }
62   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
63   voe::Channel* channelPtr = ch.channel();
64   if (channelPtr == NULL) {
65     _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
66                           "SendTelephoneEvent() failed to locate channel");
67     return -1;
68   }
69   if (!channelPtr->Sending()) {
70     _shared->SetLastError(VE_NOT_SENDING, kTraceError,
71                           "SendTelephoneEvent() sending is not active");
72     return -1;
73   }
74 
75   // Sanity check
76   const int maxEventCode = outOfBand ? static_cast<int>(kMaxTelephoneEventCode)
77                                      : static_cast<int>(kMaxDtmfEventCode);
78   const bool testFailed = ((eventCode < 0) || (eventCode > maxEventCode) ||
79                            (lengthMs < kMinTelephoneEventDuration) ||
80                            (lengthMs > kMaxTelephoneEventDuration) ||
81                            (attenuationDb < kMinTelephoneEventAttenuation) ||
82                            (attenuationDb > kMaxTelephoneEventAttenuation));
83   if (testFailed) {
84     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
85                           "SendTelephoneEvent() invalid parameter(s)");
86     return -1;
87   }
88 
89   const bool isDtmf = (eventCode >= 0) && (eventCode <= kMaxDtmfEventCode);
90   const bool playDtmfToneDirect =
91       isDtmf && (_dtmfFeedback && _dtmfDirectFeedback);
92 
93   if (playDtmfToneDirect) {
94     // Mute the microphone signal while playing back the tone directly.
95     // This is to reduce the risk of introducing echo from the added output.
96     _shared->transmit_mixer()->UpdateMuteMicrophoneTime(lengthMs);
97 
98     // Play out local feedback tone directly (same approach for both inband
99     // and outband).
100     // Reduce the length of the the tone with 80ms to reduce risk of echo.
101     // For non-direct feedback, outband and inband cases are handled
102     // differently.
103     _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs - 80,
104                                           attenuationDb);
105   }
106 
107   if (outOfBand) {
108     // The RTP/RTCP module will always deliver OnPlayTelephoneEvent when
109     // an event is transmitted. It is up to the VoE to utilize it or not.
110     // This flag ensures that feedback/playout is enabled; however, the
111     // channel object must still parse out the Dtmf events (0-15) from
112     // all possible events (0-255).
113     const bool playDTFMEvent = (_dtmfFeedback && !_dtmfDirectFeedback);
114 
115     return channelPtr->SendTelephoneEventOutband(eventCode, lengthMs,
116                                                  attenuationDb, playDTFMEvent);
117   } else {
118     // For Dtmf tones, we want to ensure that inband tones are played out
119     // in sync with the transmitted audio. This flag is utilized by the
120     // channel object to determine if the queued Dtmf e vent shall also
121     // be fed to the output mixer in the same step as input audio is
122     // replaced by inband Dtmf tones.
123     const bool playDTFMEvent =
124         (isDtmf && _dtmfFeedback && !_dtmfDirectFeedback);
125 
126     return channelPtr->SendTelephoneEventInband(eventCode, lengthMs,
127                                                 attenuationDb, playDTFMEvent);
128   }
129 }
130 
SetSendTelephoneEventPayloadType(int channel,unsigned char type)131 int VoEDtmfImpl::SetSendTelephoneEventPayloadType(int channel,
132                                                   unsigned char type) {
133   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
134                "SetSendTelephoneEventPayloadType(channel=%d, type=%u)", channel,
135                type);
136   if (!_shared->statistics().Initialized()) {
137     _shared->SetLastError(VE_NOT_INITED, kTraceError);
138     return -1;
139   }
140   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
141   voe::Channel* channelPtr = ch.channel();
142   if (channelPtr == NULL) {
143     _shared->SetLastError(
144         VE_CHANNEL_NOT_VALID, kTraceError,
145         "SetSendTelephoneEventPayloadType() failed to locate channel");
146     return -1;
147   }
148   return channelPtr->SetSendTelephoneEventPayloadType(type);
149 }
150 
GetSendTelephoneEventPayloadType(int channel,unsigned char & type)151 int VoEDtmfImpl::GetSendTelephoneEventPayloadType(int channel,
152                                                   unsigned char& type) {
153   if (!_shared->statistics().Initialized()) {
154     _shared->SetLastError(VE_NOT_INITED, kTraceError);
155     return -1;
156   }
157   voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel);
158   voe::Channel* channelPtr = ch.channel();
159   if (channelPtr == NULL) {
160     _shared->SetLastError(
161         VE_CHANNEL_NOT_VALID, kTraceError,
162         "GetSendTelephoneEventPayloadType() failed to locate channel");
163     return -1;
164   }
165   return channelPtr->GetSendTelephoneEventPayloadType(type);
166 }
167 
PlayDtmfTone(int eventCode,int lengthMs,int attenuationDb)168 int VoEDtmfImpl::PlayDtmfTone(int eventCode, int lengthMs, int attenuationDb) {
169   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
170                "PlayDtmfTone(eventCode=%d, lengthMs=%d, attenuationDb=%d)",
171                eventCode, lengthMs, attenuationDb);
172 
173   if (!_shared->statistics().Initialized()) {
174     _shared->SetLastError(VE_NOT_INITED, kTraceError);
175     return -1;
176   }
177   if (!_shared->audio_device()->Playing()) {
178     _shared->SetLastError(VE_NOT_PLAYING, kTraceError,
179                           "PlayDtmfTone() no channel is playing out");
180     return -1;
181   }
182   if ((eventCode < kMinDtmfEventCode) || (eventCode > kMaxDtmfEventCode) ||
183       (lengthMs < kMinTelephoneEventDuration) ||
184       (lengthMs > kMaxTelephoneEventDuration) ||
185       (attenuationDb < kMinTelephoneEventAttenuation) ||
186       (attenuationDb > kMaxTelephoneEventAttenuation)) {
187     _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
188                           "PlayDtmfTone() invalid tone parameter(s)");
189     return -1;
190   }
191   return _shared->output_mixer()->PlayDtmfTone(eventCode, lengthMs,
192                                                attenuationDb);
193 }
194 
SetDtmfFeedbackStatus(bool enable,bool directFeedback)195 int VoEDtmfImpl::SetDtmfFeedbackStatus(bool enable, bool directFeedback) {
196   WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1),
197                "SetDtmfFeedbackStatus(enable=%d, directFeeback=%d)",
198                (int)enable, (int)directFeedback);
199 
200   CriticalSectionScoped sc(_shared->crit_sec());
201 
202   _dtmfFeedback = enable;
203   _dtmfDirectFeedback = directFeedback;
204 
205   return 0;
206 }
207 
GetDtmfFeedbackStatus(bool & enabled,bool & directFeedback)208 int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback) {
209   CriticalSectionScoped sc(_shared->crit_sec());
210 
211   enabled = _dtmfFeedback;
212   directFeedback = _dtmfDirectFeedback;
213   return 0;
214 }
215 #endif  // #ifdef WEBRTC_VOICE_ENGINE_DTMF_API
216 
217 }  // namespace webrtc
218