OLD | NEW |
| (Empty) |
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/base/criticalsection.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 | |
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 | |
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 | |
44 VoEDtmfImpl::~VoEDtmfImpl() { | |
45 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), | |
46 "VoEDtmfImpl::~VoEDtmfImpl() - dtor"); | |
47 } | |
48 | |
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 | |
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 | |
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 | |
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 | |
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 rtc::CritScope cs(_shared->crit_sec()); | |
201 | |
202 _dtmfFeedback = enable; | |
203 _dtmfDirectFeedback = directFeedback; | |
204 | |
205 return 0; | |
206 } | |
207 | |
208 int VoEDtmfImpl::GetDtmfFeedbackStatus(bool& enabled, bool& directFeedback) { | |
209 rtc::CritScope cs(_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 | |
OLD | NEW |