blob: 9a59a07fe4a0593560c3c5920f16e8f0ecea47cd [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000013#include "webrtc/modules/audio_device/include/audio_device.h"
14#include "webrtc/modules/audio_processing/include/audio_processing.h"
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000015#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
16#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
18#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000019#include "webrtc/modules/utility/interface/audio_frame_operations.h"
20#include "webrtc/modules/utility/interface/process_thread.h"
21#include "webrtc/modules/utility/interface/rtp_dump.h"
22#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
23#include "webrtc/system_wrappers/interface/logging.h"
24#include "webrtc/system_wrappers/interface/trace.h"
25#include "webrtc/voice_engine/include/voe_base.h"
26#include "webrtc/voice_engine/include/voe_external_media.h"
27#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
28#include "webrtc/voice_engine/output_mixer.h"
29#include "webrtc/voice_engine/statistics.h"
30#include "webrtc/voice_engine/transmit_mixer.h"
31#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000032
33#if defined(_WIN32)
34#include <Qos.h>
35#endif
36
andrew@webrtc.org50419b02012-11-14 19:07:54 +000037namespace webrtc {
38namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000039
pbos@webrtc.org6141e132013-04-09 10:09:10 +000040int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000041Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000042 uint8_t payloadType,
43 uint32_t timeStamp,
44 const uint8_t* payloadData,
45 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000046 const RTPFragmentationHeader* fragmentation)
47{
48 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
49 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
50 " payloadSize=%u, fragmentation=0x%x)",
51 frameType, payloadType, timeStamp, payloadSize, fragmentation);
52
53 if (_includeAudioLevelIndication)
54 {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000055 assert(_rtpAudioProc.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000056 // Store current audio level in the RTP/RTCP module.
57 // The level will be used in combination with voice-activity state
58 // (frameType) to add an RTP header extension
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000059 _rtpRtcpModule->SetAudioLevel(_rtpAudioProc->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000060 }
61
62 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
63 // packetization.
64 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000065 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000066 payloadType,
67 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000068 // Leaving the time when this frame was
69 // received from the capture device as
70 // undefined for voice for now.
71 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000072 payloadData,
73 payloadSize,
74 fragmentation) == -1)
75 {
76 _engineStatisticsPtr->SetLastError(
77 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
78 "Channel::SendData() failed to send data to RTP/RTCP module");
79 return -1;
80 }
81
82 _lastLocalTimeStamp = timeStamp;
83 _lastPayloadType = payloadType;
84
85 return 0;
86}
87
pbos@webrtc.org6141e132013-04-09 10:09:10 +000088int32_t
89Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +000090{
91 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
92 "Channel::InFrameType(frameType=%d)", frameType);
93
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000094 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000095 // 1 indicates speech
96 _sendFrameType = (frameType == 1) ? 1 : 0;
97 return 0;
98}
99
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000100int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000101Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000102{
103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
104 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
105
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000106 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 if (_rxVadObserverPtr)
108 {
109 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
110 }
111
112 return 0;
113}
114
115int
116Channel::SendPacket(int channel, const void *data, int len)
117{
118 channel = VoEChannelId(channel);
119 assert(channel == _channelId);
120
121 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
122 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
123
124 if (_transportPtr == NULL)
125 {
126 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
127 "Channel::SendPacket() failed to send RTP packet due to"
128 " invalid transport object");
129 return -1;
130 }
131
132 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
133 // API
134 if (_insertExtraRTPPacket)
135 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136 uint8_t* rtpHdr = (uint8_t*)data;
137 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (_extraMarkerBit)
139 {
140 M_PT = 0x80; // set the M-bit
141 }
142 M_PT += _extraPayloadType; // set the payload type
143 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
144 _insertExtraRTPPacket = false; // insert one packet only
145 }
146
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 uint8_t* bufferToSendPtr = (uint8_t*)data;
148 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
150 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 {
153 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
154 VoEId(_instanceId,_channelId),
155 "Channel::SendPacket() RTP dump to output file failed");
156 }
157
158 // SRTP or External encryption
159 if (_encrypting)
160 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000161 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
163 if (_encryptionPtr)
164 {
165 if (!_encryptionRTPBufferPtr)
166 {
167 // Allocate memory for encryption buffer one time only
168 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000170 memset(_encryptionRTPBufferPtr, 0,
171 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
173
174 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000175 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 _encryptionPtr->encrypt(_channelId,
177 bufferToSendPtr,
178 _encryptionRTPBufferPtr,
179 bufferLength,
180 (int*)&encryptedBufferLength);
181 if (encryptedBufferLength <= 0)
182 {
183 _engineStatisticsPtr->SetLastError(
184 VE_ENCRYPTION_FAILED,
185 kTraceError, "Channel::SendPacket() encryption failed");
186 return -1;
187 }
188
189 // Replace default data buffer with encrypted buffer
190 bufferToSendPtr = _encryptionRTPBufferPtr;
191 bufferLength = encryptedBufferLength;
192 }
193 }
194
195 // Packet transmission using WebRtc socket transport
196 if (!_externalTransport)
197 {
198 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
199 bufferLength);
200 if (n < 0)
201 {
202 WEBRTC_TRACE(kTraceError, kTraceVoice,
203 VoEId(_instanceId,_channelId),
204 "Channel::SendPacket() RTP transmission using WebRtc"
205 " sockets failed");
206 return -1;
207 }
208 return n;
209 }
210
211 // Packet transmission using external transport transport
212 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000213 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
215 int n = _transportPtr->SendPacket(channel,
216 bufferToSendPtr,
217 bufferLength);
218 if (n < 0)
219 {
220 WEBRTC_TRACE(kTraceError, kTraceVoice,
221 VoEId(_instanceId,_channelId),
222 "Channel::SendPacket() RTP transmission using external"
223 " transport failed");
224 return -1;
225 }
226 return n;
227 }
228}
229
230int
231Channel::SendRTCPPacket(int channel, const void *data, int len)
232{
233 channel = VoEChannelId(channel);
234 assert(channel == _channelId);
235
236 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
237 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
238
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000240 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000241 if (_transportPtr == NULL)
242 {
243 WEBRTC_TRACE(kTraceError, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendRTCPPacket() failed to send RTCP packet"
246 " due to invalid transport object");
247 return -1;
248 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 uint8_t* bufferToSendPtr = (uint8_t*)data;
252 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000255 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
258 VoEId(_instanceId,_channelId),
259 "Channel::SendPacket() RTCP dump to output file failed");
260 }
261
262 // SRTP or External encryption
263 if (_encrypting)
264 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000265 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
267 if (_encryptionPtr)
268 {
269 if (!_encryptionRTCPBufferPtr)
270 {
271 // Allocate memory for encryption buffer one time only
272 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000273 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
276 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000277 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 _encryptionPtr->encrypt_rtcp(_channelId,
279 bufferToSendPtr,
280 _encryptionRTCPBufferPtr,
281 bufferLength,
282 (int*)&encryptedBufferLength);
283 if (encryptedBufferLength <= 0)
284 {
285 _engineStatisticsPtr->SetLastError(
286 VE_ENCRYPTION_FAILED, kTraceError,
287 "Channel::SendRTCPPacket() encryption failed");
288 return -1;
289 }
290
291 // Replace default data buffer with encrypted buffer
292 bufferToSendPtr = _encryptionRTCPBufferPtr;
293 bufferLength = encryptedBufferLength;
294 }
295 }
296
297 // Packet transmission using WebRtc socket transport
298 if (!_externalTransport)
299 {
300 int n = _transportPtr->SendRTCPPacket(channel,
301 bufferToSendPtr,
302 bufferLength);
303 if (n < 0)
304 {
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
306 VoEId(_instanceId,_channelId),
307 "Channel::SendRTCPPacket() transmission using WebRtc"
308 " sockets failed");
309 return -1;
310 }
311 return n;
312 }
313
314 // Packet transmission using external transport transport
315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000316 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000317 if (_transportPtr == NULL)
318 {
319 return -1;
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 int n = _transportPtr->SendRTCPPacket(channel,
322 bufferToSendPtr,
323 bufferLength);
324 if (n < 0)
325 {
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using external"
329 " transport failed");
330 return -1;
331 }
332 return n;
333 }
334
335 return len;
336}
337
338void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000339Channel::OnPlayTelephoneEvent(int32_t id,
340 uint8_t event,
341 uint16_t lengthMs,
342 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343{
344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
345 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000346 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
348 if (!_playOutbandDtmfEvent || (event > 15))
349 {
350 // Ignore callback since feedback is disabled or event is not a
351 // Dtmf tone event.
352 return;
353 }
354
355 assert(_outputMixerPtr != NULL);
356
357 // Start playing out the Dtmf tone (if playout is enabled).
358 // Reduce length of tone with 80ms to the reduce risk of echo.
359 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
360}
361
362void
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000363Channel::OnIncomingSSRCChanged(int32_t id,
364 uint32_t SSRC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000365{
366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
367 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000368 id, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000369
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000370 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000371 assert(channel == _channelId);
372
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000373 // Reset RTP-module counters since a new incoming RTP stream is detected
374 rtp_receive_statistics_->ResetDataCounters();
375 rtp_receive_statistics_->ResetStatistics();
376
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 if (_rtpObserver)
378 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000379 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
381 if (_rtpObserverPtr)
382 {
383 // Send new SSRC to registered observer using callback
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000384 _rtpObserverPtr->OnIncomingSSRCChanged(channel, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 }
386 }
387}
388
pbos@webrtc.org92135212013-05-14 08:31:39 +0000389void Channel::OnIncomingCSRCChanged(int32_t id,
390 uint32_t CSRC,
391 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000392{
393 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
394 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
395 id, CSRC, added);
396
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000397 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 assert(channel == _channelId);
399
400 if (_rtpObserver)
401 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000402 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000403
404 if (_rtpObserverPtr)
405 {
406 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
407 }
408 }
409}
410
elham@webrtc.orgb7eda432013-07-15 21:08:27 +0000411void Channel::OnResetStatistics() {
412 rtp_receive_statistics_->ResetStatistics();
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000413}
414
niklase@google.com470e71d2011-07-07 08:21:25 +0000415void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000416Channel::OnApplicationDataReceived(int32_t id,
417 uint8_t subType,
418 uint32_t name,
419 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000420 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000421{
422 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
423 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
424 " name=%u, length=%u)",
425 id, subType, name, length);
426
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000427 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 assert(channel == _channelId);
429
430 if (_rtcpObserver)
431 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000432 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
434 if (_rtcpObserverPtr)
435 {
436 _rtcpObserverPtr->OnApplicationDataReceived(channel,
437 subType,
438 name,
439 data,
440 length);
441 }
442 }
443}
444
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000445int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000446Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000447 int32_t id,
448 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000449 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000450 int frequency,
451 uint8_t channels,
452 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000453{
454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
455 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
456 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
457 id, payloadType, payloadName, frequency, channels, rate);
458
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000459 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000460
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000461 CodecInst receiveCodec = {0};
462 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
464 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 receiveCodec.plfreq = frequency;
466 receiveCodec.channels = channels;
467 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000468 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000469
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000470 _audioCodingModule.Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 receiveCodec.pacsize = dummyCodec.pacsize;
472
473 // Register the new codec to the ACM
474 if (_audioCodingModule.RegisterReceiveCodec(receiveCodec) == -1)
475 {
476 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000477 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 "Channel::OnInitializeDecoder() invalid codec ("
479 "pt=%d, name=%s) received - 1", payloadType, payloadName);
480 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
481 return -1;
482 }
483
484 return 0;
485}
486
487void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000488Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000489{
490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
491 "Channel::OnPacketTimeout(id=%d)", id);
492
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000493 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 if (_voiceEngineObserverPtr)
495 {
496 if (_receiving || _externalTransport)
497 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000498 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 assert(channel == _channelId);
500 // Ensure that next OnReceivedPacket() callback will trigger
501 // a VE_PACKET_RECEIPT_RESTARTED callback.
502 _rtpPacketTimedOut = true;
503 // Deliver callback to the observer
504 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
505 VoEId(_instanceId,_channelId),
506 "Channel::OnPacketTimeout() => "
507 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
508 _voiceEngineObserverPtr->CallbackOnError(channel,
509 VE_RECEIVE_PACKET_TIMEOUT);
510 }
511 }
512}
513
514void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000515Channel::OnReceivedPacket(int32_t id,
516 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000517{
518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
519 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
520 id, packetType);
521
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000522 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000523
524 // Notify only for the case when we have restarted an RTP session.
525 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
526 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000527 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 if (_voiceEngineObserverPtr)
529 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000530 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 assert(channel == _channelId);
532 // Reset timeout mechanism
533 _rtpPacketTimedOut = false;
534 // Deliver callback to the observer
535 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
536 VoEId(_instanceId,_channelId),
537 "Channel::OnPacketTimeout() =>"
538 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
539 _voiceEngineObserverPtr->CallbackOnError(
540 channel,
541 VE_PACKET_RECEIPT_RESTARTED);
542 }
543 }
544}
545
546void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000547Channel::OnPeriodicDeadOrAlive(int32_t id,
548 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000549{
550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
551 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
552
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000553 {
554 CriticalSectionScoped cs(&_callbackCritSect);
555 if (!_connectionObserver)
556 return;
557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000559 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 assert(channel == _channelId);
561
562 // Use Alive as default to limit risk of false Dead detections
563 bool isAlive(true);
564
565 // Always mark the connection as Dead when the module reports kRtpDead
566 if (kRtpDead == alive)
567 {
568 isAlive = false;
569 }
570
571 // It is possible that the connection is alive even if no RTP packet has
572 // been received for a long time since the other side might use VAD/DTX
573 // and a low SID-packet update rate.
574 if ((kRtpNoRtp == alive) && _playing)
575 {
576 // Detect Alive for all NetEQ states except for the case when we are
577 // in PLC_CNG state.
578 // PLC_CNG <=> background noise only due to long expand or error.
579 // Note that, the case where the other side stops sending during CNG
580 // state will be detected as Alive. Dead is is not set until after
581 // missing RTCP packets for at least twelve seconds (handled
582 // internally by the RTP/RTCP module).
583 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
584 }
585
586 UpdateDeadOrAliveCounters(isAlive);
587
588 // Send callback to the registered observer
589 if (_connectionObserver)
590 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000591 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 if (_connectionObserverPtr)
593 {
594 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
595 }
596 }
597}
598
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000599int32_t
600Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000601 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 const WebRtcRTPHeader* rtpHeader)
603{
604 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
605 "Channel::OnReceivedPayloadData(payloadSize=%d,"
606 " payloadType=%u, audioChannel=%u)",
607 payloadSize,
608 rtpHeader->header.payloadType,
609 rtpHeader->type.Audio.channel);
610
roosa@google.com0870f022012-12-12 21:31:41 +0000611 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
612
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 if (!_playing)
614 {
615 // Avoid inserting into NetEQ when we are not playing. Count the
616 // packet as discarded.
617 WEBRTC_TRACE(kTraceStream, kTraceVoice,
618 VoEId(_instanceId, _channelId),
619 "received packet is discarded since playing is not"
620 " activated");
621 _numberOfDiscardedPackets++;
622 return 0;
623 }
624
625 // Push the incoming payload (parsed and ready for decoding) into the ACM
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +0000626 if (_audioCodingModule.IncomingPacket(payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 payloadSize,
628 *rtpHeader) != 0)
629 {
630 _engineStatisticsPtr->SetLastError(
631 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
632 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
633 return -1;
634 }
635
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000636 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 UpdatePacketDelay(rtpHeader->header.timestamp,
638 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000639
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000640 uint16_t round_trip_time = 0;
641 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
642 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000643
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000644 std::vector<uint16_t> nack_list = _audioCodingModule.GetNackList(
645 round_trip_time);
646 if (!nack_list.empty()) {
647 // Can't use nack_list.data() since it's not supported by all
648 // compilers.
649 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000650 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 return 0;
652}
653
pbos@webrtc.org92135212013-05-14 08:31:39 +0000654int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000655{
656 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
657 "Channel::GetAudioFrame(id=%d)", id);
658
659 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000660 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000661 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 {
663 WEBRTC_TRACE(kTraceError, kTraceVoice,
664 VoEId(_instanceId,_channelId),
665 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000666 // In all likelihood, the audio in this frame is garbage. We return an
667 // error so that the audio mixer module doesn't add it to the mix. As
668 // a result, it won't be played out and the actions skipped here are
669 // irrelevant.
670 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 }
672
673 if (_RxVadDetection)
674 {
675 UpdateRxVadDetection(audioFrame);
676 }
677
678 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000679 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000680 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000681 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000682
683 // Perform far-end AudioProcessing module processing on the received signal
684 if (_rxApmIsEnabled)
685 {
686 ApmProcessRx(audioFrame);
687 }
688
689 // Output volume scaling
690 if (_outputGain < 0.99f || _outputGain > 1.01f)
691 {
692 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
693 }
694
695 // Scale left and/or right channel(s) if stereo and master balance is
696 // active
697
698 if (_panLeft != 1.0f || _panRight != 1.0f)
699 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000700 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 {
702 // Emulate stereo mode since panning is active.
703 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000704 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000705 }
706 // For true stereo mode (when we are receiving a stereo signal), no
707 // action is needed.
708
709 // Do the panning operation (the audio frame contains stereo at this
710 // stage)
711 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
712 }
713
714 // Mix decoded PCM output with file if file mixing is enabled
715 if (_outputFilePlaying)
716 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000717 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 }
719
720 // Place channel in on-hold state (~muted) if on-hold is activated
721 if (_outputIsOnHold)
722 {
723 AudioFrameOperations::Mute(audioFrame);
724 }
725
726 // External media
727 if (_outputExternalMedia)
728 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000729 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000730 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 if (_outputExternalMediaCallbackPtr)
732 {
733 _outputExternalMediaCallbackPtr->Process(
734 _channelId,
735 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000736 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000737 audioFrame.samples_per_channel_,
738 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 isStereo);
740 }
741 }
742
743 // Record playout if enabled
744 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000745 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000746
747 if (_outputFileRecording && _outputFileRecorderPtr)
748 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000749 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 }
751 }
752
753 // Measure audio level (0-9)
754 _outputAudioLevel.ComputeLevel(audioFrame);
755
756 return 0;
757}
758
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000759int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000760Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000761{
762 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
763 "Channel::NeededFrequency(id=%d)", id);
764
765 int highestNeeded = 0;
766
767 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000768 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000769
770 // Return the bigger of playout and receive frequency in the ACM.
771 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
772 {
773 highestNeeded = _audioCodingModule.PlayoutFrequency();
774 }
775 else
776 {
777 highestNeeded = receiveFrequency;
778 }
779
780 // Special case, if we're playing a file on the playout side
781 // we take that frequency into consideration as well
782 // This is not needed on sending side, since the codec will
783 // limit the spectrum anyway.
784 if (_outputFilePlaying)
785 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000786 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 if (_outputFilePlayerPtr && _outputFilePlaying)
788 {
789 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
790 {
791 highestNeeded=_outputFilePlayerPtr->Frequency();
792 }
793 }
794 }
795
796 return(highestNeeded);
797}
798
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000799int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000800Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000801 int32_t channelId,
802 uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000803{
804 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
805 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
806 channelId, instanceId);
807
808 channel = new Channel(channelId, instanceId);
809 if (channel == NULL)
810 {
811 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
812 VoEId(instanceId,channelId),
813 "Channel::CreateChannel() unable to allocate memory for"
814 " channel");
815 return -1;
816 }
817 return 0;
818}
819
820void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000821Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000822{
823 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
824 "Channel::PlayNotification(id=%d, durationMs=%d)",
825 id, durationMs);
826
827 // Not implement yet
828}
829
830void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000831Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000832{
833 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
834 "Channel::RecordNotification(id=%d, durationMs=%d)",
835 id, durationMs);
836
837 // Not implement yet
838}
839
840void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000841Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000842{
843 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
844 "Channel::PlayFileEnded(id=%d)", id);
845
846 if (id == _inputFilePlayerId)
847 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000848 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000849
850 _inputFilePlaying = false;
851 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
852 VoEId(_instanceId,_channelId),
853 "Channel::PlayFileEnded() => input file player module is"
854 " shutdown");
855 }
856 else if (id == _outputFilePlayerId)
857 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000858 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000859
860 _outputFilePlaying = false;
861 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
862 VoEId(_instanceId,_channelId),
863 "Channel::PlayFileEnded() => output file player module is"
864 " shutdown");
865 }
866}
867
868void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000869Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000870{
871 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
872 "Channel::RecordFileEnded(id=%d)", id);
873
874 assert(id == _outputFileRecorderId);
875
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000876 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 _outputFileRecording = false;
879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_instanceId,_channelId),
881 "Channel::RecordFileEnded() => output file recorder module is"
882 " shutdown");
883}
884
pbos@webrtc.org92135212013-05-14 08:31:39 +0000885Channel::Channel(int32_t channelId,
886 uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000887 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
888 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000890 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000891 rtp_header_parser_(RtpHeaderParser::Create()),
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000892 rtp_payload_registry_(
893 new RTPPayloadRegistry(channelId,
894 RTPPayloadStrategy::CreateStrategy(true))),
895 rtp_receive_statistics_(ReceiveStatistics::Create(
896 Clock::GetRealTimeClock())),
897 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
898 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
899 this, this, rtp_payload_registry_.get())),
900 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000902 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _rtpDumpIn(*RtpDump::CreateRtpDump()),
904 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 _inputFilePlayerPtr(NULL),
908 _outputFilePlayerPtr(NULL),
909 _outputFileRecorderPtr(NULL),
910 // Avoid conflict with other channels by adding 1024 - 1026,
911 // won't use as much as 1024 channels.
912 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
913 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
914 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
915 _inputFilePlaying(false),
916 _outputFilePlaying(false),
917 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000918 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
919 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000920 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000921 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 _inputExternalMediaCallbackPtr(NULL),
923 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000924 _encryptionRTPBufferPtr(NULL),
925 _decryptionRTPBufferPtr(NULL),
926 _encryptionRTCPBufferPtr(NULL),
927 _decryptionRTCPBufferPtr(NULL),
928 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
929 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000930 playout_timestamp_rtp_(0),
931 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000932 _numberOfDiscardedPackets(0),
933 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000934 _outputMixerPtr(NULL),
935 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000936 _moduleProcessThreadPtr(NULL),
937 _audioDeviceModulePtr(NULL),
938 _voiceEngineObserverPtr(NULL),
939 _callbackCritSectPtr(NULL),
940 _transportPtr(NULL),
941 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000942 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000943 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000944 _rxVadObserverPtr(NULL),
945 _oldVadDecision(-1),
946 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000947 _rtpObserverPtr(NULL),
948 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000949 _outputIsOnHold(false),
950 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000951 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000952 _inputIsOnHold(false),
953 _playing(false),
954 _sending(false),
955 _receiving(false),
956 _mixFileWithMicrophone(false),
957 _rtpObserver(false),
958 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 _mute(false),
960 _panLeft(1.0f),
961 _panRight(1.0f),
962 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000963 _encrypting(false),
964 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 _playOutbandDtmfEvent(false),
966 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 _extraPayloadType(0),
968 _insertExtraRTPPacket(false),
969 _extraMarkerBit(false),
970 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000971 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000973 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 _rtpPacketTimedOut(false),
975 _rtpPacketTimeOutIsEnabled(false),
976 _rtpTimeOutSeconds(0),
977 _connectionObserver(false),
978 _connectionObserverPtr(NULL),
979 _countAliveDetections(0),
980 _countDeadDetections(0),
981 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000982 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000983 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 _previousTimestamp(0),
985 _recPacketDelayMs(20),
986 _RxVadDetection(false),
987 _rxApmIsEnabled(false),
988 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000989 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000990{
991 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
992 "Channel::Channel() - ctor");
993 _inbandDtmfQueue.ResetDtmf();
994 _inbandDtmfGenerator.Init();
995 _outputAudioLevel.Clear();
996
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000997 RtpRtcp::Configuration configuration;
998 configuration.id = VoEModuleId(instanceId, channelId);
999 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001000 configuration.outgoing_transport = this;
1001 configuration.rtcp_feedback = this;
1002 configuration.audio_messages = this;
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001003 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001004
1005 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
1006
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 // Create far end AudioProcessing Module
1008 _rxAudioProcessingModulePtr = AudioProcessing::Create(
1009 VoEModuleId(instanceId, channelId));
1010}
1011
1012Channel::~Channel()
1013{
1014 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1015 "Channel::~Channel() - dtor");
1016
1017 if (_outputExternalMedia)
1018 {
1019 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1020 }
1021 if (_inputExternalMedia)
1022 {
1023 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1024 }
1025 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 StopPlayout();
1027
1028 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001029 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 if (_inputFilePlayerPtr)
1031 {
1032 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1033 _inputFilePlayerPtr->StopPlayingFile();
1034 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1035 _inputFilePlayerPtr = NULL;
1036 }
1037 if (_outputFilePlayerPtr)
1038 {
1039 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1040 _outputFilePlayerPtr->StopPlayingFile();
1041 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1042 _outputFilePlayerPtr = NULL;
1043 }
1044 if (_outputFileRecorderPtr)
1045 {
1046 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1047 _outputFileRecorderPtr->StopRecording();
1048 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1049 _outputFileRecorderPtr = NULL;
1050 }
1051 }
1052
1053 // The order to safely shutdown modules in a channel is:
1054 // 1. De-register callbacks in modules
1055 // 2. De-register modules in process thread
1056 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1058 {
1059 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1060 VoEId(_instanceId,_channelId),
1061 "~Channel() failed to de-register transport callback"
1062 " (Audio coding module)");
1063 }
1064 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1065 {
1066 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1067 VoEId(_instanceId,_channelId),
1068 "~Channel() failed to de-register VAD callback"
1069 " (Audio coding module)");
1070 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001072 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 {
1074 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1075 VoEId(_instanceId,_channelId),
1076 "~Channel() failed to deregister RTP/RTCP module");
1077 }
1078
1079 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 if (_rxAudioProcessingModulePtr != NULL)
1082 {
1083 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1084 _rxAudioProcessingModulePtr = NULL;
1085 }
1086
1087 // End of modules shutdown
1088
1089 // Delete other objects
1090 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1091 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1092 delete [] _encryptionRTPBufferPtr;
1093 delete [] _decryptionRTPBufferPtr;
1094 delete [] _encryptionRTCPBufferPtr;
1095 delete [] _decryptionRTCPBufferPtr;
1096 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 delete &_fileCritSect;
1098}
1099
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001100int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001101Channel::Init()
1102{
1103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1104 "Channel::Init()");
1105
1106 // --- Initial sanity
1107
1108 if ((_engineStatisticsPtr == NULL) ||
1109 (_moduleProcessThreadPtr == NULL))
1110 {
1111 WEBRTC_TRACE(kTraceError, kTraceVoice,
1112 VoEId(_instanceId,_channelId),
1113 "Channel::Init() must call SetEngineInformation() first");
1114 return -1;
1115 }
1116
1117 // --- Add modules to process thread (for periodic schedulation)
1118
1119 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001120 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 if (processThreadFail)
1123 {
1124 _engineStatisticsPtr->SetLastError(
1125 VE_CANNOT_INIT_CHANNEL, kTraceError,
1126 "Channel::Init() modules not registered");
1127 return -1;
1128 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001129 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001130
1131 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1132#ifdef WEBRTC_CODEC_AVT
1133 // out-of-band Dtmf tones are played out by default
1134 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1135#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 (_audioCodingModule.InitializeSender() == -1))
1137 {
1138 _engineStatisticsPtr->SetLastError(
1139 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1140 "Channel::Init() unable to initialize the ACM - 1");
1141 return -1;
1142 }
1143
1144 // --- RTP/RTCP module initialization
1145
1146 // Ensure that RTCP is enabled by default for the created channel.
1147 // Note that, the module will keep generating RTCP until it is explicitly
1148 // disabled by the user.
1149 // After StopListen (when no sockets exists), RTCP packets will no longer
1150 // be transmitted since the Transport object will then be invalid.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001151 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1152 // RTCP is enabled by default.
1153 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 {
1155 _engineStatisticsPtr->SetLastError(
1156 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1157 "Channel::Init() RTP/RTCP module not initialized");
1158 return -1;
1159 }
1160
1161 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1164 (_audioCodingModule.RegisterVADCallback(this) == -1);
1165
1166 if (fail)
1167 {
1168 _engineStatisticsPtr->SetLastError(
1169 VE_CANNOT_INIT_CHANNEL, kTraceError,
1170 "Channel::Init() callbacks not registered");
1171 return -1;
1172 }
1173
1174 // --- Register all supported codecs to the receiving side of the
1175 // RTP/RTCP module
1176
1177 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001178 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001179
1180 for (int idx = 0; idx < nSupportedCodecs; idx++)
1181 {
1182 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001183 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001184 (rtp_receiver_->RegisterReceivePayload(
1185 codec.plname,
1186 codec.pltype,
1187 codec.plfreq,
1188 codec.channels,
1189 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 {
1191 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1192 VoEId(_instanceId,_channelId),
1193 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1194 "to RTP/RTCP receiver",
1195 codec.plname, codec.pltype, codec.plfreq,
1196 codec.channels, codec.rate);
1197 }
1198 else
1199 {
1200 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1201 VoEId(_instanceId,_channelId),
1202 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1203 "the RTP/RTCP receiver",
1204 codec.plname, codec.pltype, codec.plfreq,
1205 codec.channels, codec.rate);
1206 }
1207
1208 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001209 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001210 {
1211 SetSendCodec(codec);
1212 }
1213
1214 // Register default PT for outband 'telephone-event'
1215 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1216 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001217 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1219 {
1220 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1221 VoEId(_instanceId,_channelId),
1222 "Channel::Init() failed to register outband "
1223 "'telephone-event' (%d/%d) correctly",
1224 codec.pltype, codec.plfreq);
1225 }
1226 }
1227
1228 if (!STR_CASE_CMP(codec.plname, "CN"))
1229 {
1230 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1231 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001232 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001233 {
1234 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1235 VoEId(_instanceId,_channelId),
1236 "Channel::Init() failed to register CN (%d/%d) "
1237 "correctly - 1",
1238 codec.pltype, codec.plfreq);
1239 }
1240 }
1241#ifdef WEBRTC_CODEC_RED
1242 // Register RED to the receiving side of the ACM.
1243 // We will not receive an OnInitializeDecoder() callback for RED.
1244 if (!STR_CASE_CMP(codec.plname, "RED"))
1245 {
1246 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1247 {
1248 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1249 VoEId(_instanceId,_channelId),
1250 "Channel::Init() failed to register RED (%d/%d) "
1251 "correctly",
1252 codec.pltype, codec.plfreq);
1253 }
1254 }
1255#endif
1256 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001257
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 // Initialize the far end AP module
1259 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1260 // changed at the first receiving audio.
1261 if (_rxAudioProcessingModulePtr == NULL)
1262 {
1263 _engineStatisticsPtr->SetLastError(
1264 VE_NO_MEMORY, kTraceCritical,
1265 "Channel::Init() failed to create the far-end AudioProcessing"
1266 " module");
1267 return -1;
1268 }
1269
niklase@google.com470e71d2011-07-07 08:21:25 +00001270 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1271 {
1272 _engineStatisticsPtr->SetLastError(
1273 VE_APM_ERROR, kTraceWarning,
1274 "Channel::Init() failed to set the sample rate to 8K for"
1275 " far-end AP module");
1276 }
1277
1278 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1279 {
1280 _engineStatisticsPtr->SetLastError(
1281 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001282 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 }
1284
1285 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1286 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1287 {
1288 _engineStatisticsPtr->SetLastError(
1289 VE_APM_ERROR, kTraceWarning,
1290 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001291 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001292 }
1293
1294 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1295 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1296 {
1297 _engineStatisticsPtr->SetLastError(
1298 VE_APM_ERROR, kTraceWarning,
1299 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001300 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 }
1302 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1303 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1304 {
1305 _engineStatisticsPtr->SetLastError(
1306 VE_APM_ERROR, kTraceWarning,
1307 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001308 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 }
1310
1311 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1312 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1313 {
1314 _engineStatisticsPtr->SetLastError(
1315 VE_APM_ERROR, kTraceWarning,
1316 "Init() failed to set AGC mode for far-end AP module");
1317 }
1318 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1319 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1320 {
1321 _engineStatisticsPtr->SetLastError(
1322 VE_APM_ERROR, kTraceWarning,
1323 "Init() failed to set AGC state for far-end AP module");
1324 }
1325
1326 return 0;
1327}
1328
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001329int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001330Channel::SetEngineInformation(Statistics& engineStatistics,
1331 OutputMixer& outputMixer,
1332 voe::TransmitMixer& transmitMixer,
1333 ProcessThread& moduleProcessThread,
1334 AudioDeviceModule& audioDeviceModule,
1335 VoiceEngineObserver* voiceEngineObserver,
1336 CriticalSectionWrapper* callbackCritSect)
1337{
1338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1339 "Channel::SetEngineInformation()");
1340 _engineStatisticsPtr = &engineStatistics;
1341 _outputMixerPtr = &outputMixer;
1342 _transmitMixerPtr = &transmitMixer,
1343 _moduleProcessThreadPtr = &moduleProcessThread;
1344 _audioDeviceModulePtr = &audioDeviceModule;
1345 _voiceEngineObserverPtr = voiceEngineObserver;
1346 _callbackCritSectPtr = callbackCritSect;
1347 return 0;
1348}
1349
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001350int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001351Channel::UpdateLocalTimeStamp()
1352{
1353
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001354 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 return 0;
1356}
1357
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001358int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001359Channel::StartPlayout()
1360{
1361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1362 "Channel::StartPlayout()");
1363 if (_playing)
1364 {
1365 return 0;
1366 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001367
1368 if (!_externalMixing) {
1369 // Add participant as candidates for mixing.
1370 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1371 {
1372 _engineStatisticsPtr->SetLastError(
1373 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1374 "StartPlayout() failed to add participant to mixer");
1375 return -1;
1376 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001377 }
1378
1379 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001380
1381 if (RegisterFilePlayingToMixer() != 0)
1382 return -1;
1383
niklase@google.com470e71d2011-07-07 08:21:25 +00001384 return 0;
1385}
1386
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001387int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001388Channel::StopPlayout()
1389{
1390 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1391 "Channel::StopPlayout()");
1392 if (!_playing)
1393 {
1394 return 0;
1395 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001396
1397 if (!_externalMixing) {
1398 // Remove participant as candidates for mixing
1399 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1400 {
1401 _engineStatisticsPtr->SetLastError(
1402 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1403 "StopPlayout() failed to remove participant from mixer");
1404 return -1;
1405 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 }
1407
1408 _playing = false;
1409 _outputAudioLevel.Clear();
1410
1411 return 0;
1412}
1413
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001414int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001415Channel::StartSend()
1416{
1417 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1418 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001420 // A lock is needed because |_sending| can be accessed or modified by
1421 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001422 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001423
1424 if (_sending)
1425 {
1426 return 0;
1427 }
1428 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001430
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001431 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001432 {
1433 _engineStatisticsPtr->SetLastError(
1434 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1435 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001436 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001437 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001438 return -1;
1439 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001440
niklase@google.com470e71d2011-07-07 08:21:25 +00001441 return 0;
1442}
1443
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001445Channel::StopSend()
1446{
1447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1448 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001450 // A lock is needed because |_sending| can be accessed or modified by
1451 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001452 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001453
1454 if (!_sending)
1455 {
1456 return 0;
1457 }
1458 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001460
niklase@google.com470e71d2011-07-07 08:21:25 +00001461 // Reset sending SSRC and sequence number and triggers direct transmission
1462 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001463 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1464 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 {
1466 _engineStatisticsPtr->SetLastError(
1467 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1468 "StartSend() RTP/RTCP failed to stop sending");
1469 }
1470
niklase@google.com470e71d2011-07-07 08:21:25 +00001471 return 0;
1472}
1473
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001474int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001475Channel::StartReceiving()
1476{
1477 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1478 "Channel::StartReceiving()");
1479 if (_receiving)
1480 {
1481 return 0;
1482 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001483 _receiving = true;
1484 _numberOfDiscardedPackets = 0;
1485 return 0;
1486}
1487
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001488int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001489Channel::StopReceiving()
1490{
1491 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1492 "Channel::StopReceiving()");
1493 if (!_receiving)
1494 {
1495 return 0;
1496 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001497
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001498 // Recover DTMF detection status.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001499 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 RegisterReceiveCodecsToRTPModule();
1501 _receiving = false;
1502 return 0;
1503}
1504
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001505int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001506Channel::SetNetEQPlayoutMode(NetEqModes mode)
1507{
1508 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1509 "Channel::SetNetEQPlayoutMode()");
1510 AudioPlayoutMode playoutMode(voice);
1511 switch (mode)
1512 {
1513 case kNetEqDefault:
1514 playoutMode = voice;
1515 break;
1516 case kNetEqStreaming:
1517 playoutMode = streaming;
1518 break;
1519 case kNetEqFax:
1520 playoutMode = fax;
1521 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001522 case kNetEqOff:
1523 playoutMode = off;
1524 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001525 }
1526 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1527 {
1528 _engineStatisticsPtr->SetLastError(
1529 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1530 "SetNetEQPlayoutMode() failed to set playout mode");
1531 return -1;
1532 }
1533 return 0;
1534}
1535
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001536int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001537Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1538{
1539 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1540 switch (playoutMode)
1541 {
1542 case voice:
1543 mode = kNetEqDefault;
1544 break;
1545 case streaming:
1546 mode = kNetEqStreaming;
1547 break;
1548 case fax:
1549 mode = kNetEqFax;
1550 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001551 case off:
1552 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001553 }
1554 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1555 VoEId(_instanceId,_channelId),
1556 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1557 return 0;
1558}
1559
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001560int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001561Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1562{
1563 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1564 "Channel::SetOnHoldStatus()");
1565 if (mode == kHoldSendAndPlay)
1566 {
1567 _outputIsOnHold = enable;
1568 _inputIsOnHold = enable;
1569 }
1570 else if (mode == kHoldPlayOnly)
1571 {
1572 _outputIsOnHold = enable;
1573 }
1574 if (mode == kHoldSendOnly)
1575 {
1576 _inputIsOnHold = enable;
1577 }
1578 return 0;
1579}
1580
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001581int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001582Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1583{
1584 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1585 "Channel::GetOnHoldStatus()");
1586 enabled = (_outputIsOnHold || _inputIsOnHold);
1587 if (_outputIsOnHold && _inputIsOnHold)
1588 {
1589 mode = kHoldSendAndPlay;
1590 }
1591 else if (_outputIsOnHold && !_inputIsOnHold)
1592 {
1593 mode = kHoldPlayOnly;
1594 }
1595 else if (!_outputIsOnHold && _inputIsOnHold)
1596 {
1597 mode = kHoldSendOnly;
1598 }
1599 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1600 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1601 enabled, mode);
1602 return 0;
1603}
1604
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001605int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001606Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1607{
1608 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1609 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001610 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001611
1612 if (_voiceEngineObserverPtr)
1613 {
1614 _engineStatisticsPtr->SetLastError(
1615 VE_INVALID_OPERATION, kTraceError,
1616 "RegisterVoiceEngineObserver() observer already enabled");
1617 return -1;
1618 }
1619 _voiceEngineObserverPtr = &observer;
1620 return 0;
1621}
1622
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001623int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001624Channel::DeRegisterVoiceEngineObserver()
1625{
1626 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1627 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001628 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001629
1630 if (!_voiceEngineObserverPtr)
1631 {
1632 _engineStatisticsPtr->SetLastError(
1633 VE_INVALID_OPERATION, kTraceWarning,
1634 "DeRegisterVoiceEngineObserver() observer already disabled");
1635 return 0;
1636 }
1637 _voiceEngineObserverPtr = NULL;
1638 return 0;
1639}
1640
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001641int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001642Channel::GetSendCodec(CodecInst& codec)
1643{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001644 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001645}
1646
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001647int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001648Channel::GetRecCodec(CodecInst& codec)
1649{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001650 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001651}
1652
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001653int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001654Channel::SetSendCodec(const CodecInst& codec)
1655{
1656 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1657 "Channel::SetSendCodec()");
1658
1659 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1660 {
1661 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1662 "SetSendCodec() failed to register codec to ACM");
1663 return -1;
1664 }
1665
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001666 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001667 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001668 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1669 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 {
1671 WEBRTC_TRACE(
1672 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1673 "SetSendCodec() failed to register codec to"
1674 " RTP/RTCP module");
1675 return -1;
1676 }
1677 }
1678
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001679 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001680 {
1681 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1682 "SetSendCodec() failed to set audio packet size");
1683 return -1;
1684 }
1685
1686 return 0;
1687}
1688
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001689int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001690Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1691{
1692 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1693 "Channel::SetVADStatus(mode=%d)", mode);
1694 // To disable VAD, DTX must be disabled too
1695 disableDTX = ((enableVAD == false) ? true : disableDTX);
1696 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1697 {
1698 _engineStatisticsPtr->SetLastError(
1699 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1700 "SetVADStatus() failed to set VAD");
1701 return -1;
1702 }
1703 return 0;
1704}
1705
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001706int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001707Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1708{
1709 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1710 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001711 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001712 {
1713 _engineStatisticsPtr->SetLastError(
1714 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1715 "GetVADStatus() failed to get VAD status");
1716 return -1;
1717 }
1718 disabledDTX = !disabledDTX;
1719 return 0;
1720}
1721
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001722int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001723Channel::SetRecPayloadType(const CodecInst& codec)
1724{
1725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726 "Channel::SetRecPayloadType()");
1727
1728 if (_playing)
1729 {
1730 _engineStatisticsPtr->SetLastError(
1731 VE_ALREADY_PLAYING, kTraceError,
1732 "SetRecPayloadType() unable to set PT while playing");
1733 return -1;
1734 }
1735 if (_receiving)
1736 {
1737 _engineStatisticsPtr->SetLastError(
1738 VE_ALREADY_LISTENING, kTraceError,
1739 "SetRecPayloadType() unable to set PT while listening");
1740 return -1;
1741 }
1742
1743 if (codec.pltype == -1)
1744 {
1745 // De-register the selected codec (RTP/RTCP module and ACM)
1746
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001747 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001748 CodecInst rxCodec = codec;
1749
1750 // Get payload type for the given codec
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001751 rtp_payload_registry_->ReceivePayloadType(
1752 rxCodec.plname,
1753 rxCodec.plfreq,
1754 rxCodec.channels,
1755 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1756 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001757 rxCodec.pltype = pltype;
1758
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001759 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001760 {
1761 _engineStatisticsPtr->SetLastError(
1762 VE_RTP_RTCP_MODULE_ERROR,
1763 kTraceError,
1764 "SetRecPayloadType() RTP/RTCP-module deregistration "
1765 "failed");
1766 return -1;
1767 }
1768 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1769 {
1770 _engineStatisticsPtr->SetLastError(
1771 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1772 "SetRecPayloadType() ACM deregistration failed - 1");
1773 return -1;
1774 }
1775 return 0;
1776 }
1777
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001778 if (rtp_receiver_->RegisterReceivePayload(
1779 codec.plname,
1780 codec.pltype,
1781 codec.plfreq,
1782 codec.channels,
1783 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001784 {
1785 // First attempt to register failed => de-register and try again
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001786 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1787 if (rtp_receiver_->RegisterReceivePayload(
1788 codec.plname,
1789 codec.pltype,
1790 codec.plfreq,
1791 codec.channels,
1792 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001793 {
1794 _engineStatisticsPtr->SetLastError(
1795 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1796 "SetRecPayloadType() RTP/RTCP-module registration failed");
1797 return -1;
1798 }
1799 }
1800 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1801 {
1802 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1803 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1804 {
1805 _engineStatisticsPtr->SetLastError(
1806 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1807 "SetRecPayloadType() ACM registration failed - 1");
1808 return -1;
1809 }
1810 }
1811 return 0;
1812}
1813
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001814int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001815Channel::GetRecPayloadType(CodecInst& codec)
1816{
1817 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1818 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001819 int8_t payloadType(-1);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001820 if (rtp_payload_registry_->ReceivePayloadType(
1821 codec.plname,
1822 codec.plfreq,
1823 codec.channels,
1824 (codec.rate < 0) ? 0 : codec.rate,
1825 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001826 {
1827 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001828 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001829 "GetRecPayloadType() failed to retrieve RX payload type");
1830 return -1;
1831 }
1832 codec.pltype = payloadType;
1833 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1834 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1835 return 0;
1836}
1837
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001838int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001839Channel::SetAMREncFormat(AmrMode mode)
1840{
1841 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1842 "Channel::SetAMREncFormat()");
1843
1844 // ACM doesn't support AMR
1845 return -1;
1846}
1847
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001849Channel::SetAMRDecFormat(AmrMode mode)
1850{
1851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1852 "Channel::SetAMRDecFormat()");
1853
1854 // ACM doesn't support AMR
1855 return -1;
1856}
1857
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001858int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001859Channel::SetAMRWbEncFormat(AmrMode mode)
1860{
1861 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1862 "Channel::SetAMRWbEncFormat()");
1863
1864 // ACM doesn't support AMR
1865 return -1;
1866
1867}
1868
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001869int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001870Channel::SetAMRWbDecFormat(AmrMode mode)
1871{
1872 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1873 "Channel::SetAMRWbDecFormat()");
1874
1875 // ACM doesn't support AMR
1876 return -1;
1877}
1878
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001879int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001880Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1881{
1882 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1883 "Channel::SetSendCNPayloadType()");
1884
1885 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001886 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001887 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001888 if (frequency == kFreq32000Hz)
1889 samplingFreqHz = 32000;
1890 else if (frequency == kFreq16000Hz)
1891 samplingFreqHz = 16000;
1892
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001893 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001894 {
1895 _engineStatisticsPtr->SetLastError(
1896 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1897 "SetSendCNPayloadType() failed to retrieve default CN codec "
1898 "settings");
1899 return -1;
1900 }
1901
1902 // Modify the payload type (must be set to dynamic range)
1903 codec.pltype = type;
1904
1905 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1906 {
1907 _engineStatisticsPtr->SetLastError(
1908 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1909 "SetSendCNPayloadType() failed to register CN to ACM");
1910 return -1;
1911 }
1912
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001913 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001914 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001915 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1916 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1920 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1921 "module");
1922 return -1;
1923 }
1924 }
1925 return 0;
1926}
1927
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001928int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001929Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1930{
1931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1932 "Channel::SetISACInitTargetRate()");
1933
1934 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001935 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001936 {
1937 _engineStatisticsPtr->SetLastError(
1938 VE_CODEC_ERROR, kTraceError,
1939 "SetISACInitTargetRate() failed to retrieve send codec");
1940 return -1;
1941 }
1942 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1943 {
1944 // This API is only valid if iSAC is setup to run in channel-adaptive
1945 // mode.
1946 // We do not validate the adaptive mode here. It is done later in the
1947 // ConfigISACBandwidthEstimator() API.
1948 _engineStatisticsPtr->SetLastError(
1949 VE_CODEC_ERROR, kTraceError,
1950 "SetISACInitTargetRate() send codec is not iSAC");
1951 return -1;
1952 }
1953
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001954 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001955 if (16000 == sendCodec.plfreq)
1956 {
1957 // Note that 0 is a valid and corresponds to "use default
1958 if ((rateBps != 0 &&
1959 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1960 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1961 {
1962 _engineStatisticsPtr->SetLastError(
1963 VE_INVALID_ARGUMENT, kTraceError,
1964 "SetISACInitTargetRate() invalid target rate - 1");
1965 return -1;
1966 }
1967 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001968 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001969 }
1970 else if (32000 == sendCodec.plfreq)
1971 {
1972 if ((rateBps != 0 &&
1973 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1974 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1975 {
1976 _engineStatisticsPtr->SetLastError(
1977 VE_INVALID_ARGUMENT, kTraceError,
1978 "SetISACInitTargetRate() invalid target rate - 2");
1979 return -1;
1980 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001981 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001982 }
1983
1984 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1985 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1986 {
1987 _engineStatisticsPtr->SetLastError(
1988 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1989 "SetISACInitTargetRate() iSAC BWE config failed");
1990 return -1;
1991 }
1992
1993 return 0;
1994}
1995
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001996int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001997Channel::SetISACMaxRate(int rateBps)
1998{
1999 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2000 "Channel::SetISACMaxRate()");
2001
2002 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002003 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002004 {
2005 _engineStatisticsPtr->SetLastError(
2006 VE_CODEC_ERROR, kTraceError,
2007 "SetISACMaxRate() failed to retrieve send codec");
2008 return -1;
2009 }
2010 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2011 {
2012 // This API is only valid if iSAC is selected as sending codec.
2013 _engineStatisticsPtr->SetLastError(
2014 VE_CODEC_ERROR, kTraceError,
2015 "SetISACMaxRate() send codec is not iSAC");
2016 return -1;
2017 }
2018 if (16000 == sendCodec.plfreq)
2019 {
2020 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2021 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2022 {
2023 _engineStatisticsPtr->SetLastError(
2024 VE_INVALID_ARGUMENT, kTraceError,
2025 "SetISACMaxRate() invalid max rate - 1");
2026 return -1;
2027 }
2028 }
2029 else if (32000 == sendCodec.plfreq)
2030 {
2031 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2032 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2033 {
2034 _engineStatisticsPtr->SetLastError(
2035 VE_INVALID_ARGUMENT, kTraceError,
2036 "SetISACMaxRate() invalid max rate - 2");
2037 return -1;
2038 }
2039 }
2040 if (_sending)
2041 {
2042 _engineStatisticsPtr->SetLastError(
2043 VE_SENDING, kTraceError,
2044 "SetISACMaxRate() unable to set max rate while sending");
2045 return -1;
2046 }
2047
2048 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2049 // and non-adaptive mode)
2050 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2051 {
2052 _engineStatisticsPtr->SetLastError(
2053 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2054 "SetISACMaxRate() failed to set max rate");
2055 return -1;
2056 }
2057
2058 return 0;
2059}
2060
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002061int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002062Channel::SetISACMaxPayloadSize(int sizeBytes)
2063{
2064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2065 "Channel::SetISACMaxPayloadSize()");
2066 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002067 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002068 {
2069 _engineStatisticsPtr->SetLastError(
2070 VE_CODEC_ERROR, kTraceError,
2071 "SetISACMaxPayloadSize() failed to retrieve send codec");
2072 return -1;
2073 }
2074 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2075 {
2076 _engineStatisticsPtr->SetLastError(
2077 VE_CODEC_ERROR, kTraceError,
2078 "SetISACMaxPayloadSize() send codec is not iSAC");
2079 return -1;
2080 }
2081 if (16000 == sendCodec.plfreq)
2082 {
2083 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2084 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2085 {
2086 _engineStatisticsPtr->SetLastError(
2087 VE_INVALID_ARGUMENT, kTraceError,
2088 "SetISACMaxPayloadSize() invalid max payload - 1");
2089 return -1;
2090 }
2091 }
2092 else if (32000 == sendCodec.plfreq)
2093 {
2094 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2095 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2096 {
2097 _engineStatisticsPtr->SetLastError(
2098 VE_INVALID_ARGUMENT, kTraceError,
2099 "SetISACMaxPayloadSize() invalid max payload - 2");
2100 return -1;
2101 }
2102 }
2103 if (_sending)
2104 {
2105 _engineStatisticsPtr->SetLastError(
2106 VE_SENDING, kTraceError,
2107 "SetISACMaxPayloadSize() unable to set max rate while sending");
2108 return -1;
2109 }
2110
2111 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2112 {
2113 _engineStatisticsPtr->SetLastError(
2114 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2115 "SetISACMaxPayloadSize() failed to set max payload size");
2116 return -1;
2117 }
2118 return 0;
2119}
2120
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002121int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002122{
2123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2124 "Channel::RegisterExternalTransport()");
2125
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002126 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002127
niklase@google.com470e71d2011-07-07 08:21:25 +00002128 if (_externalTransport)
2129 {
2130 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2131 kTraceError,
2132 "RegisterExternalTransport() external transport already enabled");
2133 return -1;
2134 }
2135 _externalTransport = true;
2136 _transportPtr = &transport;
2137 return 0;
2138}
2139
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002140int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002141Channel::DeRegisterExternalTransport()
2142{
2143 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2144 "Channel::DeRegisterExternalTransport()");
2145
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002146 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002147
niklase@google.com470e71d2011-07-07 08:21:25 +00002148 if (!_transportPtr)
2149 {
2150 _engineStatisticsPtr->SetLastError(
2151 VE_INVALID_OPERATION, kTraceWarning,
2152 "DeRegisterExternalTransport() external transport already "
2153 "disabled");
2154 return 0;
2155 }
2156 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002157 _transportPtr = NULL;
2158 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2159 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002160 return 0;
2161}
2162
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002163int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002164 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2165 "Channel::ReceivedRTPPacket()");
2166
2167 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002168 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002169
2170 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002171 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2172 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002173 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2174 VoEId(_instanceId,_channelId),
2175 "Channel::SendPacket() RTP dump to input file failed");
2176 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002177 RTPHeader header;
2178 if (!rtp_header_parser_->Parse(reinterpret_cast<const uint8_t*>(data),
2179 static_cast<uint16_t>(length), &header)) {
2180 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo,
2181 VoEId(_instanceId,_channelId),
2182 "IncomingPacket invalid RTP header");
2183 return -1;
2184 }
pbos@webrtc.org08933a52013-07-10 10:06:29 +00002185 header.payload_type_frequency =
2186 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002187 bool retransmitted = IsPacketRetransmitted(header);
2188 bool in_order = rtp_receiver_->InOrderPacket(header.sequenceNumber);
2189 rtp_receive_statistics_->IncomingPacket(header, static_cast<uint16_t>(length),
2190 retransmitted, in_order);
2191 PayloadUnion payload_specific;
2192 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
2193 &payload_specific)) {
2194 return -1;
2195 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002196 // Deliver RTP packet to RTP/RTCP module for parsing
2197 // The packet will be pushed back to the channel thru the
2198 // OnReceivedPayloadData callback so we don't push it to the ACM here
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002199 if (!rtp_receiver_->IncomingRtpPacket(&header,
2200 reinterpret_cast<const uint8_t*>(data),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002201 static_cast<uint16_t>(length),
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002202 payload_specific, in_order)) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002203 _engineStatisticsPtr->SetLastError(
2204 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2205 "Channel::IncomingRTPPacket() RTP packet is invalid");
2206 }
2207 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002208}
2209
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002210bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
2211 bool rtx_enabled = false;
2212 uint32_t rtx_ssrc = 0;
2213 int rtx_payload_type = 0;
2214 rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type);
2215 if (!rtx_enabled) {
2216 // Check if this is a retransmission.
elham@webrtc.orgb7eda432013-07-15 21:08:27 +00002217 ReceiveStatistics::RtpReceiveStatistics stats;
2218 if (rtp_receive_statistics_->Statistics(&stats, false)) {
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002219 uint16_t min_rtt = 0;
2220 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
2221 return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter,
2222 min_rtt);
2223 }
2224 }
2225 return false;
2226}
2227
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002228int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002229 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2230 "Channel::ReceivedRTCPPacket()");
2231 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002232 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002233
2234 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002235 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2236 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002237 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2238 VoEId(_instanceId,_channelId),
2239 "Channel::SendPacket() RTCP dump to input file failed");
2240 }
2241
2242 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002243 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2244 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002245 _engineStatisticsPtr->SetLastError(
2246 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2247 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2248 }
2249 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002250}
2251
niklase@google.com470e71d2011-07-07 08:21:25 +00002252int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002253 bool loop,
2254 FileFormats format,
2255 int startPosition,
2256 float volumeScaling,
2257 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002258 const CodecInst* codecInst)
2259{
2260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2261 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2262 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2263 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2264 startPosition, stopPosition);
2265
2266 if (_outputFilePlaying)
2267 {
2268 _engineStatisticsPtr->SetLastError(
2269 VE_ALREADY_PLAYING, kTraceError,
2270 "StartPlayingFileLocally() is already playing");
2271 return -1;
2272 }
2273
niklase@google.com470e71d2011-07-07 08:21:25 +00002274 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002275 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002276
2277 if (_outputFilePlayerPtr)
2278 {
2279 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2280 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2281 _outputFilePlayerPtr = NULL;
2282 }
2283
2284 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2285 _outputFilePlayerId, (const FileFormats)format);
2286
2287 if (_outputFilePlayerPtr == NULL)
2288 {
2289 _engineStatisticsPtr->SetLastError(
2290 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002291 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002292 return -1;
2293 }
2294
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002295 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002296
2297 if (_outputFilePlayerPtr->StartPlayingFile(
2298 fileName,
2299 loop,
2300 startPosition,
2301 volumeScaling,
2302 notificationTime,
2303 stopPosition,
2304 (const CodecInst*)codecInst) != 0)
2305 {
2306 _engineStatisticsPtr->SetLastError(
2307 VE_BAD_FILE, kTraceError,
2308 "StartPlayingFile() failed to start file playout");
2309 _outputFilePlayerPtr->StopPlayingFile();
2310 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2311 _outputFilePlayerPtr = NULL;
2312 return -1;
2313 }
2314 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2315 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002316 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002317
2318 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002319 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002320
2321 return 0;
2322}
2323
2324int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002325 FileFormats format,
2326 int startPosition,
2327 float volumeScaling,
2328 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002329 const CodecInst* codecInst)
2330{
2331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2332 "Channel::StartPlayingFileLocally(format=%d,"
2333 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2334 format, volumeScaling, startPosition, stopPosition);
2335
2336 if(stream == NULL)
2337 {
2338 _engineStatisticsPtr->SetLastError(
2339 VE_BAD_FILE, kTraceError,
2340 "StartPlayingFileLocally() NULL as input stream");
2341 return -1;
2342 }
2343
2344
2345 if (_outputFilePlaying)
2346 {
2347 _engineStatisticsPtr->SetLastError(
2348 VE_ALREADY_PLAYING, kTraceError,
2349 "StartPlayingFileLocally() is already playing");
2350 return -1;
2351 }
2352
niklase@google.com470e71d2011-07-07 08:21:25 +00002353 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002354 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002355
2356 // Destroy the old instance
2357 if (_outputFilePlayerPtr)
2358 {
2359 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2360 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2361 _outputFilePlayerPtr = NULL;
2362 }
2363
2364 // Create the instance
2365 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2366 _outputFilePlayerId,
2367 (const FileFormats)format);
2368
2369 if (_outputFilePlayerPtr == NULL)
2370 {
2371 _engineStatisticsPtr->SetLastError(
2372 VE_INVALID_ARGUMENT, kTraceError,
2373 "StartPlayingFileLocally() filePlayer format isnot correct");
2374 return -1;
2375 }
2376
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002377 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002378
2379 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2380 volumeScaling,
2381 notificationTime,
2382 stopPosition, codecInst) != 0)
2383 {
2384 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2385 "StartPlayingFile() failed to "
2386 "start file playout");
2387 _outputFilePlayerPtr->StopPlayingFile();
2388 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2389 _outputFilePlayerPtr = NULL;
2390 return -1;
2391 }
2392 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2393 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002394 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002395
2396 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002397 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002398
niklase@google.com470e71d2011-07-07 08:21:25 +00002399 return 0;
2400}
2401
2402int Channel::StopPlayingFileLocally()
2403{
2404 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2405 "Channel::StopPlayingFileLocally()");
2406
2407 if (!_outputFilePlaying)
2408 {
2409 _engineStatisticsPtr->SetLastError(
2410 VE_INVALID_OPERATION, kTraceWarning,
2411 "StopPlayingFileLocally() isnot playing");
2412 return 0;
2413 }
2414
niklase@google.com470e71d2011-07-07 08:21:25 +00002415 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002416 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002417
2418 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2419 {
2420 _engineStatisticsPtr->SetLastError(
2421 VE_STOP_RECORDING_FAILED, kTraceError,
2422 "StopPlayingFile() could not stop playing");
2423 return -1;
2424 }
2425 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2426 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2427 _outputFilePlayerPtr = NULL;
2428 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002429 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002430 // _fileCritSect cannot be taken while calling
2431 // SetAnonymousMixibilityStatus. Refer to comments in
2432 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002433 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2434 {
2435 _engineStatisticsPtr->SetLastError(
2436 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002437 "StopPlayingFile() failed to stop participant from playing as"
2438 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002439 return -1;
2440 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002441
2442 return 0;
2443}
2444
2445int Channel::IsPlayingFileLocally() const
2446{
2447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2448 "Channel::IsPlayingFileLocally()");
2449
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002450 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002451}
2452
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002453int Channel::RegisterFilePlayingToMixer()
2454{
2455 // Return success for not registering for file playing to mixer if:
2456 // 1. playing file before playout is started on that channel.
2457 // 2. starting playout without file playing on that channel.
2458 if (!_playing || !_outputFilePlaying)
2459 {
2460 return 0;
2461 }
2462
2463 // |_fileCritSect| cannot be taken while calling
2464 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2465 // frames can be pulled by the mixer. Since the frames are generated from
2466 // the file, _fileCritSect will be taken. This would result in a deadlock.
2467 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2468 {
2469 CriticalSectionScoped cs(&_fileCritSect);
2470 _outputFilePlaying = false;
2471 _engineStatisticsPtr->SetLastError(
2472 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2473 "StartPlayingFile() failed to add participant as file to mixer");
2474 _outputFilePlayerPtr->StopPlayingFile();
2475 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2476 _outputFilePlayerPtr = NULL;
2477 return -1;
2478 }
2479
2480 return 0;
2481}
2482
pbos@webrtc.org92135212013-05-14 08:31:39 +00002483int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002484{
2485 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2486 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2487
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002488 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002489
2490 if (!_outputFilePlaying)
2491 {
2492 _engineStatisticsPtr->SetLastError(
2493 VE_INVALID_OPERATION, kTraceError,
2494 "ScaleLocalFilePlayout() isnot playing");
2495 return -1;
2496 }
2497 if ((_outputFilePlayerPtr == NULL) ||
2498 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2499 {
2500 _engineStatisticsPtr->SetLastError(
2501 VE_BAD_ARGUMENT, kTraceError,
2502 "SetAudioScaling() failed to scale the playout");
2503 return -1;
2504 }
2505
2506 return 0;
2507}
2508
2509int Channel::GetLocalPlayoutPosition(int& positionMs)
2510{
2511 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2512 "Channel::GetLocalPlayoutPosition(position=?)");
2513
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002514 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002515
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002516 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002517
2518 if (_outputFilePlayerPtr == NULL)
2519 {
2520 _engineStatisticsPtr->SetLastError(
2521 VE_INVALID_OPERATION, kTraceError,
2522 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2523 return -1;
2524 }
2525
2526 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2527 {
2528 _engineStatisticsPtr->SetLastError(
2529 VE_BAD_FILE, kTraceError,
2530 "GetLocalPlayoutPosition() failed");
2531 return -1;
2532 }
2533 positionMs = position;
2534
2535 return 0;
2536}
2537
2538int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002539 bool loop,
2540 FileFormats format,
2541 int startPosition,
2542 float volumeScaling,
2543 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002544 const CodecInst* codecInst)
2545{
2546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2547 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2548 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2549 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2550 startPosition, stopPosition);
2551
2552 if (_inputFilePlaying)
2553 {
2554 _engineStatisticsPtr->SetLastError(
2555 VE_ALREADY_PLAYING, kTraceWarning,
2556 "StartPlayingFileAsMicrophone() filePlayer is playing");
2557 return 0;
2558 }
2559
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002560 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002561
2562 // Destroy the old instance
2563 if (_inputFilePlayerPtr)
2564 {
2565 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2566 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2567 _inputFilePlayerPtr = NULL;
2568 }
2569
2570 // Create the instance
2571 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2572 _inputFilePlayerId, (const FileFormats)format);
2573
2574 if (_inputFilePlayerPtr == NULL)
2575 {
2576 _engineStatisticsPtr->SetLastError(
2577 VE_INVALID_ARGUMENT, kTraceError,
2578 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2579 return -1;
2580 }
2581
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002582 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002583
2584 if (_inputFilePlayerPtr->StartPlayingFile(
2585 fileName,
2586 loop,
2587 startPosition,
2588 volumeScaling,
2589 notificationTime,
2590 stopPosition,
2591 (const CodecInst*)codecInst) != 0)
2592 {
2593 _engineStatisticsPtr->SetLastError(
2594 VE_BAD_FILE, kTraceError,
2595 "StartPlayingFile() failed to start file playout");
2596 _inputFilePlayerPtr->StopPlayingFile();
2597 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2598 _inputFilePlayerPtr = NULL;
2599 return -1;
2600 }
2601 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2602 _inputFilePlaying = true;
2603
2604 return 0;
2605}
2606
2607int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002608 FileFormats format,
2609 int startPosition,
2610 float volumeScaling,
2611 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002612 const CodecInst* codecInst)
2613{
2614 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2615 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2616 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2617 format, volumeScaling, startPosition, stopPosition);
2618
2619 if(stream == NULL)
2620 {
2621 _engineStatisticsPtr->SetLastError(
2622 VE_BAD_FILE, kTraceError,
2623 "StartPlayingFileAsMicrophone NULL as input stream");
2624 return -1;
2625 }
2626
2627 if (_inputFilePlaying)
2628 {
2629 _engineStatisticsPtr->SetLastError(
2630 VE_ALREADY_PLAYING, kTraceWarning,
2631 "StartPlayingFileAsMicrophone() is playing");
2632 return 0;
2633 }
2634
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002635 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002636
2637 // Destroy the old instance
2638 if (_inputFilePlayerPtr)
2639 {
2640 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2641 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2642 _inputFilePlayerPtr = NULL;
2643 }
2644
2645 // Create the instance
2646 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2647 _inputFilePlayerId, (const FileFormats)format);
2648
2649 if (_inputFilePlayerPtr == NULL)
2650 {
2651 _engineStatisticsPtr->SetLastError(
2652 VE_INVALID_ARGUMENT, kTraceError,
2653 "StartPlayingInputFile() filePlayer format isnot correct");
2654 return -1;
2655 }
2656
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002657 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002658
2659 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2660 volumeScaling, notificationTime,
2661 stopPosition, codecInst) != 0)
2662 {
2663 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2664 "StartPlayingFile() failed to start "
2665 "file playout");
2666 _inputFilePlayerPtr->StopPlayingFile();
2667 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2668 _inputFilePlayerPtr = NULL;
2669 return -1;
2670 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002671
niklase@google.com470e71d2011-07-07 08:21:25 +00002672 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2673 _inputFilePlaying = true;
2674
2675 return 0;
2676}
2677
2678int Channel::StopPlayingFileAsMicrophone()
2679{
2680 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2681 "Channel::StopPlayingFileAsMicrophone()");
2682
2683 if (!_inputFilePlaying)
2684 {
2685 _engineStatisticsPtr->SetLastError(
2686 VE_INVALID_OPERATION, kTraceWarning,
2687 "StopPlayingFileAsMicrophone() isnot playing");
2688 return 0;
2689 }
2690
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002691 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002692 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2693 {
2694 _engineStatisticsPtr->SetLastError(
2695 VE_STOP_RECORDING_FAILED, kTraceError,
2696 "StopPlayingFile() could not stop playing");
2697 return -1;
2698 }
2699 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2700 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2701 _inputFilePlayerPtr = NULL;
2702 _inputFilePlaying = false;
2703
2704 return 0;
2705}
2706
2707int Channel::IsPlayingFileAsMicrophone() const
2708{
2709 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2710 "Channel::IsPlayingFileAsMicrophone()");
2711
2712 return _inputFilePlaying;
2713}
2714
pbos@webrtc.org92135212013-05-14 08:31:39 +00002715int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002716{
2717 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2718 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2719
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002720 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002721
2722 if (!_inputFilePlaying)
2723 {
2724 _engineStatisticsPtr->SetLastError(
2725 VE_INVALID_OPERATION, kTraceError,
2726 "ScaleFileAsMicrophonePlayout() isnot playing");
2727 return -1;
2728 }
2729
2730 if ((_inputFilePlayerPtr == NULL) ||
2731 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2732 {
2733 _engineStatisticsPtr->SetLastError(
2734 VE_BAD_ARGUMENT, kTraceError,
2735 "SetAudioScaling() failed to scale playout");
2736 return -1;
2737 }
2738
2739 return 0;
2740}
2741
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002742int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002743 const CodecInst* codecInst)
2744{
2745 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2746 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2747
2748 if (_outputFileRecording)
2749 {
2750 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2751 "StartRecordingPlayout() is already recording");
2752 return 0;
2753 }
2754
2755 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002756 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002757 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2758
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002759 if ((codecInst != NULL) &&
2760 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 {
2762 _engineStatisticsPtr->SetLastError(
2763 VE_BAD_ARGUMENT, kTraceError,
2764 "StartRecordingPlayout() invalid compression");
2765 return(-1);
2766 }
2767 if(codecInst == NULL)
2768 {
2769 format = kFileFormatPcm16kHzFile;
2770 codecInst=&dummyCodec;
2771 }
2772 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2773 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2774 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2775 {
2776 format = kFileFormatWavFile;
2777 }
2778 else
2779 {
2780 format = kFileFormatCompressedFile;
2781 }
2782
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002783 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002784
2785 // Destroy the old instance
2786 if (_outputFileRecorderPtr)
2787 {
2788 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2789 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2790 _outputFileRecorderPtr = NULL;
2791 }
2792
2793 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2794 _outputFileRecorderId, (const FileFormats)format);
2795 if (_outputFileRecorderPtr == NULL)
2796 {
2797 _engineStatisticsPtr->SetLastError(
2798 VE_INVALID_ARGUMENT, kTraceError,
2799 "StartRecordingPlayout() fileRecorder format isnot correct");
2800 return -1;
2801 }
2802
2803 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2804 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2805 {
2806 _engineStatisticsPtr->SetLastError(
2807 VE_BAD_FILE, kTraceError,
2808 "StartRecordingAudioFile() failed to start file recording");
2809 _outputFileRecorderPtr->StopRecording();
2810 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2811 _outputFileRecorderPtr = NULL;
2812 return -1;
2813 }
2814 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2815 _outputFileRecording = true;
2816
2817 return 0;
2818}
2819
2820int Channel::StartRecordingPlayout(OutStream* stream,
2821 const CodecInst* codecInst)
2822{
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2824 "Channel::StartRecordingPlayout()");
2825
2826 if (_outputFileRecording)
2827 {
2828 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2829 "StartRecordingPlayout() is already recording");
2830 return 0;
2831 }
2832
2833 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002834 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002835 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2836
2837 if (codecInst != NULL && codecInst->channels != 1)
2838 {
2839 _engineStatisticsPtr->SetLastError(
2840 VE_BAD_ARGUMENT, kTraceError,
2841 "StartRecordingPlayout() invalid compression");
2842 return(-1);
2843 }
2844 if(codecInst == NULL)
2845 {
2846 format = kFileFormatPcm16kHzFile;
2847 codecInst=&dummyCodec;
2848 }
2849 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2850 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2851 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2852 {
2853 format = kFileFormatWavFile;
2854 }
2855 else
2856 {
2857 format = kFileFormatCompressedFile;
2858 }
2859
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002860 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002861
2862 // Destroy the old instance
2863 if (_outputFileRecorderPtr)
2864 {
2865 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2866 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2867 _outputFileRecorderPtr = NULL;
2868 }
2869
2870 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2871 _outputFileRecorderId, (const FileFormats)format);
2872 if (_outputFileRecorderPtr == NULL)
2873 {
2874 _engineStatisticsPtr->SetLastError(
2875 VE_INVALID_ARGUMENT, kTraceError,
2876 "StartRecordingPlayout() fileRecorder format isnot correct");
2877 return -1;
2878 }
2879
2880 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2881 notificationTime) != 0)
2882 {
2883 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2884 "StartRecordingPlayout() failed to "
2885 "start file recording");
2886 _outputFileRecorderPtr->StopRecording();
2887 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2888 _outputFileRecorderPtr = NULL;
2889 return -1;
2890 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002891
niklase@google.com470e71d2011-07-07 08:21:25 +00002892 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2893 _outputFileRecording = true;
2894
2895 return 0;
2896}
2897
2898int Channel::StopRecordingPlayout()
2899{
2900 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2901 "Channel::StopRecordingPlayout()");
2902
2903 if (!_outputFileRecording)
2904 {
2905 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2906 "StopRecordingPlayout() isnot recording");
2907 return -1;
2908 }
2909
2910
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002911 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002912
2913 if (_outputFileRecorderPtr->StopRecording() != 0)
2914 {
2915 _engineStatisticsPtr->SetLastError(
2916 VE_STOP_RECORDING_FAILED, kTraceError,
2917 "StopRecording() could not stop recording");
2918 return(-1);
2919 }
2920 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2921 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2922 _outputFileRecorderPtr = NULL;
2923 _outputFileRecording = false;
2924
2925 return 0;
2926}
2927
2928void
2929Channel::SetMixWithMicStatus(bool mix)
2930{
2931 _mixFileWithMicrophone=mix;
2932}
2933
2934int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002935Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002936{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002937 int8_t currentLevel = _outputAudioLevel.Level();
2938 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002939 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2940 VoEId(_instanceId,_channelId),
2941 "GetSpeechOutputLevel() => level=%u", level);
2942 return 0;
2943}
2944
2945int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002946Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002947{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002948 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2949 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002950 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2951 VoEId(_instanceId,_channelId),
2952 "GetSpeechOutputLevelFullRange() => level=%u", level);
2953 return 0;
2954}
2955
2956int
2957Channel::SetMute(bool enable)
2958{
2959 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2960 "Channel::SetMute(enable=%d)", enable);
2961 _mute = enable;
2962 return 0;
2963}
2964
2965bool
2966Channel::Mute() const
2967{
2968 return _mute;
2969}
2970
2971int
2972Channel::SetOutputVolumePan(float left, float right)
2973{
2974 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2975 "Channel::SetOutputVolumePan()");
2976 _panLeft = left;
2977 _panRight = right;
2978 return 0;
2979}
2980
2981int
2982Channel::GetOutputVolumePan(float& left, float& right) const
2983{
2984 left = _panLeft;
2985 right = _panRight;
2986 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2987 VoEId(_instanceId,_channelId),
2988 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2989 return 0;
2990}
2991
2992int
2993Channel::SetChannelOutputVolumeScaling(float scaling)
2994{
2995 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2996 "Channel::SetChannelOutputVolumeScaling()");
2997 _outputGain = scaling;
2998 return 0;
2999}
3000
3001int
3002Channel::GetChannelOutputVolumeScaling(float& scaling) const
3003{
3004 scaling = _outputGain;
3005 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3006 VoEId(_instanceId,_channelId),
3007 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3008 return 0;
3009}
3010
niklase@google.com470e71d2011-07-07 08:21:25 +00003011int
3012Channel::RegisterExternalEncryption(Encryption& encryption)
3013{
3014 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3015 "Channel::RegisterExternalEncryption()");
3016
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003017 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003018
3019 if (_encryptionPtr)
3020 {
3021 _engineStatisticsPtr->SetLastError(
3022 VE_INVALID_OPERATION, kTraceError,
3023 "RegisterExternalEncryption() encryption already enabled");
3024 return -1;
3025 }
3026
3027 _encryptionPtr = &encryption;
3028
3029 _decrypting = true;
3030 _encrypting = true;
3031
3032 return 0;
3033}
3034
3035int
3036Channel::DeRegisterExternalEncryption()
3037{
3038 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3039 "Channel::DeRegisterExternalEncryption()");
3040
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003041 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003042
3043 if (!_encryptionPtr)
3044 {
3045 _engineStatisticsPtr->SetLastError(
3046 VE_INVALID_OPERATION, kTraceWarning,
3047 "DeRegisterExternalEncryption() encryption already disabled");
3048 return 0;
3049 }
3050
3051 _decrypting = false;
3052 _encrypting = false;
3053
3054 _encryptionPtr = NULL;
3055
3056 return 0;
3057}
3058
3059int Channel::SendTelephoneEventOutband(unsigned char eventCode,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003060 int lengthMs, int attenuationDb,
3061 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003062{
3063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3064 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3065 playDtmfEvent);
3066
3067 _playOutbandDtmfEvent = playDtmfEvent;
3068
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003069 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003070 attenuationDb) != 0)
3071 {
3072 _engineStatisticsPtr->SetLastError(
3073 VE_SEND_DTMF_FAILED,
3074 kTraceWarning,
3075 "SendTelephoneEventOutband() failed to send event");
3076 return -1;
3077 }
3078 return 0;
3079}
3080
3081int Channel::SendTelephoneEventInband(unsigned char eventCode,
3082 int lengthMs,
3083 int attenuationDb,
3084 bool playDtmfEvent)
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3087 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3088 playDtmfEvent);
3089
3090 _playInbandDtmfEvent = playDtmfEvent;
3091 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3092
3093 return 0;
3094}
3095
3096int
3097Channel::SetDtmfPlayoutStatus(bool enable)
3098{
3099 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3100 "Channel::SetDtmfPlayoutStatus()");
3101 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3102 {
3103 _engineStatisticsPtr->SetLastError(
3104 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3105 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3106 return -1;
3107 }
3108 return 0;
3109}
3110
3111bool
3112Channel::DtmfPlayoutStatus() const
3113{
3114 return _audioCodingModule.DtmfPlayoutStatus();
3115}
3116
3117int
3118Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3119{
3120 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3121 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003122 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003123 {
3124 _engineStatisticsPtr->SetLastError(
3125 VE_INVALID_ARGUMENT, kTraceError,
3126 "SetSendTelephoneEventPayloadType() invalid type");
3127 return -1;
3128 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003129 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003130 codec.plfreq = 8000;
3131 codec.pltype = type;
3132 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003133 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003134 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003135 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3136 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3137 _engineStatisticsPtr->SetLastError(
3138 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3139 "SetSendTelephoneEventPayloadType() failed to register send"
3140 "payload type");
3141 return -1;
3142 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003143 }
3144 _sendTelephoneEventPayloadType = type;
3145 return 0;
3146}
3147
3148int
3149Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3150{
3151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3152 "Channel::GetSendTelephoneEventPayloadType()");
3153 type = _sendTelephoneEventPayloadType;
3154 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3155 VoEId(_instanceId,_channelId),
3156 "GetSendTelephoneEventPayloadType() => type=%u", type);
3157 return 0;
3158}
3159
niklase@google.com470e71d2011-07-07 08:21:25 +00003160int
3161Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3162{
3163 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3164 "Channel::UpdateRxVadDetection()");
3165
3166 int vadDecision = 1;
3167
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003168 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003169
3170 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3171 {
3172 OnRxVadDetected(vadDecision);
3173 _oldVadDecision = vadDecision;
3174 }
3175
3176 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3177 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3178 vadDecision);
3179 return 0;
3180}
3181
3182int
3183Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3184{
3185 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3186 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003187 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003188
3189 if (_rxVadObserverPtr)
3190 {
3191 _engineStatisticsPtr->SetLastError(
3192 VE_INVALID_OPERATION, kTraceError,
3193 "RegisterRxVadObserver() observer already enabled");
3194 return -1;
3195 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003196 _rxVadObserverPtr = &observer;
3197 _RxVadDetection = true;
3198 return 0;
3199}
3200
3201int
3202Channel::DeRegisterRxVadObserver()
3203{
3204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3205 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003206 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003207
3208 if (!_rxVadObserverPtr)
3209 {
3210 _engineStatisticsPtr->SetLastError(
3211 VE_INVALID_OPERATION, kTraceWarning,
3212 "DeRegisterRxVadObserver() observer already disabled");
3213 return 0;
3214 }
3215 _rxVadObserverPtr = NULL;
3216 _RxVadDetection = false;
3217 return 0;
3218}
3219
3220int
3221Channel::VoiceActivityIndicator(int &activity)
3222{
3223 activity = _sendFrameType;
3224
3225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3226 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3227 return 0;
3228}
3229
3230#ifdef WEBRTC_VOICE_ENGINE_AGC
3231
3232int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003233Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003234{
3235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3236 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3237 (int)enable, (int)mode);
3238
3239 GainControl::Mode agcMode(GainControl::kFixedDigital);
3240 switch (mode)
3241 {
3242 case kAgcDefault:
3243 agcMode = GainControl::kAdaptiveDigital;
3244 break;
3245 case kAgcUnchanged:
3246 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3247 break;
3248 case kAgcFixedDigital:
3249 agcMode = GainControl::kFixedDigital;
3250 break;
3251 case kAgcAdaptiveDigital:
3252 agcMode =GainControl::kAdaptiveDigital;
3253 break;
3254 default:
3255 _engineStatisticsPtr->SetLastError(
3256 VE_INVALID_ARGUMENT, kTraceError,
3257 "SetRxAgcStatus() invalid Agc mode");
3258 return -1;
3259 }
3260
3261 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3262 {
3263 _engineStatisticsPtr->SetLastError(
3264 VE_APM_ERROR, kTraceError,
3265 "SetRxAgcStatus() failed to set Agc mode");
3266 return -1;
3267 }
3268 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3269 {
3270 _engineStatisticsPtr->SetLastError(
3271 VE_APM_ERROR, kTraceError,
3272 "SetRxAgcStatus() failed to set Agc state");
3273 return -1;
3274 }
3275
3276 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3278
3279 return 0;
3280}
3281
3282int
3283Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3284{
3285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3286 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3287
3288 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3289 GainControl::Mode agcMode =
3290 _rxAudioProcessingModulePtr->gain_control()->mode();
3291
3292 enabled = enable;
3293
3294 switch (agcMode)
3295 {
3296 case GainControl::kFixedDigital:
3297 mode = kAgcFixedDigital;
3298 break;
3299 case GainControl::kAdaptiveDigital:
3300 mode = kAgcAdaptiveDigital;
3301 break;
3302 default:
3303 _engineStatisticsPtr->SetLastError(
3304 VE_APM_ERROR, kTraceError,
3305 "GetRxAgcStatus() invalid Agc mode");
3306 return -1;
3307 }
3308
3309 return 0;
3310}
3311
3312int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003313Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003314{
3315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3316 "Channel::SetRxAgcConfig()");
3317
3318 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3319 config.targetLeveldBOv) != 0)
3320 {
3321 _engineStatisticsPtr->SetLastError(
3322 VE_APM_ERROR, kTraceError,
3323 "SetRxAgcConfig() failed to set target peak |level|"
3324 "(or envelope) of the Agc");
3325 return -1;
3326 }
3327 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3328 config.digitalCompressionGaindB) != 0)
3329 {
3330 _engineStatisticsPtr->SetLastError(
3331 VE_APM_ERROR, kTraceError,
3332 "SetRxAgcConfig() failed to set the range in |gain| the"
3333 " digital compression stage may apply");
3334 return -1;
3335 }
3336 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3337 config.limiterEnable) != 0)
3338 {
3339 _engineStatisticsPtr->SetLastError(
3340 VE_APM_ERROR, kTraceError,
3341 "SetRxAgcConfig() failed to set hard limiter to the signal");
3342 return -1;
3343 }
3344
3345 return 0;
3346}
3347
3348int
3349Channel::GetRxAgcConfig(AgcConfig& config)
3350{
3351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3352 "Channel::GetRxAgcConfig(config=%?)");
3353
3354 config.targetLeveldBOv =
3355 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3356 config.digitalCompressionGaindB =
3357 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3358 config.limiterEnable =
3359 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3360
3361 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3362 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3363 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3364 " limiterEnable=%d",
3365 config.targetLeveldBOv,
3366 config.digitalCompressionGaindB,
3367 config.limiterEnable);
3368
3369 return 0;
3370}
3371
3372#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3373
3374#ifdef WEBRTC_VOICE_ENGINE_NR
3375
3376int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003377Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003378{
3379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3380 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3381 (int)enable, (int)mode);
3382
3383 NoiseSuppression::Level nsLevel(
3384 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3385 switch (mode)
3386 {
3387
3388 case kNsDefault:
3389 nsLevel = (NoiseSuppression::Level)
3390 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3391 break;
3392 case kNsUnchanged:
3393 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3394 break;
3395 case kNsConference:
3396 nsLevel = NoiseSuppression::kHigh;
3397 break;
3398 case kNsLowSuppression:
3399 nsLevel = NoiseSuppression::kLow;
3400 break;
3401 case kNsModerateSuppression:
3402 nsLevel = NoiseSuppression::kModerate;
3403 break;
3404 case kNsHighSuppression:
3405 nsLevel = NoiseSuppression::kHigh;
3406 break;
3407 case kNsVeryHighSuppression:
3408 nsLevel = NoiseSuppression::kVeryHigh;
3409 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 }
3411
3412 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3413 != 0)
3414 {
3415 _engineStatisticsPtr->SetLastError(
3416 VE_APM_ERROR, kTraceError,
3417 "SetRxAgcStatus() failed to set Ns level");
3418 return -1;
3419 }
3420 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3421 {
3422 _engineStatisticsPtr->SetLastError(
3423 VE_APM_ERROR, kTraceError,
3424 "SetRxAgcStatus() failed to set Agc state");
3425 return -1;
3426 }
3427
3428 _rxNsIsEnabled = enable;
3429 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3430
3431 return 0;
3432}
3433
3434int
3435Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3436{
3437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3438 "Channel::GetRxNsStatus(enable=?, mode=?)");
3439
3440 bool enable =
3441 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3442 NoiseSuppression::Level ncLevel =
3443 _rxAudioProcessingModulePtr->noise_suppression()->level();
3444
3445 enabled = enable;
3446
3447 switch (ncLevel)
3448 {
3449 case NoiseSuppression::kLow:
3450 mode = kNsLowSuppression;
3451 break;
3452 case NoiseSuppression::kModerate:
3453 mode = kNsModerateSuppression;
3454 break;
3455 case NoiseSuppression::kHigh:
3456 mode = kNsHighSuppression;
3457 break;
3458 case NoiseSuppression::kVeryHigh:
3459 mode = kNsVeryHighSuppression;
3460 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003461 }
3462
3463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3464 VoEId(_instanceId,_channelId),
3465 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3466 return 0;
3467}
3468
3469#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3470
3471int
3472Channel::RegisterRTPObserver(VoERTPObserver& observer)
3473{
3474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3475 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003476 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003477
3478 if (_rtpObserverPtr)
3479 {
3480 _engineStatisticsPtr->SetLastError(
3481 VE_INVALID_OPERATION, kTraceError,
3482 "RegisterRTPObserver() observer already enabled");
3483 return -1;
3484 }
3485
3486 _rtpObserverPtr = &observer;
3487 _rtpObserver = true;
3488
3489 return 0;
3490}
3491
3492int
3493Channel::DeRegisterRTPObserver()
3494{
3495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3496 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003497 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003498
3499 if (!_rtpObserverPtr)
3500 {
3501 _engineStatisticsPtr->SetLastError(
3502 VE_INVALID_OPERATION, kTraceWarning,
3503 "DeRegisterRTPObserver() observer already disabled");
3504 return 0;
3505 }
3506
3507 _rtpObserver = false;
3508 _rtpObserverPtr = NULL;
3509
3510 return 0;
3511}
3512
3513int
3514Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3515{
3516 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3517 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003518 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003519
3520 if (_rtcpObserverPtr)
3521 {
3522 _engineStatisticsPtr->SetLastError(
3523 VE_INVALID_OPERATION, kTraceError,
3524 "RegisterRTCPObserver() observer already enabled");
3525 return -1;
3526 }
3527
3528 _rtcpObserverPtr = &observer;
3529 _rtcpObserver = true;
3530
3531 return 0;
3532}
3533
3534int
3535Channel::DeRegisterRTCPObserver()
3536{
3537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3538 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003539 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003540
3541 if (!_rtcpObserverPtr)
3542 {
3543 _engineStatisticsPtr->SetLastError(
3544 VE_INVALID_OPERATION, kTraceWarning,
3545 "DeRegisterRTCPObserver() observer already disabled");
3546 return 0;
3547 }
3548
3549 _rtcpObserver = false;
3550 _rtcpObserverPtr = NULL;
3551
3552 return 0;
3553}
3554
3555int
3556Channel::SetLocalSSRC(unsigned int ssrc)
3557{
3558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3559 "Channel::SetLocalSSRC()");
3560 if (_sending)
3561 {
3562 _engineStatisticsPtr->SetLastError(
3563 VE_ALREADY_SENDING, kTraceError,
3564 "SetLocalSSRC() already sending");
3565 return -1;
3566 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003567 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003568 {
3569 _engineStatisticsPtr->SetLastError(
3570 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3571 "SetLocalSSRC() failed to set SSRC");
3572 return -1;
3573 }
3574 return 0;
3575}
3576
3577int
3578Channel::GetLocalSSRC(unsigned int& ssrc)
3579{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003580 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003581 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3582 VoEId(_instanceId,_channelId),
3583 "GetLocalSSRC() => ssrc=%lu", ssrc);
3584 return 0;
3585}
3586
3587int
3588Channel::GetRemoteSSRC(unsigned int& ssrc)
3589{
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003590 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003591 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3592 VoEId(_instanceId,_channelId),
3593 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3594 return 0;
3595}
3596
3597int
3598Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3599{
3600 if (arrCSRC == NULL)
3601 {
3602 _engineStatisticsPtr->SetLastError(
3603 VE_INVALID_ARGUMENT, kTraceError,
3604 "GetRemoteCSRCs() invalid array argument");
3605 return -1;
3606 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003607 uint32_t arrOfCSRC[kRtpCsrcSize];
3608 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003609 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003610 if (CSRCs > 0)
3611 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003612 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003613 for (int i = 0; i < (int) CSRCs; i++)
3614 {
3615 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3616 VoEId(_instanceId, _channelId),
3617 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3618 }
3619 } else
3620 {
3621 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3622 VoEId(_instanceId, _channelId),
3623 "GetRemoteCSRCs() => list is empty!");
3624 }
3625 return CSRCs;
3626}
3627
3628int
3629Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3630{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003631 if (_rtpAudioProc.get() == NULL)
3632 {
3633 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3634 _channelId)));
3635 if (_rtpAudioProc.get() == NULL)
3636 {
3637 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3638 "Failed to create AudioProcessing");
3639 return -1;
3640 }
3641 }
3642
3643 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3644 AudioProcessing::kNoError)
3645 {
3646 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3647 "Failed to enable AudioProcessing::level_estimator()");
3648 }
3649
niklase@google.com470e71d2011-07-07 08:21:25 +00003650 _includeAudioLevelIndication = enable;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00003651 if (enable) {
3652 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3653 ID);
3654 } else {
3655 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3656 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003657 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003658}
3659int
3660Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3661{
3662 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3663 VoEId(_instanceId,_channelId),
3664 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3665 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003666 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003667}
3668
3669int
3670Channel::SetRTCPStatus(bool enable)
3671{
3672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3673 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003674 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003675 kRtcpCompound : kRtcpOff) != 0)
3676 {
3677 _engineStatisticsPtr->SetLastError(
3678 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3679 "SetRTCPStatus() failed to set RTCP status");
3680 return -1;
3681 }
3682 return 0;
3683}
3684
3685int
3686Channel::GetRTCPStatus(bool& enabled)
3687{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003688 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003689 enabled = (method != kRtcpOff);
3690 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3691 VoEId(_instanceId,_channelId),
3692 "GetRTCPStatus() => enabled=%d", enabled);
3693 return 0;
3694}
3695
3696int
3697Channel::SetRTCP_CNAME(const char cName[256])
3698{
3699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3700 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003701 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003702 {
3703 _engineStatisticsPtr->SetLastError(
3704 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3705 "SetRTCP_CNAME() failed to set RTCP CNAME");
3706 return -1;
3707 }
3708 return 0;
3709}
3710
3711int
3712Channel::GetRTCP_CNAME(char cName[256])
3713{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003714 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003715 {
3716 _engineStatisticsPtr->SetLastError(
3717 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3718 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3719 return -1;
3720 }
3721 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3722 VoEId(_instanceId, _channelId),
3723 "GetRTCP_CNAME() => cName=%s", cName);
3724 return 0;
3725}
3726
3727int
3728Channel::GetRemoteRTCP_CNAME(char cName[256])
3729{
3730 if (cName == NULL)
3731 {
3732 _engineStatisticsPtr->SetLastError(
3733 VE_INVALID_ARGUMENT, kTraceError,
3734 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3735 return -1;
3736 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003737 char cname[RTCP_CNAME_SIZE];
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003738 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003739 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003740 {
3741 _engineStatisticsPtr->SetLastError(
3742 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3743 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3744 return -1;
3745 }
3746 strcpy(cName, cname);
3747 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3748 VoEId(_instanceId, _channelId),
3749 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3750 return 0;
3751}
3752
3753int
3754Channel::GetRemoteRTCPData(
3755 unsigned int& NTPHigh,
3756 unsigned int& NTPLow,
3757 unsigned int& timestamp,
3758 unsigned int& playoutTimestamp,
3759 unsigned int* jitter,
3760 unsigned short* fractionLost)
3761{
3762 // --- Information from sender info in received Sender Reports
3763
3764 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003765 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003766 {
3767 _engineStatisticsPtr->SetLastError(
3768 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003769 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003770 "side");
3771 return -1;
3772 }
3773
3774 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3775 // and octet count)
3776 NTPHigh = senderInfo.NTPseconds;
3777 NTPLow = senderInfo.NTPfraction;
3778 timestamp = senderInfo.RTPtimeStamp;
3779
3780 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3781 VoEId(_instanceId, _channelId),
3782 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3783 "timestamp=%lu",
3784 NTPHigh, NTPLow, timestamp);
3785
3786 // --- Locally derived information
3787
3788 // This value is updated on each incoming RTCP packet (0 when no packet
3789 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003790 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003791
3792 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3793 VoEId(_instanceId, _channelId),
3794 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003795 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003796
3797 if (NULL != jitter || NULL != fractionLost)
3798 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003799 // Get all RTCP receiver report blocks that have been received on this
3800 // channel. If we receive RTP packets from a remote source we know the
3801 // remote SSRC and use the report block from him.
3802 // Otherwise use the first report block.
3803 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003804 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003805 remote_stats.empty()) {
3806 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3807 VoEId(_instanceId, _channelId),
3808 "GetRemoteRTCPData() failed to measure statistics due"
3809 " to lack of received RTP and/or RTCP packets");
3810 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003811 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003812
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003813 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003814 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3815 for (; it != remote_stats.end(); ++it) {
3816 if (it->remoteSSRC == remoteSSRC)
3817 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003818 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003819
3820 if (it == remote_stats.end()) {
3821 // If we have not received any RTCP packets from this SSRC it probably
3822 // means that we have not received any RTP packets.
3823 // Use the first received report block instead.
3824 it = remote_stats.begin();
3825 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003826 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003827
xians@webrtc.org79af7342012-01-31 12:22:14 +00003828 if (jitter) {
3829 *jitter = it->jitter;
3830 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3831 VoEId(_instanceId, _channelId),
3832 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3833 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003834
xians@webrtc.org79af7342012-01-31 12:22:14 +00003835 if (fractionLost) {
3836 *fractionLost = it->fractionLost;
3837 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3838 VoEId(_instanceId, _channelId),
3839 "GetRemoteRTCPData() => fractionLost = %lu",
3840 *fractionLost);
3841 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003842 }
3843 return 0;
3844}
3845
3846int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003847Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003848 unsigned int name,
3849 const char* data,
3850 unsigned short dataLengthInBytes)
3851{
3852 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3853 "Channel::SendApplicationDefinedRTCPPacket()");
3854 if (!_sending)
3855 {
3856 _engineStatisticsPtr->SetLastError(
3857 VE_NOT_SENDING, kTraceError,
3858 "SendApplicationDefinedRTCPPacket() not sending");
3859 return -1;
3860 }
3861 if (NULL == data)
3862 {
3863 _engineStatisticsPtr->SetLastError(
3864 VE_INVALID_ARGUMENT, kTraceError,
3865 "SendApplicationDefinedRTCPPacket() invalid data value");
3866 return -1;
3867 }
3868 if (dataLengthInBytes % 4 != 0)
3869 {
3870 _engineStatisticsPtr->SetLastError(
3871 VE_INVALID_ARGUMENT, kTraceError,
3872 "SendApplicationDefinedRTCPPacket() invalid length value");
3873 return -1;
3874 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003875 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003876 if (status == kRtcpOff)
3877 {
3878 _engineStatisticsPtr->SetLastError(
3879 VE_RTCP_ERROR, kTraceError,
3880 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3881 return -1;
3882 }
3883
3884 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003885 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003886 subType,
3887 name,
3888 (const unsigned char*) data,
3889 dataLengthInBytes) != 0)
3890 {
3891 _engineStatisticsPtr->SetLastError(
3892 VE_SEND_ERROR, kTraceError,
3893 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3894 return -1;
3895 }
3896 return 0;
3897}
3898
3899int
3900Channel::GetRTPStatistics(
3901 unsigned int& averageJitterMs,
3902 unsigned int& maxJitterMs,
3903 unsigned int& discardedPackets)
3904{
niklase@google.com470e71d2011-07-07 08:21:25 +00003905 // The jitter statistics is updated for each received RTP packet and is
3906 // based on received packets.
elham@webrtc.orgb7eda432013-07-15 21:08:27 +00003907 ReceiveStatistics::RtpReceiveStatistics statistics;
3908 if (!rtp_receive_statistics_->Statistics(
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003909 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3910 _engineStatisticsPtr->SetLastError(
3911 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3912 "GetRTPStatistics() failed to read RTP statistics from the "
3913 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 }
3915
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003916 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00003917 _audioCodingModule.PlayoutFrequency();
3918 if (playoutFrequency > 0)
3919 {
3920 // Scale RTP statistics given the current playout frequency
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003921 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3922 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 }
3924
3925 discardedPackets = _numberOfDiscardedPackets;
3926
3927 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3928 VoEId(_instanceId, _channelId),
3929 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003930 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003931 averageJitterMs, maxJitterMs, discardedPackets);
3932 return 0;
3933}
3934
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003935int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3936 if (sender_info == NULL) {
3937 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3938 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3939 return -1;
3940 }
3941
3942 // Get the sender info from the latest received RTCP Sender Report.
3943 RTCPSenderInfo rtcp_sender_info;
3944 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3945 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3946 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3947 return -1;
3948 }
3949
3950 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3951 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3952 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3953 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3954 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3955 return 0;
3956}
3957
3958int Channel::GetRemoteRTCPReportBlocks(
3959 std::vector<ReportBlock>* report_blocks) {
3960 if (report_blocks == NULL) {
3961 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3962 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3963 return -1;
3964 }
3965
3966 // Get the report blocks from the latest received RTCP Sender or Receiver
3967 // Report. Each element in the vector contains the sender's SSRC and a
3968 // report block according to RFC 3550.
3969 std::vector<RTCPReportBlock> rtcp_report_blocks;
3970 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3971 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3972 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3973 return -1;
3974 }
3975
3976 if (rtcp_report_blocks.empty())
3977 return 0;
3978
3979 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3980 for (; it != rtcp_report_blocks.end(); ++it) {
3981 ReportBlock report_block;
3982 report_block.sender_SSRC = it->remoteSSRC;
3983 report_block.source_SSRC = it->sourceSSRC;
3984 report_block.fraction_lost = it->fractionLost;
3985 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3986 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3987 report_block.interarrival_jitter = it->jitter;
3988 report_block.last_SR_timestamp = it->lastSR;
3989 report_block.delay_since_last_SR = it->delaySinceLastSR;
3990 report_blocks->push_back(report_block);
3991 }
3992 return 0;
3993}
3994
niklase@google.com470e71d2011-07-07 08:21:25 +00003995int
3996Channel::GetRTPStatistics(CallStatistics& stats)
3997{
niklase@google.com470e71d2011-07-07 08:21:25 +00003998 // --- Part one of the final structure (four values)
3999
4000 // The jitter statistics is updated for each received RTP packet and is
4001 // based on received packets.
elham@webrtc.orgb7eda432013-07-15 21:08:27 +00004002 ReceiveStatistics::RtpReceiveStatistics statistics;
4003 if (!rtp_receive_statistics_->Statistics(
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004004 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4005 _engineStatisticsPtr->SetLastError(
4006 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4007 "GetRTPStatistics() failed to read RTP statistics from the "
4008 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004009 }
4010
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004011 stats.fractionLost = statistics.fraction_lost;
4012 stats.cumulativeLost = statistics.cumulative_lost;
4013 stats.extendedMax = statistics.extended_max_sequence_number;
4014 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004015
4016 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4017 VoEId(_instanceId, _channelId),
4018 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004019 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004020 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4021 stats.jitterSamples);
4022
4023 // --- Part two of the final structure (one value)
4024
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004025 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004026 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004027 if (method == kRtcpOff)
4028 {
4029 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4030 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004031 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004032 "measurements cannot be retrieved");
4033 } else
4034 {
4035 // The remote SSRC will be zero if no RTP packet has been received.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004036 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004037 if (remoteSSRC > 0)
4038 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004039 uint16_t avgRTT(0);
4040 uint16_t maxRTT(0);
4041 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004042
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004043 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004044 != 0)
4045 {
4046 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4047 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004048 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004049 "the RTP/RTCP module");
4050 }
4051 } else
4052 {
4053 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4054 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004055 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004056 "RTP packets have been received yet");
4057 }
4058 }
4059
4060 stats.rttMs = static_cast<int> (RTT);
4061
4062 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4063 VoEId(_instanceId, _channelId),
4064 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4065
4066 // --- Part three of the final structure (four values)
4067
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004068 uint32_t bytesSent(0);
4069 uint32_t packetsSent(0);
4070 uint32_t bytesReceived(0);
4071 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004072
elham@webrtc.orgb7eda432013-07-15 21:08:27 +00004073 rtp_receive_statistics_->GetDataCounters(&bytesReceived, &packetsReceived);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004074
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004075 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004076 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004077 {
4078 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4079 VoEId(_instanceId, _channelId),
4080 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004081 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004082 }
4083
4084 stats.bytesSent = bytesSent;
4085 stats.packetsSent = packetsSent;
4086 stats.bytesReceived = bytesReceived;
4087 stats.packetsReceived = packetsReceived;
4088
4089 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4090 VoEId(_instanceId, _channelId),
4091 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004092 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004093 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4094 stats.packetsReceived);
4095
4096 return 0;
4097}
4098
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004099int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4101 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004102
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004103 if (enable) {
4104 if (redPayloadtype < 0 || redPayloadtype > 127) {
4105 _engineStatisticsPtr->SetLastError(
4106 VE_PLTYPE_ERROR, kTraceError,
4107 "SetFECStatus() invalid RED payload type");
4108 return -1;
4109 }
4110
4111 if (SetRedPayloadType(redPayloadtype) < 0) {
4112 _engineStatisticsPtr->SetLastError(
4113 VE_CODEC_ERROR, kTraceError,
4114 "SetSecondarySendCodec() Failed to register RED ACM");
4115 return -1;
4116 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004117 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004118
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004119 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4120 _engineStatisticsPtr->SetLastError(
4121 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4122 "SetFECStatus() failed to set FEC state in the ACM");
4123 return -1;
4124 }
4125 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004126}
4127
4128int
4129Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4130{
4131 enabled = _audioCodingModule.FECStatus();
4132 if (enabled)
4133 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004134 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004135 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004136 {
4137 _engineStatisticsPtr->SetLastError(
4138 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4139 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4140 "module");
4141 return -1;
4142 }
4143 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4144 VoEId(_instanceId, _channelId),
4145 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4146 enabled, redPayloadtype);
4147 return 0;
4148 }
4149 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4150 VoEId(_instanceId, _channelId),
4151 "GetFECStatus() => enabled=%d", enabled);
4152 return 0;
4153}
4154
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004155void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4156 // None of these functions can fail.
4157 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004158 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff,
4159 maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004160 if (enable)
4161 _audioCodingModule.EnableNack(maxNumberOfPackets);
4162 else
4163 _audioCodingModule.DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004164}
4165
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004166// Called when we are missing one or more packets.
4167int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004168 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4169}
4170
niklase@google.com470e71d2011-07-07 08:21:25 +00004171int
niklase@google.com470e71d2011-07-07 08:21:25 +00004172Channel::StartRTPDump(const char fileNameUTF8[1024],
4173 RTPDirections direction)
4174{
4175 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4176 "Channel::StartRTPDump()");
4177 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4178 {
4179 _engineStatisticsPtr->SetLastError(
4180 VE_INVALID_ARGUMENT, kTraceError,
4181 "StartRTPDump() invalid RTP direction");
4182 return -1;
4183 }
4184 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4185 &_rtpDumpIn : &_rtpDumpOut;
4186 if (rtpDumpPtr == NULL)
4187 {
4188 assert(false);
4189 return -1;
4190 }
4191 if (rtpDumpPtr->IsActive())
4192 {
4193 rtpDumpPtr->Stop();
4194 }
4195 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4196 {
4197 _engineStatisticsPtr->SetLastError(
4198 VE_BAD_FILE, kTraceError,
4199 "StartRTPDump() failed to create file");
4200 return -1;
4201 }
4202 return 0;
4203}
4204
4205int
4206Channel::StopRTPDump(RTPDirections direction)
4207{
4208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4209 "Channel::StopRTPDump()");
4210 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4211 {
4212 _engineStatisticsPtr->SetLastError(
4213 VE_INVALID_ARGUMENT, kTraceError,
4214 "StopRTPDump() invalid RTP direction");
4215 return -1;
4216 }
4217 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4218 &_rtpDumpIn : &_rtpDumpOut;
4219 if (rtpDumpPtr == NULL)
4220 {
4221 assert(false);
4222 return -1;
4223 }
4224 if (!rtpDumpPtr->IsActive())
4225 {
4226 return 0;
4227 }
4228 return rtpDumpPtr->Stop();
4229}
4230
4231bool
4232Channel::RTPDumpIsActive(RTPDirections direction)
4233{
4234 if ((direction != kRtpIncoming) &&
4235 (direction != kRtpOutgoing))
4236 {
4237 _engineStatisticsPtr->SetLastError(
4238 VE_INVALID_ARGUMENT, kTraceError,
4239 "RTPDumpIsActive() invalid RTP direction");
4240 return false;
4241 }
4242 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4243 &_rtpDumpIn : &_rtpDumpOut;
4244 return rtpDumpPtr->IsActive();
4245}
4246
4247int
4248Channel::InsertExtraRTPPacket(unsigned char payloadType,
4249 bool markerBit,
4250 const char* payloadData,
4251 unsigned short payloadSize)
4252{
4253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4254 "Channel::InsertExtraRTPPacket()");
4255 if (payloadType > 127)
4256 {
4257 _engineStatisticsPtr->SetLastError(
4258 VE_INVALID_PLTYPE, kTraceError,
4259 "InsertExtraRTPPacket() invalid payload type");
4260 return -1;
4261 }
4262 if (payloadData == NULL)
4263 {
4264 _engineStatisticsPtr->SetLastError(
4265 VE_INVALID_ARGUMENT, kTraceError,
4266 "InsertExtraRTPPacket() invalid payload data");
4267 return -1;
4268 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004269 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004270 {
4271 _engineStatisticsPtr->SetLastError(
4272 VE_INVALID_ARGUMENT, kTraceError,
4273 "InsertExtraRTPPacket() invalid payload size");
4274 return -1;
4275 }
4276 if (!_sending)
4277 {
4278 _engineStatisticsPtr->SetLastError(
4279 VE_NOT_SENDING, kTraceError,
4280 "InsertExtraRTPPacket() not sending");
4281 return -1;
4282 }
4283
4284 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4285 // Transport::SendPacket() will be called by the module when the RTP packet
4286 // is created.
4287 // The call to SendOutgoingData() does *not* modify the timestamp and
4288 // payloadtype to ensure that the RTP module generates a valid RTP packet
4289 // (user might utilize a non-registered payload type).
4290 // The marker bit and payload type will be replaced just before the actual
4291 // transmission, i.e., the actual modification is done *after* the RTP
4292 // module has delivered its RTP packet back to the VoE.
4293 // We will use the stored values above when the packet is modified
4294 // (see Channel::SendPacket()).
4295
4296 _extraPayloadType = payloadType;
4297 _extraMarkerBit = markerBit;
4298 _insertExtraRTPPacket = true;
4299
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004300 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004301 _lastPayloadType,
4302 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004303 // Leaving the time when this frame was
4304 // received from the capture device as
4305 // undefined for voice for now.
4306 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004307 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004308 payloadSize) != 0)
4309 {
4310 _engineStatisticsPtr->SetLastError(
4311 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4312 "InsertExtraRTPPacket() failed to send extra RTP packet");
4313 return -1;
4314 }
4315
4316 return 0;
4317}
4318
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004319uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004320Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004321{
4322 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004323 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004324 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004325 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004326 return 0;
4327}
4328
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004329uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004330Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004331{
4332 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4333 "Channel::PrepareEncodeAndSend()");
4334
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004335 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004336 {
4337 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4338 "Channel::PrepareEncodeAndSend() invalid audio frame");
4339 return -1;
4340 }
4341
4342 if (_inputFilePlaying)
4343 {
4344 MixOrReplaceAudioWithFile(mixingFrequency);
4345 }
4346
4347 if (_mute)
4348 {
4349 AudioFrameOperations::Mute(_audioFrame);
4350 }
4351
4352 if (_inputExternalMedia)
4353 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004354 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004355 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004356 if (_inputExternalMediaCallbackPtr)
4357 {
4358 _inputExternalMediaCallbackPtr->Process(
4359 _channelId,
4360 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004361 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004362 _audioFrame.samples_per_channel_,
4363 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004364 isStereo);
4365 }
4366 }
4367
4368 InsertInbandDtmfTone();
4369
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004370 if (_includeAudioLevelIndication)
4371 {
4372 assert(_rtpAudioProc.get() != NULL);
4373
4374 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004375 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004376 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004377 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004378 AudioProcessing::kNoError)
4379 {
4380 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4381 VoEId(_instanceId, _channelId),
4382 "Error setting AudioProcessing sample rate");
4383 return -1;
4384 }
4385 }
4386
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004387 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004388 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004389 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4390 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004391 != AudioProcessing::kNoError)
4392 {
4393 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4394 VoEId(_instanceId, _channelId),
4395 "Error setting AudioProcessing channels");
4396 return -1;
4397 }
4398 }
4399
4400 // Performs level analysis only; does not affect the signal.
4401 _rtpAudioProc->ProcessStream(&_audioFrame);
4402 }
4403
niklase@google.com470e71d2011-07-07 08:21:25 +00004404 return 0;
4405}
4406
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004407uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004408Channel::EncodeAndSend()
4409{
4410 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4411 "Channel::EncodeAndSend()");
4412
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004413 assert(_audioFrame.num_channels_ <= 2);
4414 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004415 {
4416 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4417 "Channel::EncodeAndSend() invalid audio frame");
4418 return -1;
4419 }
4420
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004421 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004422
4423 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4424
4425 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004426 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004427 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4428 {
4429 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4430 "Channel::EncodeAndSend() ACM encoding failed");
4431 return -1;
4432 }
4433
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004434 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004435
4436 // --- Encode if complete frame is ready
4437
4438 // This call will trigger AudioPacketizationCallback::SendData if encoding
4439 // is done and payload is ready for packetization and transmission.
4440 return _audioCodingModule.Process();
4441}
4442
4443int Channel::RegisterExternalMediaProcessing(
4444 ProcessingTypes type,
4445 VoEMediaProcess& processObject)
4446{
4447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4448 "Channel::RegisterExternalMediaProcessing()");
4449
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004450 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004451
4452 if (kPlaybackPerChannel == type)
4453 {
4454 if (_outputExternalMediaCallbackPtr)
4455 {
4456 _engineStatisticsPtr->SetLastError(
4457 VE_INVALID_OPERATION, kTraceError,
4458 "Channel::RegisterExternalMediaProcessing() "
4459 "output external media already enabled");
4460 return -1;
4461 }
4462 _outputExternalMediaCallbackPtr = &processObject;
4463 _outputExternalMedia = true;
4464 }
4465 else if (kRecordingPerChannel == type)
4466 {
4467 if (_inputExternalMediaCallbackPtr)
4468 {
4469 _engineStatisticsPtr->SetLastError(
4470 VE_INVALID_OPERATION, kTraceError,
4471 "Channel::RegisterExternalMediaProcessing() "
4472 "output external media already enabled");
4473 return -1;
4474 }
4475 _inputExternalMediaCallbackPtr = &processObject;
4476 _inputExternalMedia = true;
4477 }
4478 return 0;
4479}
4480
4481int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4482{
4483 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4484 "Channel::DeRegisterExternalMediaProcessing()");
4485
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004486 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004487
4488 if (kPlaybackPerChannel == type)
4489 {
4490 if (!_outputExternalMediaCallbackPtr)
4491 {
4492 _engineStatisticsPtr->SetLastError(
4493 VE_INVALID_OPERATION, kTraceWarning,
4494 "Channel::DeRegisterExternalMediaProcessing() "
4495 "output external media already disabled");
4496 return 0;
4497 }
4498 _outputExternalMedia = false;
4499 _outputExternalMediaCallbackPtr = NULL;
4500 }
4501 else if (kRecordingPerChannel == type)
4502 {
4503 if (!_inputExternalMediaCallbackPtr)
4504 {
4505 _engineStatisticsPtr->SetLastError(
4506 VE_INVALID_OPERATION, kTraceWarning,
4507 "Channel::DeRegisterExternalMediaProcessing() "
4508 "input external media already disabled");
4509 return 0;
4510 }
4511 _inputExternalMedia = false;
4512 _inputExternalMediaCallbackPtr = NULL;
4513 }
4514
4515 return 0;
4516}
4517
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004518int Channel::SetExternalMixing(bool enabled) {
4519 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4520 "Channel::SetExternalMixing(enabled=%d)", enabled);
4521
4522 if (_playing)
4523 {
4524 _engineStatisticsPtr->SetLastError(
4525 VE_INVALID_OPERATION, kTraceError,
4526 "Channel::SetExternalMixing() "
4527 "external mixing cannot be changed while playing.");
4528 return -1;
4529 }
4530
4531 _externalMixing = enabled;
4532
4533 return 0;
4534}
4535
niklase@google.com470e71d2011-07-07 08:21:25 +00004536int
4537Channel::ResetRTCPStatistics()
4538{
4539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4540 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004541 uint32_t remoteSSRC(0);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004542 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004543 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004544}
4545
4546int
4547Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4548{
4549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4550 "Channel::GetRoundTripTimeSummary()");
4551 // Override default module outputs for the case when RTCP is disabled.
4552 // This is done to ensure that we are backward compatible with the
4553 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004554 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004555 {
4556 delaysMs.min = -1;
4557 delaysMs.max = -1;
4558 delaysMs.average = -1;
4559 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4560 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4561 " valid RTT measurements cannot be retrieved");
4562 return 0;
4563 }
4564
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004565 uint32_t remoteSSRC;
4566 uint16_t RTT;
4567 uint16_t avgRTT;
4568 uint16_t maxRTT;
4569 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004570 // The remote SSRC will be zero if no RTP packet has been received.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004571 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004572 if (remoteSSRC == 0)
4573 {
4574 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4575 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4576 " since no RTP packet has been received yet");
4577 }
4578
4579 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4580 // channel and SSRC. The SSRC is required to parse out the correct source
4581 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004582 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004583 {
4584 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4585 "GetRoundTripTimeSummary unable to retrieve RTT values"
4586 " from the RTCP layer");
4587 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4588 }
4589 else
4590 {
4591 delaysMs.min = minRTT;
4592 delaysMs.max = maxRTT;
4593 delaysMs.average = avgRTT;
4594 }
4595 return 0;
4596}
4597
4598int
4599Channel::GetNetworkStatistics(NetworkStatistics& stats)
4600{
4601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4602 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004603 ACMNetworkStatistics acm_stats;
4604 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4605 if (return_value >= 0) {
4606 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4607 }
4608 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004609}
4610
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004611bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4612 int* playout_buffer_delay_ms) const {
4613 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004614 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004615 "Channel::GetDelayEstimate() no valid estimate.");
4616 return false;
4617 }
4618 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4619 _recPacketDelayMs;
4620 *playout_buffer_delay_ms = playout_delay_ms_;
4621 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4622 "Channel::GetDelayEstimate()");
4623 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004624}
4625
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004626int Channel::SetInitialPlayoutDelay(int delay_ms)
4627{
4628 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4629 "Channel::SetInitialPlayoutDelay()");
4630 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4631 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4632 {
4633 _engineStatisticsPtr->SetLastError(
4634 VE_INVALID_ARGUMENT, kTraceError,
4635 "SetInitialPlayoutDelay() invalid min delay");
4636 return -1;
4637 }
4638 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4639 {
4640 _engineStatisticsPtr->SetLastError(
4641 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4642 "SetInitialPlayoutDelay() failed to set min playout delay");
4643 return -1;
4644 }
4645 return 0;
4646}
4647
4648
niklase@google.com470e71d2011-07-07 08:21:25 +00004649int
4650Channel::SetMinimumPlayoutDelay(int delayMs)
4651{
4652 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4653 "Channel::SetMinimumPlayoutDelay()");
4654 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4655 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4656 {
4657 _engineStatisticsPtr->SetLastError(
4658 VE_INVALID_ARGUMENT, kTraceError,
4659 "SetMinimumPlayoutDelay() invalid min delay");
4660 return -1;
4661 }
4662 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4663 {
4664 _engineStatisticsPtr->SetLastError(
4665 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4666 "SetMinimumPlayoutDelay() failed to set min playout delay");
4667 return -1;
4668 }
4669 return 0;
4670}
4671
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004672void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4673 uint32_t playout_timestamp = 0;
4674
4675 if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1) {
4676 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4677 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4678 " timestamp from the ACM");
4679 _engineStatisticsPtr->SetLastError(
4680 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4681 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4682 return;
4683 }
4684
4685 uint16_t delay_ms = 0;
4686 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4687 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4688 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4689 " delay from the ADM");
4690 _engineStatisticsPtr->SetLastError(
4691 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4692 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4693 return;
4694 }
4695
4696 int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
4697 CodecInst current_recive_codec;
4698 if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
4699 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4700 playout_frequency = 8000;
4701 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4702 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004703 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004704 }
4705
4706 // Remove the playout delay.
4707 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4708
4709 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4710 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4711 playout_timestamp);
4712
4713 if (rtcp) {
4714 playout_timestamp_rtcp_ = playout_timestamp;
4715 } else {
4716 playout_timestamp_rtp_ = playout_timestamp;
4717 }
4718 playout_delay_ms_ = delay_ms;
4719}
4720
4721int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4722 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4723 "Channel::GetPlayoutTimestamp()");
4724 if (playout_timestamp_rtp_ == 0) {
4725 _engineStatisticsPtr->SetLastError(
4726 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4727 "GetPlayoutTimestamp() failed to retrieve timestamp");
4728 return -1;
4729 }
4730 timestamp = playout_timestamp_rtp_;
4731 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4732 VoEId(_instanceId,_channelId),
4733 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4734 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004735}
4736
4737int
4738Channel::SetInitTimestamp(unsigned int timestamp)
4739{
4740 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4741 "Channel::SetInitTimestamp()");
4742 if (_sending)
4743 {
4744 _engineStatisticsPtr->SetLastError(
4745 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4746 return -1;
4747 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004748 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004749 {
4750 _engineStatisticsPtr->SetLastError(
4751 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4752 "SetInitTimestamp() failed to set timestamp");
4753 return -1;
4754 }
4755 return 0;
4756}
4757
4758int
4759Channel::SetInitSequenceNumber(short sequenceNumber)
4760{
4761 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4762 "Channel::SetInitSequenceNumber()");
4763 if (_sending)
4764 {
4765 _engineStatisticsPtr->SetLastError(
4766 VE_SENDING, kTraceError,
4767 "SetInitSequenceNumber() already sending");
4768 return -1;
4769 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004770 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004771 {
4772 _engineStatisticsPtr->SetLastError(
4773 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4774 "SetInitSequenceNumber() failed to set sequence number");
4775 return -1;
4776 }
4777 return 0;
4778}
4779
4780int
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004781Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004782{
4783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4784 "Channel::GetRtpRtcp()");
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004785 *rtpRtcpModule = _rtpRtcpModule.get();
4786 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004787 return 0;
4788}
4789
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004790// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4791// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004792int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004793Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004794{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004795 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004796 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004797
4798 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004799 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004800
4801 if (_inputFilePlayerPtr == NULL)
4802 {
4803 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4804 VoEId(_instanceId, _channelId),
4805 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4806 " doesnt exist");
4807 return -1;
4808 }
4809
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004810 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004811 fileSamples,
4812 mixingFrequency) == -1)
4813 {
4814 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4815 VoEId(_instanceId, _channelId),
4816 "Channel::MixOrReplaceAudioWithFile() file mixing "
4817 "failed");
4818 return -1;
4819 }
4820 if (fileSamples == 0)
4821 {
4822 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4823 VoEId(_instanceId, _channelId),
4824 "Channel::MixOrReplaceAudioWithFile() file is ended");
4825 return 0;
4826 }
4827 }
4828
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004829 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004830
4831 if (_mixFileWithMicrophone)
4832 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004833 // Currently file stream is always mono.
4834 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004835 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004836 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004837 fileBuffer.get(),
4838 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004839 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004840 }
4841 else
4842 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004843 // Replace ACM audio with file.
4844 // Currently file stream is always mono.
4845 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004846 _audioFrame.UpdateFrame(_channelId,
4847 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004848 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004849 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004850 mixingFrequency,
4851 AudioFrame::kNormalSpeech,
4852 AudioFrame::kVadUnknown,
4853 1);
4854
4855 }
4856 return 0;
4857}
4858
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004859int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004860Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004861 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004862{
4863 assert(mixingFrequency <= 32000);
4864
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004865 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004866 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004867
4868 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004869 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004870
4871 if (_outputFilePlayerPtr == NULL)
4872 {
4873 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4874 VoEId(_instanceId, _channelId),
4875 "Channel::MixAudioWithFile() file mixing failed");
4876 return -1;
4877 }
4878
4879 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004880 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004881 fileSamples,
4882 mixingFrequency) == -1)
4883 {
4884 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4885 VoEId(_instanceId, _channelId),
4886 "Channel::MixAudioWithFile() file mixing failed");
4887 return -1;
4888 }
4889 }
4890
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004891 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004892 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004893 // Currently file stream is always mono.
4894 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004895 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004896 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004897 fileBuffer.get(),
4898 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004899 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004900 }
4901 else
4902 {
4903 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004904 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004905 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004906 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004907 return -1;
4908 }
4909
4910 return 0;
4911}
4912
4913int
4914Channel::InsertInbandDtmfTone()
4915{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004916 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004917 if (_inbandDtmfQueue.PendingDtmf() &&
4918 !_inbandDtmfGenerator.IsAddingTone() &&
4919 _inbandDtmfGenerator.DelaySinceLastTone() >
4920 kMinTelephoneEventSeparationMs)
4921 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004922 int8_t eventCode(0);
4923 uint16_t lengthMs(0);
4924 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004925
4926 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4927 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4928 if (_playInbandDtmfEvent)
4929 {
4930 // Add tone to output mixer using a reduced length to minimize
4931 // risk of echo.
4932 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4933 attenuationDb);
4934 }
4935 }
4936
4937 if (_inbandDtmfGenerator.IsAddingTone())
4938 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004939 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004940 _inbandDtmfGenerator.GetSampleRate(frequency);
4941
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004942 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004943 {
4944 // Update sample rate of Dtmf tone since the mixing frequency
4945 // has changed.
4946 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004947 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004948 // Reset the tone to be added taking the new sample rate into
4949 // account.
4950 _inbandDtmfGenerator.ResetTone();
4951 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004952
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004953 int16_t toneBuffer[320];
4954 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004955 // Get 10ms tone segment and set time since last tone to zero
4956 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4957 {
4958 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4959 VoEId(_instanceId, _channelId),
4960 "Channel::EncodeAndSend() inserting Dtmf failed");
4961 return -1;
4962 }
4963
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004964 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004965 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004966 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004967 sample++)
4968 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004969 for (int channel = 0;
4970 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004971 channel++)
4972 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004973 const int index = sample * _audioFrame.num_channels_ + channel;
4974 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004975 }
4976 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004977
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004978 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004979 } else
4980 {
4981 // Add 10ms to "delay-since-last-tone" counter
4982 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4983 }
4984 return 0;
4985}
4986
niklase@google.com470e71d2011-07-07 08:21:25 +00004987void
4988Channel::ResetDeadOrAliveCounters()
4989{
4990 _countDeadDetections = 0;
4991 _countAliveDetections = 0;
4992}
4993
4994void
4995Channel::UpdateDeadOrAliveCounters(bool alive)
4996{
4997 if (alive)
4998 _countAliveDetections++;
4999 else
5000 _countDeadDetections++;
5001}
5002
5003int
5004Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5005{
niklase@google.com470e71d2011-07-07 08:21:25 +00005006 return 0;
5007}
5008
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005009int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005010Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5011{
5012 if (_transportPtr == NULL)
5013 {
5014 return -1;
5015 }
5016 if (!RTCP)
5017 {
5018 return _transportPtr->SendPacket(_channelId, data, len);
5019 }
5020 else
5021 {
5022 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5023 }
5024}
5025
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005026// Called for incoming RTP packets after successful RTP header parsing.
5027void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5028 uint16_t sequence_number) {
5029 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5030 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5031 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005032
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005033 // Get frequency of last received payload
5034 int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005035
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005036 CodecInst current_receive_codec;
5037 if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
5038 return;
5039 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005040
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005041 // Update the least required delay.
5042 least_required_delay_ms_ = _audioCodingModule.LeastRequiredDelayMs();
5043
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005044 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5045 // Even though the actual sampling rate for G.722 audio is
5046 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5047 // 8,000 Hz because that value was erroneously assigned in
5048 // RFC 1890 and must remain unchanged for backward compatibility.
5049 rtp_receive_frequency = 8000;
5050 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5051 // We are resampling Opus internally to 32,000 Hz until all our
5052 // DSP routines can operate at 48,000 Hz, but the RTP clock
5053 // rate for the Opus payload format is standardized to 48,000 Hz,
5054 // because that is the maximum supported decoding sampling rate.
5055 rtp_receive_frequency = 48000;
5056 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005057
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005058 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5059 // packet.
5060 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5061 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005062
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005063 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5064 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005065
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005066 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005067
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005068 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5069 timestamp_diff_ms = 0;
5070 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005071
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005072 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005073
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005074 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5075 _recPacketDelayMs = packet_delay_ms;
5076 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005077
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005078 if (_average_jitter_buffer_delay_us == 0) {
5079 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5080 return;
5081 }
5082
5083 // Filter average delay value using exponential filter (alpha is
5084 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5085 // risk of rounding error) and compensate for it in GetDelayEstimate()
5086 // later.
5087 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5088 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005089}
5090
5091void
5092Channel::RegisterReceiveCodecsToRTPModule()
5093{
5094 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5095 "Channel::RegisterReceiveCodecsToRTPModule()");
5096
5097
5098 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005099 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005100
5101 for (int idx = 0; idx < nSupportedCodecs; idx++)
5102 {
5103 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005104 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00005105 (rtp_receiver_->RegisterReceivePayload(
5106 codec.plname,
5107 codec.pltype,
5108 codec.plfreq,
5109 codec.channels,
5110 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005111 {
5112 WEBRTC_TRACE(
5113 kTraceWarning,
5114 kTraceVoice,
5115 VoEId(_instanceId, _channelId),
5116 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5117 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5118 codec.plname, codec.pltype, codec.plfreq,
5119 codec.channels, codec.rate);
5120 }
5121 else
5122 {
5123 WEBRTC_TRACE(
5124 kTraceInfo,
5125 kTraceVoice,
5126 VoEId(_instanceId, _channelId),
5127 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005128 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005129 "receiver",
5130 codec.plname, codec.pltype, codec.plfreq,
5131 codec.channels, codec.rate);
5132 }
5133 }
5134}
5135
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005136int Channel::ApmProcessRx(AudioFrame& frame) {
5137 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5138 // Register the (possibly new) frame parameters.
5139 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005140 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005141 }
5142 if (audioproc->set_num_channels(frame.num_channels_,
5143 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005144 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005145 }
5146 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005147 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005148 }
5149 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005150}
5151
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005152int Channel::SetSecondarySendCodec(const CodecInst& codec,
5153 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005154 // Sanity check for payload type.
5155 if (red_payload_type < 0 || red_payload_type > 127) {
5156 _engineStatisticsPtr->SetLastError(
5157 VE_PLTYPE_ERROR, kTraceError,
5158 "SetRedPayloadType() invalid RED payload type");
5159 return -1;
5160 }
5161
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005162 if (SetRedPayloadType(red_payload_type) < 0) {
5163 _engineStatisticsPtr->SetLastError(
5164 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5165 "SetSecondarySendCodec() Failed to register RED ACM");
5166 return -1;
5167 }
5168 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5169 _engineStatisticsPtr->SetLastError(
5170 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5171 "SetSecondarySendCodec() Failed to register secondary send codec in "
5172 "ACM");
5173 return -1;
5174 }
5175
5176 return 0;
5177}
5178
5179void Channel::RemoveSecondarySendCodec() {
5180 _audioCodingModule.UnregisterSecondarySendCodec();
5181}
5182
5183int Channel::GetSecondarySendCodec(CodecInst* codec) {
5184 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5185 _engineStatisticsPtr->SetLastError(
5186 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5187 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5188 return -1;
5189 }
5190 return 0;
5191}
5192
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005193// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005194int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005195 CodecInst codec;
5196 bool found_red = false;
5197
5198 // Get default RED settings from the ACM database
5199 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5200 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005201 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005202 if (!STR_CASE_CMP(codec.plname, "RED")) {
5203 found_red = true;
5204 break;
5205 }
5206 }
5207
5208 if (!found_red) {
5209 _engineStatisticsPtr->SetLastError(
5210 VE_CODEC_ERROR, kTraceError,
5211 "SetRedPayloadType() RED is not supported");
5212 return -1;
5213 }
5214
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005215 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005216 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5217 _engineStatisticsPtr->SetLastError(
5218 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5219 "SetRedPayloadType() RED registration in ACM module failed");
5220 return -1;
5221 }
5222
5223 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5224 _engineStatisticsPtr->SetLastError(
5225 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5226 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5227 return -1;
5228 }
5229 return 0;
5230}
5231
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005232} // namespace voe
5233} // namespace webrtc