blob: e26cf7f923bf56c0cd65a42bb5384df5a4314251 [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"
15#include "webrtc/modules/utility/interface/audio_frame_operations.h"
16#include "webrtc/modules/utility/interface/process_thread.h"
17#include "webrtc/modules/utility/interface/rtp_dump.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/logging.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21#include "webrtc/voice_engine/include/voe_base.h"
22#include "webrtc/voice_engine/include/voe_external_media.h"
23#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
24#include "webrtc/voice_engine/output_mixer.h"
25#include "webrtc/voice_engine/statistics.h"
26#include "webrtc/voice_engine/transmit_mixer.h"
27#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000028
29#if defined(_WIN32)
30#include <Qos.h>
31#endif
32
andrew@webrtc.org50419b02012-11-14 19:07:54 +000033namespace webrtc {
34namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36WebRtc_Word32
37Channel::SendData(FrameType frameType,
38 WebRtc_UWord8 payloadType,
39 WebRtc_UWord32 timeStamp,
40 const WebRtc_UWord8* payloadData,
41 WebRtc_UWord16 payloadSize,
42 const RTPFragmentationHeader* fragmentation)
43{
44 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
45 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
46 " payloadSize=%u, fragmentation=0x%x)",
47 frameType, payloadType, timeStamp, payloadSize, fragmentation);
48
49 if (_includeAudioLevelIndication)
50 {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000051 assert(_rtpAudioProc.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000052 // Store current audio level in the RTP/RTCP module.
53 // The level will be used in combination with voice-activity state
54 // (frameType) to add an RTP header extension
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000055 _rtpRtcpModule->SetAudioLevel(_rtpAudioProc->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000056 }
57
58 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
59 // packetization.
60 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000061 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000062 payloadType,
63 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000064 // Leaving the time when this frame was
65 // received from the capture device as
66 // undefined for voice for now.
67 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000068 payloadData,
69 payloadSize,
70 fragmentation) == -1)
71 {
72 _engineStatisticsPtr->SetLastError(
73 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
74 "Channel::SendData() failed to send data to RTP/RTCP module");
75 return -1;
76 }
77
78 _lastLocalTimeStamp = timeStamp;
79 _lastPayloadType = payloadType;
80
81 return 0;
82}
83
84WebRtc_Word32
85Channel::InFrameType(WebRtc_Word16 frameType)
86{
87 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
88 "Channel::InFrameType(frameType=%d)", frameType);
89
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000090 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000091 // 1 indicates speech
92 _sendFrameType = (frameType == 1) ? 1 : 0;
93 return 0;
94}
95
niklase@google.com470e71d2011-07-07 08:21:25 +000096WebRtc_Word32
97Channel::OnRxVadDetected(const int vadDecision)
98{
99 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
100 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
101
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000102 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 if (_rxVadObserverPtr)
104 {
105 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
106 }
107
108 return 0;
109}
110
111int
112Channel::SendPacket(int channel, const void *data, int len)
113{
114 channel = VoEChannelId(channel);
115 assert(channel == _channelId);
116
117 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
118 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
119
120 if (_transportPtr == NULL)
121 {
122 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
123 "Channel::SendPacket() failed to send RTP packet due to"
124 " invalid transport object");
125 return -1;
126 }
127
128 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
129 // API
130 if (_insertExtraRTPPacket)
131 {
132 WebRtc_UWord8* rtpHdr = (WebRtc_UWord8*)data;
133 WebRtc_UWord8 M_PT(0);
134 if (_extraMarkerBit)
135 {
136 M_PT = 0x80; // set the M-bit
137 }
138 M_PT += _extraPayloadType; // set the payload type
139 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
140 _insertExtraRTPPacket = false; // insert one packet only
141 }
142
143 WebRtc_UWord8* bufferToSendPtr = (WebRtc_UWord8*)data;
144 WebRtc_Word32 bufferLength = len;
145
146 // Dump the RTP packet to a file (if RTP dump is enabled).
147 if (_rtpDumpOut.DumpPacket((const WebRtc_UWord8*)data, len) == -1)
148 {
149 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
150 VoEId(_instanceId,_channelId),
151 "Channel::SendPacket() RTP dump to output file failed");
152 }
153
154 // SRTP or External encryption
155 if (_encrypting)
156 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000157 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 if (_encryptionPtr)
160 {
161 if (!_encryptionRTPBufferPtr)
162 {
163 // Allocate memory for encryption buffer one time only
164 _encryptionRTPBufferPtr =
165 new WebRtc_UWord8[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000166 memset(_encryptionRTPBufferPtr, 0,
167 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 }
169
170 // Perform encryption (SRTP or external)
171 WebRtc_Word32 encryptedBufferLength = 0;
172 _encryptionPtr->encrypt(_channelId,
173 bufferToSendPtr,
174 _encryptionRTPBufferPtr,
175 bufferLength,
176 (int*)&encryptedBufferLength);
177 if (encryptedBufferLength <= 0)
178 {
179 _engineStatisticsPtr->SetLastError(
180 VE_ENCRYPTION_FAILED,
181 kTraceError, "Channel::SendPacket() encryption failed");
182 return -1;
183 }
184
185 // Replace default data buffer with encrypted buffer
186 bufferToSendPtr = _encryptionRTPBufferPtr;
187 bufferLength = encryptedBufferLength;
188 }
189 }
190
191 // Packet transmission using WebRtc socket transport
192 if (!_externalTransport)
193 {
194 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
195 bufferLength);
196 if (n < 0)
197 {
198 WEBRTC_TRACE(kTraceError, kTraceVoice,
199 VoEId(_instanceId,_channelId),
200 "Channel::SendPacket() RTP transmission using WebRtc"
201 " sockets failed");
202 return -1;
203 }
204 return n;
205 }
206
207 // Packet transmission using external transport transport
208 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000209 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000210
211 int n = _transportPtr->SendPacket(channel,
212 bufferToSendPtr,
213 bufferLength);
214 if (n < 0)
215 {
216 WEBRTC_TRACE(kTraceError, kTraceVoice,
217 VoEId(_instanceId,_channelId),
218 "Channel::SendPacket() RTP transmission using external"
219 " transport failed");
220 return -1;
221 }
222 return n;
223 }
224}
225
226int
227Channel::SendRTCPPacket(int channel, const void *data, int len)
228{
229 channel = VoEChannelId(channel);
230 assert(channel == _channelId);
231
232 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
233 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
234
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000236 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000237 if (_transportPtr == NULL)
238 {
239 WEBRTC_TRACE(kTraceError, kTraceVoice,
240 VoEId(_instanceId,_channelId),
241 "Channel::SendRTCPPacket() failed to send RTCP packet"
242 " due to invalid transport object");
243 return -1;
244 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
246
247 WebRtc_UWord8* bufferToSendPtr = (WebRtc_UWord8*)data;
248 WebRtc_Word32 bufferLength = len;
249
250 // Dump the RTCP packet to a file (if RTP dump is enabled).
251 if (_rtpDumpOut.DumpPacket((const WebRtc_UWord8*)data, len) == -1)
252 {
253 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254 VoEId(_instanceId,_channelId),
255 "Channel::SendPacket() RTCP dump to output file failed");
256 }
257
258 // SRTP or External encryption
259 if (_encrypting)
260 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000261 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
263 if (_encryptionPtr)
264 {
265 if (!_encryptionRTCPBufferPtr)
266 {
267 // Allocate memory for encryption buffer one time only
268 _encryptionRTCPBufferPtr =
269 new WebRtc_UWord8[kVoiceEngineMaxIpPacketSizeBytes];
270 }
271
272 // Perform encryption (SRTP or external).
273 WebRtc_Word32 encryptedBufferLength = 0;
274 _encryptionPtr->encrypt_rtcp(_channelId,
275 bufferToSendPtr,
276 _encryptionRTCPBufferPtr,
277 bufferLength,
278 (int*)&encryptedBufferLength);
279 if (encryptedBufferLength <= 0)
280 {
281 _engineStatisticsPtr->SetLastError(
282 VE_ENCRYPTION_FAILED, kTraceError,
283 "Channel::SendRTCPPacket() encryption failed");
284 return -1;
285 }
286
287 // Replace default data buffer with encrypted buffer
288 bufferToSendPtr = _encryptionRTCPBufferPtr;
289 bufferLength = encryptedBufferLength;
290 }
291 }
292
293 // Packet transmission using WebRtc socket transport
294 if (!_externalTransport)
295 {
296 int n = _transportPtr->SendRTCPPacket(channel,
297 bufferToSendPtr,
298 bufferLength);
299 if (n < 0)
300 {
301 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
302 VoEId(_instanceId,_channelId),
303 "Channel::SendRTCPPacket() transmission using WebRtc"
304 " sockets failed");
305 return -1;
306 }
307 return n;
308 }
309
310 // Packet transmission using external transport transport
311 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000312 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000313 if (_transportPtr == NULL)
314 {
315 return -1;
316 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 int n = _transportPtr->SendRTCPPacket(channel,
318 bufferToSendPtr,
319 bufferLength);
320 if (n < 0)
321 {
322 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
323 VoEId(_instanceId,_channelId),
324 "Channel::SendRTCPPacket() transmission using external"
325 " transport failed");
326 return -1;
327 }
328 return n;
329 }
330
331 return len;
332}
333
334void
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000335Channel::IncomingRTPPacket(const WebRtc_Word8* incomingRtpPacket,
336 const WebRtc_Word32 rtpPacketLength,
337 const char* fromIP,
338 const WebRtc_UWord16 fromPort)
339{
340 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
341 "Channel::IncomingRTPPacket(rtpPacketLength=%d,"
342 " fromIP=%s, fromPort=%u)",
343 rtpPacketLength, fromIP, fromPort);
344
345 // Store playout timestamp for the received RTP packet
346 // to be used for upcoming delay estimations
347 WebRtc_UWord32 playoutTimestamp(0);
348 if (GetPlayoutTimeStamp(playoutTimestamp) == 0)
349 {
350 _playoutTimeStampRTP = playoutTimestamp;
351 }
352
353 WebRtc_UWord8* rtpBufferPtr = (WebRtc_UWord8*)incomingRtpPacket;
354 WebRtc_Word32 rtpBufferLength = rtpPacketLength;
355
356 // SRTP or External decryption
357 if (_decrypting)
358 {
359 CriticalSectionScoped cs(&_callbackCritSect);
360
361 if (_encryptionPtr)
362 {
363 if (!_decryptionRTPBufferPtr)
364 {
365 // Allocate memory for decryption buffer one time only
366 _decryptionRTPBufferPtr =
367 new WebRtc_UWord8[kVoiceEngineMaxIpPacketSizeBytes];
368 }
369
370 // Perform decryption (SRTP or external)
371 WebRtc_Word32 decryptedBufferLength = 0;
372 _encryptionPtr->decrypt(_channelId,
373 rtpBufferPtr,
374 _decryptionRTPBufferPtr,
375 rtpBufferLength,
376 (int*)&decryptedBufferLength);
377 if (decryptedBufferLength <= 0)
378 {
379 _engineStatisticsPtr->SetLastError(
380 VE_DECRYPTION_FAILED, kTraceError,
381 "Channel::IncomingRTPPacket() decryption failed");
382 return;
383 }
384
385 // Replace default data buffer with decrypted buffer
386 rtpBufferPtr = _decryptionRTPBufferPtr;
387 rtpBufferLength = decryptedBufferLength;
388 }
389 }
390
391 // Dump the RTP packet to a file (if RTP dump is enabled).
392 if (_rtpDumpIn.DumpPacket(rtpBufferPtr,
393 (WebRtc_UWord16)rtpBufferLength) == -1)
394 {
395 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
396 VoEId(_instanceId,_channelId),
397 "Channel::SendPacket() RTP dump to input file failed");
398 }
399
400 // Deliver RTP packet to RTP/RTCP module for parsing
401 // The packet will be pushed back to the channel thru the
402 // OnReceivedPayloadData callback so we don't push it to the ACM here
403 if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)rtpBufferPtr,
404 (WebRtc_UWord16)rtpBufferLength) == -1)
405 {
406 _engineStatisticsPtr->SetLastError(
407 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
408 "Channel::IncomingRTPPacket() RTP packet is invalid");
409 return;
410 }
411}
412
413void
414Channel::IncomingRTCPPacket(const WebRtc_Word8* incomingRtcpPacket,
415 const WebRtc_Word32 rtcpPacketLength,
416 const char* fromIP,
417 const WebRtc_UWord16 fromPort)
418{
419 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
420 "Channel::IncomingRTCPPacket(rtcpPacketLength=%d, fromIP=%s,"
421 " fromPort=%u)",
422 rtcpPacketLength, fromIP, fromPort);
423
424 // Temporary buffer pointer and size for decryption
425 WebRtc_UWord8* rtcpBufferPtr = (WebRtc_UWord8*)incomingRtcpPacket;
426 WebRtc_Word32 rtcpBufferLength = rtcpPacketLength;
427
428 // Store playout timestamp for the received RTCP packet
429 // which will be read by the GetRemoteRTCPData API
430 WebRtc_UWord32 playoutTimestamp(0);
431 if (GetPlayoutTimeStamp(playoutTimestamp) == 0)
432 {
433 _playoutTimeStampRTCP = playoutTimestamp;
434 }
435
436 // SRTP or External decryption
437 if (_decrypting)
438 {
439 CriticalSectionScoped cs(&_callbackCritSect);
440
441 if (_encryptionPtr)
442 {
443 if (!_decryptionRTCPBufferPtr)
444 {
445 // Allocate memory for decryption buffer one time only
446 _decryptionRTCPBufferPtr =
447 new WebRtc_UWord8[kVoiceEngineMaxIpPacketSizeBytes];
448 }
449
450 // Perform decryption (SRTP or external).
451 WebRtc_Word32 decryptedBufferLength = 0;
452 _encryptionPtr->decrypt_rtcp(_channelId,
453 rtcpBufferPtr,
454 _decryptionRTCPBufferPtr,
455 rtcpBufferLength,
456 (int*)&decryptedBufferLength);
457 if (decryptedBufferLength <= 0)
458 {
459 _engineStatisticsPtr->SetLastError(
460 VE_DECRYPTION_FAILED, kTraceError,
461 "Channel::IncomingRTCPPacket() decryption failed");
462 return;
463 }
464
465 // Replace default data buffer with decrypted buffer
466 rtcpBufferPtr = _decryptionRTCPBufferPtr;
467 rtcpBufferLength = decryptedBufferLength;
468 }
469 }
470
471 // Dump the RTCP packet to a file (if RTP dump is enabled).
472 if (_rtpDumpIn.DumpPacket(rtcpBufferPtr,
473 (WebRtc_UWord16)rtcpBufferLength) == -1)
474 {
475 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
476 VoEId(_instanceId,_channelId),
477 "Channel::SendPacket() RTCP dump to input file failed");
478 }
479
480 // Deliver RTCP packet to RTP/RTCP module for parsing
481 if (_rtpRtcpModule->IncomingPacket((const WebRtc_UWord8*)rtcpBufferPtr,
482 (WebRtc_UWord16)rtcpBufferLength) == -1)
483 {
484 _engineStatisticsPtr->SetLastError(
485 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
486 "Channel::IncomingRTPPacket() RTCP packet is invalid");
487 return;
488 }
489}
490
491void
niklase@google.com470e71d2011-07-07 08:21:25 +0000492Channel::OnPlayTelephoneEvent(const WebRtc_Word32 id,
493 const WebRtc_UWord8 event,
494 const WebRtc_UWord16 lengthMs,
495 const WebRtc_UWord8 volume)
496{
497 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
498 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000499 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000500
501 if (!_playOutbandDtmfEvent || (event > 15))
502 {
503 // Ignore callback since feedback is disabled or event is not a
504 // Dtmf tone event.
505 return;
506 }
507
508 assert(_outputMixerPtr != NULL);
509
510 // Start playing out the Dtmf tone (if playout is enabled).
511 // Reduce length of tone with 80ms to the reduce risk of echo.
512 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
513}
514
515void
516Channel::OnIncomingSSRCChanged(const WebRtc_Word32 id,
517 const WebRtc_UWord32 SSRC)
518{
519 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
520 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
521 id, SSRC);
522
523 WebRtc_Word32 channel = VoEChannelId(id);
524 assert(channel == _channelId);
525
526 // Reset RTP-module counters since a new incoming RTP stream is detected
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000527 _rtpRtcpModule->ResetReceiveDataCountersRTP();
528 _rtpRtcpModule->ResetStatisticsRTP();
niklase@google.com470e71d2011-07-07 08:21:25 +0000529
530 if (_rtpObserver)
531 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000532 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000533
534 if (_rtpObserverPtr)
535 {
536 // Send new SSRC to registered observer using callback
537 _rtpObserverPtr->OnIncomingSSRCChanged(channel, SSRC);
538 }
539 }
540}
541
542void Channel::OnIncomingCSRCChanged(const WebRtc_Word32 id,
543 const WebRtc_UWord32 CSRC,
544 const bool added)
545{
546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
547 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
548 id, CSRC, added);
549
550 WebRtc_Word32 channel = VoEChannelId(id);
551 assert(channel == _channelId);
552
553 if (_rtpObserver)
554 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000555 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000556
557 if (_rtpObserverPtr)
558 {
559 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
560 }
561 }
562}
563
564void
565Channel::OnApplicationDataReceived(const WebRtc_Word32 id,
566 const WebRtc_UWord8 subType,
567 const WebRtc_UWord32 name,
568 const WebRtc_UWord16 length,
569 const WebRtc_UWord8* data)
570{
571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
572 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
573 " name=%u, length=%u)",
574 id, subType, name, length);
575
576 WebRtc_Word32 channel = VoEChannelId(id);
577 assert(channel == _channelId);
578
579 if (_rtcpObserver)
580 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000581 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000582
583 if (_rtcpObserverPtr)
584 {
585 _rtcpObserverPtr->OnApplicationDataReceived(channel,
586 subType,
587 name,
588 data,
589 length);
590 }
591 }
592}
593
594WebRtc_Word32
595Channel::OnInitializeDecoder(
596 const WebRtc_Word32 id,
597 const WebRtc_Word8 payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000598 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
xians@google.com0b0665a2011-08-08 08:18:44 +0000599 const int frequency,
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 const WebRtc_UWord8 channels,
601 const WebRtc_UWord32 rate)
602{
603 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
604 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
605 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
606 id, payloadType, payloadName, frequency, channels, rate);
607
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000608 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000609
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000610 CodecInst receiveCodec = {0};
611 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000612
613 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 receiveCodec.plfreq = frequency;
615 receiveCodec.channels = channels;
616 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000617 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000618
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000619 _audioCodingModule.Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 receiveCodec.pacsize = dummyCodec.pacsize;
621
622 // Register the new codec to the ACM
623 if (_audioCodingModule.RegisterReceiveCodec(receiveCodec) == -1)
624 {
625 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000626 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 "Channel::OnInitializeDecoder() invalid codec ("
628 "pt=%d, name=%s) received - 1", payloadType, payloadName);
629 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
630 return -1;
631 }
632
633 return 0;
634}
635
636void
637Channel::OnPacketTimeout(const WebRtc_Word32 id)
638{
639 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
640 "Channel::OnPacketTimeout(id=%d)", id);
641
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000642 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 if (_voiceEngineObserverPtr)
644 {
645 if (_receiving || _externalTransport)
646 {
647 WebRtc_Word32 channel = VoEChannelId(id);
648 assert(channel == _channelId);
649 // Ensure that next OnReceivedPacket() callback will trigger
650 // a VE_PACKET_RECEIPT_RESTARTED callback.
651 _rtpPacketTimedOut = true;
652 // Deliver callback to the observer
653 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
654 VoEId(_instanceId,_channelId),
655 "Channel::OnPacketTimeout() => "
656 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
657 _voiceEngineObserverPtr->CallbackOnError(channel,
658 VE_RECEIVE_PACKET_TIMEOUT);
659 }
660 }
661}
662
663void
664Channel::OnReceivedPacket(const WebRtc_Word32 id,
665 const RtpRtcpPacketType packetType)
666{
667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
668 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
669 id, packetType);
670
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000671 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672
673 // Notify only for the case when we have restarted an RTP session.
674 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
675 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000676 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 if (_voiceEngineObserverPtr)
678 {
679 WebRtc_Word32 channel = VoEChannelId(id);
680 assert(channel == _channelId);
681 // Reset timeout mechanism
682 _rtpPacketTimedOut = false;
683 // Deliver callback to the observer
684 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
685 VoEId(_instanceId,_channelId),
686 "Channel::OnPacketTimeout() =>"
687 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
688 _voiceEngineObserverPtr->CallbackOnError(
689 channel,
690 VE_PACKET_RECEIPT_RESTARTED);
691 }
692 }
693}
694
695void
696Channel::OnPeriodicDeadOrAlive(const WebRtc_Word32 id,
697 const RTPAliveType alive)
698{
699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
700 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
701
702 if (!_connectionObserver)
703 return;
704
705 WebRtc_Word32 channel = VoEChannelId(id);
706 assert(channel == _channelId);
707
708 // Use Alive as default to limit risk of false Dead detections
709 bool isAlive(true);
710
711 // Always mark the connection as Dead when the module reports kRtpDead
712 if (kRtpDead == alive)
713 {
714 isAlive = false;
715 }
716
717 // It is possible that the connection is alive even if no RTP packet has
718 // been received for a long time since the other side might use VAD/DTX
719 // and a low SID-packet update rate.
720 if ((kRtpNoRtp == alive) && _playing)
721 {
722 // Detect Alive for all NetEQ states except for the case when we are
723 // in PLC_CNG state.
724 // PLC_CNG <=> background noise only due to long expand or error.
725 // Note that, the case where the other side stops sending during CNG
726 // state will be detected as Alive. Dead is is not set until after
727 // missing RTCP packets for at least twelve seconds (handled
728 // internally by the RTP/RTCP module).
729 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
730 }
731
732 UpdateDeadOrAliveCounters(isAlive);
733
734 // Send callback to the registered observer
735 if (_connectionObserver)
736 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000737 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 if (_connectionObserverPtr)
739 {
740 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
741 }
742 }
743}
744
745WebRtc_Word32
746Channel::OnReceivedPayloadData(const WebRtc_UWord8* payloadData,
747 const WebRtc_UWord16 payloadSize,
748 const WebRtcRTPHeader* rtpHeader)
749{
750 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
751 "Channel::OnReceivedPayloadData(payloadSize=%d,"
752 " payloadType=%u, audioChannel=%u)",
753 payloadSize,
754 rtpHeader->header.payloadType,
755 rtpHeader->type.Audio.channel);
756
roosa@google.com0870f022012-12-12 21:31:41 +0000757 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
758
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 if (!_playing)
760 {
761 // Avoid inserting into NetEQ when we are not playing. Count the
762 // packet as discarded.
763 WEBRTC_TRACE(kTraceStream, kTraceVoice,
764 VoEId(_instanceId, _channelId),
765 "received packet is discarded since playing is not"
766 " activated");
767 _numberOfDiscardedPackets++;
768 return 0;
769 }
770
771 // Push the incoming payload (parsed and ready for decoding) into the ACM
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +0000772 if (_audioCodingModule.IncomingPacket(payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000773 payloadSize,
774 *rtpHeader) != 0)
775 {
776 _engineStatisticsPtr->SetLastError(
777 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
778 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
779 return -1;
780 }
781
782 // Update the packet delay
783 UpdatePacketDelay(rtpHeader->header.timestamp,
784 rtpHeader->header.sequenceNumber);
785
786 return 0;
787}
788
789WebRtc_Word32 Channel::GetAudioFrame(const WebRtc_Word32 id,
790 AudioFrame& audioFrame)
791{
792 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
793 "Channel::GetAudioFrame(id=%d)", id);
794
795 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000796 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000797 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 {
799 WEBRTC_TRACE(kTraceError, kTraceVoice,
800 VoEId(_instanceId,_channelId),
801 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000802 // In all likelihood, the audio in this frame is garbage. We return an
803 // error so that the audio mixer module doesn't add it to the mix. As
804 // a result, it won't be played out and the actions skipped here are
805 // irrelevant.
806 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 }
808
809 if (_RxVadDetection)
810 {
811 UpdateRxVadDetection(audioFrame);
812 }
813
814 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000815 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000817 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000818
819 // Perform far-end AudioProcessing module processing on the received signal
820 if (_rxApmIsEnabled)
821 {
822 ApmProcessRx(audioFrame);
823 }
824
825 // Output volume scaling
826 if (_outputGain < 0.99f || _outputGain > 1.01f)
827 {
828 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
829 }
830
831 // Scale left and/or right channel(s) if stereo and master balance is
832 // active
833
834 if (_panLeft != 1.0f || _panRight != 1.0f)
835 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000836 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 {
838 // Emulate stereo mode since panning is active.
839 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000840 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 }
842 // For true stereo mode (when we are receiving a stereo signal), no
843 // action is needed.
844
845 // Do the panning operation (the audio frame contains stereo at this
846 // stage)
847 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
848 }
849
850 // Mix decoded PCM output with file if file mixing is enabled
851 if (_outputFilePlaying)
852 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000853 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000854 }
855
856 // Place channel in on-hold state (~muted) if on-hold is activated
857 if (_outputIsOnHold)
858 {
859 AudioFrameOperations::Mute(audioFrame);
860 }
861
862 // External media
863 if (_outputExternalMedia)
864 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000865 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000866 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 if (_outputExternalMediaCallbackPtr)
868 {
869 _outputExternalMediaCallbackPtr->Process(
870 _channelId,
871 kPlaybackPerChannel,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000872 (WebRtc_Word16*)audioFrame.data_,
873 audioFrame.samples_per_channel_,
874 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 isStereo);
876 }
877 }
878
879 // Record playout if enabled
880 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000881 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000882
883 if (_outputFileRecording && _outputFileRecorderPtr)
884 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000885 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 }
887 }
888
889 // Measure audio level (0-9)
890 _outputAudioLevel.ComputeLevel(audioFrame);
891
892 return 0;
893}
894
895WebRtc_Word32
896Channel::NeededFrequency(const WebRtc_Word32 id)
897{
898 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
899 "Channel::NeededFrequency(id=%d)", id);
900
901 int highestNeeded = 0;
902
903 // Determine highest needed receive frequency
904 WebRtc_Word32 receiveFrequency = _audioCodingModule.ReceiveFrequency();
905
906 // Return the bigger of playout and receive frequency in the ACM.
907 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
908 {
909 highestNeeded = _audioCodingModule.PlayoutFrequency();
910 }
911 else
912 {
913 highestNeeded = receiveFrequency;
914 }
915
916 // Special case, if we're playing a file on the playout side
917 // we take that frequency into consideration as well
918 // This is not needed on sending side, since the codec will
919 // limit the spectrum anyway.
920 if (_outputFilePlaying)
921 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000922 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 if (_outputFilePlayerPtr && _outputFilePlaying)
924 {
925 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
926 {
927 highestNeeded=_outputFilePlayerPtr->Frequency();
928 }
929 }
930 }
931
932 return(highestNeeded);
933}
934
niklase@google.com470e71d2011-07-07 08:21:25 +0000935WebRtc_Word32
936Channel::CreateChannel(Channel*& channel,
937 const WebRtc_Word32 channelId,
938 const WebRtc_UWord32 instanceId)
939{
940 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
941 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
942 channelId, instanceId);
943
944 channel = new Channel(channelId, instanceId);
945 if (channel == NULL)
946 {
947 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
948 VoEId(instanceId,channelId),
949 "Channel::CreateChannel() unable to allocate memory for"
950 " channel");
951 return -1;
952 }
953 return 0;
954}
955
956void
957Channel::PlayNotification(const WebRtc_Word32 id,
958 const WebRtc_UWord32 durationMs)
959{
960 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
961 "Channel::PlayNotification(id=%d, durationMs=%d)",
962 id, durationMs);
963
964 // Not implement yet
965}
966
967void
968Channel::RecordNotification(const WebRtc_Word32 id,
969 const WebRtc_UWord32 durationMs)
970{
971 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
972 "Channel::RecordNotification(id=%d, durationMs=%d)",
973 id, durationMs);
974
975 // Not implement yet
976}
977
978void
979Channel::PlayFileEnded(const WebRtc_Word32 id)
980{
981 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
982 "Channel::PlayFileEnded(id=%d)", id);
983
984 if (id == _inputFilePlayerId)
985 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000986 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000987
988 _inputFilePlaying = false;
989 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
990 VoEId(_instanceId,_channelId),
991 "Channel::PlayFileEnded() => input file player module is"
992 " shutdown");
993 }
994 else if (id == _outputFilePlayerId)
995 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000996 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000997
998 _outputFilePlaying = false;
999 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1000 VoEId(_instanceId,_channelId),
1001 "Channel::PlayFileEnded() => output file player module is"
1002 " shutdown");
1003 }
1004}
1005
1006void
1007Channel::RecordFileEnded(const WebRtc_Word32 id)
1008{
1009 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1010 "Channel::RecordFileEnded(id=%d)", id);
1011
1012 assert(id == _outputFileRecorderId);
1013
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001014 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001015
1016 _outputFileRecording = false;
1017 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1018 VoEId(_instanceId,_channelId),
1019 "Channel::RecordFileEnded() => output file recorder module is"
1020 " shutdown");
1021}
1022
1023Channel::Channel(const WebRtc_Word32 channelId,
1024 const WebRtc_UWord32 instanceId) :
1025 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
1026 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +00001028 _channelId(channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +00001030 VoEModuleId(instanceId, channelId))),
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001031#ifndef WEBRTC_EXTERNAL_TRANSPORT
1032 _numSocketThreads(KNumSocketThreads),
1033 _socketTransportModule(*UdpTransport::Create(
1034 VoEModuleId(instanceId, channelId), _numSocketThreads)),
1035#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 _rtpDumpIn(*RtpDump::CreateRtpDump()),
1037 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 _inputFilePlayerPtr(NULL),
1041 _outputFilePlayerPtr(NULL),
1042 _outputFileRecorderPtr(NULL),
1043 // Avoid conflict with other channels by adding 1024 - 1026,
1044 // won't use as much as 1024 channels.
1045 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
1046 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
1047 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
1048 _inputFilePlaying(false),
1049 _outputFilePlaying(false),
1050 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +00001051 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
1052 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +00001054 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 _inputExternalMediaCallbackPtr(NULL),
1056 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +00001057 _encryptionRTPBufferPtr(NULL),
1058 _decryptionRTPBufferPtr(NULL),
1059 _encryptionRTCPBufferPtr(NULL),
1060 _decryptionRTCPBufferPtr(NULL),
1061 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
1062 _sendTelephoneEventPayloadType(106),
1063 _playoutTimeStampRTP(0),
1064 _playoutTimeStampRTCP(0),
1065 _numberOfDiscardedPackets(0),
1066 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +00001067 _outputMixerPtr(NULL),
1068 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +00001069 _moduleProcessThreadPtr(NULL),
1070 _audioDeviceModulePtr(NULL),
1071 _voiceEngineObserverPtr(NULL),
1072 _callbackCritSectPtr(NULL),
1073 _transportPtr(NULL),
1074 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001075 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +00001076 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +00001077 _rxVadObserverPtr(NULL),
1078 _oldVadDecision(-1),
1079 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 _rtpObserverPtr(NULL),
1081 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +00001082 _outputIsOnHold(false),
1083 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001084 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +00001085 _inputIsOnHold(false),
1086 _playing(false),
1087 _sending(false),
1088 _receiving(false),
1089 _mixFileWithMicrophone(false),
1090 _rtpObserver(false),
1091 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 _mute(false),
1093 _panLeft(1.0f),
1094 _panRight(1.0f),
1095 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +00001096 _encrypting(false),
1097 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 _playOutbandDtmfEvent(false),
1099 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 _extraPayloadType(0),
1101 _insertExtraRTPPacket(false),
1102 _extraMarkerBit(false),
1103 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +00001104 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +00001106 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 _rtpPacketTimedOut(false),
1108 _rtpPacketTimeOutIsEnabled(false),
1109 _rtpTimeOutSeconds(0),
1110 _connectionObserver(false),
1111 _connectionObserverPtr(NULL),
1112 _countAliveDetections(0),
1113 _countDeadDetections(0),
1114 _outputSpeechType(AudioFrame::kNormalSpeech),
1115 _averageDelayMs(0),
1116 _previousSequenceNumber(0),
1117 _previousTimestamp(0),
1118 _recPacketDelayMs(20),
1119 _RxVadDetection(false),
1120 _rxApmIsEnabled(false),
1121 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +00001122 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001123{
1124 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1125 "Channel::Channel() - ctor");
1126 _inbandDtmfQueue.ResetDtmf();
1127 _inbandDtmfGenerator.Init();
1128 _outputAudioLevel.Clear();
1129
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001130 RtpRtcp::Configuration configuration;
1131 configuration.id = VoEModuleId(instanceId, channelId);
1132 configuration.audio = true;
1133 configuration.incoming_data = this;
1134 configuration.incoming_messages = this;
1135 configuration.outgoing_transport = this;
1136 configuration.rtcp_feedback = this;
1137 configuration.audio_messages = this;
1138
1139 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
1140
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 // Create far end AudioProcessing Module
1142 _rxAudioProcessingModulePtr = AudioProcessing::Create(
1143 VoEModuleId(instanceId, channelId));
1144}
1145
1146Channel::~Channel()
1147{
1148 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1149 "Channel::~Channel() - dtor");
1150
1151 if (_outputExternalMedia)
1152 {
1153 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1154 }
1155 if (_inputExternalMedia)
1156 {
1157 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1158 }
1159 StopSend();
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001160#ifndef WEBRTC_EXTERNAL_TRANSPORT
1161 StopReceiving();
1162 // De-register packet callback to ensure we're not in a callback when
1163 // deleting channel state, avoids race condition and deadlock.
1164 if (_socketTransportModule.InitializeReceiveSockets(NULL, 0, NULL, NULL, 0)
1165 != 0)
1166 {
1167 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1168 VoEId(_instanceId, _channelId),
1169 "~Channel() failed to de-register receive callback");
1170 }
1171#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 StopPlayout();
1173
1174 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001175 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 if (_inputFilePlayerPtr)
1177 {
1178 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1179 _inputFilePlayerPtr->StopPlayingFile();
1180 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1181 _inputFilePlayerPtr = NULL;
1182 }
1183 if (_outputFilePlayerPtr)
1184 {
1185 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1186 _outputFilePlayerPtr->StopPlayingFile();
1187 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1188 _outputFilePlayerPtr = NULL;
1189 }
1190 if (_outputFileRecorderPtr)
1191 {
1192 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1193 _outputFileRecorderPtr->StopRecording();
1194 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1195 _outputFileRecorderPtr = NULL;
1196 }
1197 }
1198
1199 // The order to safely shutdown modules in a channel is:
1200 // 1. De-register callbacks in modules
1201 // 2. De-register modules in process thread
1202 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1204 {
1205 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1206 VoEId(_instanceId,_channelId),
1207 "~Channel() failed to de-register transport callback"
1208 " (Audio coding module)");
1209 }
1210 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1211 {
1212 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1213 VoEId(_instanceId,_channelId),
1214 "~Channel() failed to de-register VAD callback"
1215 " (Audio coding module)");
1216 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 // De-register modules in process thread
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001218#ifndef WEBRTC_EXTERNAL_TRANSPORT
1219 if (_moduleProcessThreadPtr->DeRegisterModule(&_socketTransportModule)
1220 == -1)
1221 {
1222 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1223 VoEId(_instanceId,_channelId),
1224 "~Channel() failed to deregister socket module");
1225 }
1226#endif
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001227 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001228 {
1229 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1230 VoEId(_instanceId,_channelId),
1231 "~Channel() failed to deregister RTP/RTCP module");
1232 }
1233
1234 // Destroy modules
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001235#ifndef WEBRTC_EXTERNAL_TRANSPORT
1236 UdpTransport::Destroy(
1237 &_socketTransportModule);
1238#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001239 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 if (_rxAudioProcessingModulePtr != NULL)
1241 {
1242 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1243 _rxAudioProcessingModulePtr = NULL;
1244 }
1245
1246 // End of modules shutdown
1247
1248 // Delete other objects
1249 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1250 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1251 delete [] _encryptionRTPBufferPtr;
1252 delete [] _decryptionRTPBufferPtr;
1253 delete [] _encryptionRTCPBufferPtr;
1254 delete [] _decryptionRTCPBufferPtr;
1255 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 delete &_fileCritSect;
1257}
1258
1259WebRtc_Word32
1260Channel::Init()
1261{
1262 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1263 "Channel::Init()");
1264
1265 // --- Initial sanity
1266
1267 if ((_engineStatisticsPtr == NULL) ||
1268 (_moduleProcessThreadPtr == NULL))
1269 {
1270 WEBRTC_TRACE(kTraceError, kTraceVoice,
1271 VoEId(_instanceId,_channelId),
1272 "Channel::Init() must call SetEngineInformation() first");
1273 return -1;
1274 }
1275
1276 // --- Add modules to process thread (for periodic schedulation)
1277
1278 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001279 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001280#ifndef WEBRTC_EXTERNAL_TRANSPORT
1281 (_moduleProcessThreadPtr->RegisterModule(
1282 &_socketTransportModule) != 0));
1283#else
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 false);
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001285#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001286 if (processThreadFail)
1287 {
1288 _engineStatisticsPtr->SetLastError(
1289 VE_CANNOT_INIT_CHANNEL, kTraceError,
1290 "Channel::Init() modules not registered");
1291 return -1;
1292 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001293 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001294
1295 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1296#ifdef WEBRTC_CODEC_AVT
1297 // out-of-band Dtmf tones are played out by default
1298 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1299#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 (_audioCodingModule.InitializeSender() == -1))
1301 {
1302 _engineStatisticsPtr->SetLastError(
1303 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1304 "Channel::Init() unable to initialize the ACM - 1");
1305 return -1;
1306 }
1307
1308 // --- RTP/RTCP module initialization
1309
1310 // Ensure that RTCP is enabled by default for the created channel.
1311 // Note that, the module will keep generating RTCP until it is explicitly
1312 // disabled by the user.
1313 // After StopListen (when no sockets exists), RTCP packets will no longer
1314 // be transmitted since the Transport object will then be invalid.
1315
1316 const bool rtpRtcpFail =
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001317 ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 // RTCP is enabled by default
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001319 (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
niklase@google.com470e71d2011-07-07 08:21:25 +00001320 if (rtpRtcpFail)
1321 {
1322 _engineStatisticsPtr->SetLastError(
1323 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1324 "Channel::Init() RTP/RTCP module not initialized");
1325 return -1;
1326 }
1327
1328 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001329 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1331 (_audioCodingModule.RegisterVADCallback(this) == -1);
1332
1333 if (fail)
1334 {
1335 _engineStatisticsPtr->SetLastError(
1336 VE_CANNOT_INIT_CHANNEL, kTraceError,
1337 "Channel::Init() callbacks not registered");
1338 return -1;
1339 }
1340
1341 // --- Register all supported codecs to the receiving side of the
1342 // RTP/RTCP module
1343
1344 CodecInst codec;
1345 const WebRtc_UWord8 nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
1346
1347 for (int idx = 0; idx < nSupportedCodecs; idx++)
1348 {
1349 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001350 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001351 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 {
1353 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1354 VoEId(_instanceId,_channelId),
1355 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1356 "to RTP/RTCP receiver",
1357 codec.plname, codec.pltype, codec.plfreq,
1358 codec.channels, codec.rate);
1359 }
1360 else
1361 {
1362 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1363 VoEId(_instanceId,_channelId),
1364 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1365 "the RTP/RTCP receiver",
1366 codec.plname, codec.pltype, codec.plfreq,
1367 codec.channels, codec.rate);
1368 }
1369
1370 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001371 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 {
1373 SetSendCodec(codec);
1374 }
1375
1376 // Register default PT for outband 'telephone-event'
1377 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1378 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001379 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001380 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1381 {
1382 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1383 VoEId(_instanceId,_channelId),
1384 "Channel::Init() failed to register outband "
1385 "'telephone-event' (%d/%d) correctly",
1386 codec.pltype, codec.plfreq);
1387 }
1388 }
1389
1390 if (!STR_CASE_CMP(codec.plname, "CN"))
1391 {
1392 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1393 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001394 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 {
1396 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1397 VoEId(_instanceId,_channelId),
1398 "Channel::Init() failed to register CN (%d/%d) "
1399 "correctly - 1",
1400 codec.pltype, codec.plfreq);
1401 }
1402 }
1403#ifdef WEBRTC_CODEC_RED
1404 // Register RED to the receiving side of the ACM.
1405 // We will not receive an OnInitializeDecoder() callback for RED.
1406 if (!STR_CASE_CMP(codec.plname, "RED"))
1407 {
1408 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1409 {
1410 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1411 VoEId(_instanceId,_channelId),
1412 "Channel::Init() failed to register RED (%d/%d) "
1413 "correctly",
1414 codec.pltype, codec.plfreq);
1415 }
1416 }
1417#endif
1418 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001419#ifndef WEBRTC_EXTERNAL_TRANSPORT
1420 // Ensure that the WebRtcSocketTransport implementation is used as
1421 // Transport on the sending side
1422 {
1423 // A lock is needed here since users can call
1424 // RegisterExternalTransport() at the same time.
1425 CriticalSectionScoped cs(&_callbackCritSect);
1426 _transportPtr = &_socketTransportModule;
1427 }
1428#endif
1429
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 // Initialize the far end AP module
1431 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1432 // changed at the first receiving audio.
1433 if (_rxAudioProcessingModulePtr == NULL)
1434 {
1435 _engineStatisticsPtr->SetLastError(
1436 VE_NO_MEMORY, kTraceCritical,
1437 "Channel::Init() failed to create the far-end AudioProcessing"
1438 " module");
1439 return -1;
1440 }
1441
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1443 {
1444 _engineStatisticsPtr->SetLastError(
1445 VE_APM_ERROR, kTraceWarning,
1446 "Channel::Init() failed to set the sample rate to 8K for"
1447 " far-end AP module");
1448 }
1449
1450 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1451 {
1452 _engineStatisticsPtr->SetLastError(
1453 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001454 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 }
1456
1457 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1458 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1459 {
1460 _engineStatisticsPtr->SetLastError(
1461 VE_APM_ERROR, kTraceWarning,
1462 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001463 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 }
1465
1466 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1467 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1468 {
1469 _engineStatisticsPtr->SetLastError(
1470 VE_APM_ERROR, kTraceWarning,
1471 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001472 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 }
1474 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1475 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1476 {
1477 _engineStatisticsPtr->SetLastError(
1478 VE_APM_ERROR, kTraceWarning,
1479 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001480 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 }
1482
1483 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1484 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1485 {
1486 _engineStatisticsPtr->SetLastError(
1487 VE_APM_ERROR, kTraceWarning,
1488 "Init() failed to set AGC mode for far-end AP module");
1489 }
1490 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1491 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1492 {
1493 _engineStatisticsPtr->SetLastError(
1494 VE_APM_ERROR, kTraceWarning,
1495 "Init() failed to set AGC state for far-end AP module");
1496 }
1497
1498 return 0;
1499}
1500
1501WebRtc_Word32
1502Channel::SetEngineInformation(Statistics& engineStatistics,
1503 OutputMixer& outputMixer,
1504 voe::TransmitMixer& transmitMixer,
1505 ProcessThread& moduleProcessThread,
1506 AudioDeviceModule& audioDeviceModule,
1507 VoiceEngineObserver* voiceEngineObserver,
1508 CriticalSectionWrapper* callbackCritSect)
1509{
1510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1511 "Channel::SetEngineInformation()");
1512 _engineStatisticsPtr = &engineStatistics;
1513 _outputMixerPtr = &outputMixer;
1514 _transmitMixerPtr = &transmitMixer,
1515 _moduleProcessThreadPtr = &moduleProcessThread;
1516 _audioDeviceModulePtr = &audioDeviceModule;
1517 _voiceEngineObserverPtr = voiceEngineObserver;
1518 _callbackCritSectPtr = callbackCritSect;
1519 return 0;
1520}
1521
1522WebRtc_Word32
1523Channel::UpdateLocalTimeStamp()
1524{
1525
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001526 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 return 0;
1528}
1529
1530WebRtc_Word32
1531Channel::StartPlayout()
1532{
1533 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1534 "Channel::StartPlayout()");
1535 if (_playing)
1536 {
1537 return 0;
1538 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001539
1540 if (!_externalMixing) {
1541 // Add participant as candidates for mixing.
1542 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1543 {
1544 _engineStatisticsPtr->SetLastError(
1545 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1546 "StartPlayout() failed to add participant to mixer");
1547 return -1;
1548 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001549 }
1550
1551 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001552
1553 if (RegisterFilePlayingToMixer() != 0)
1554 return -1;
1555
niklase@google.com470e71d2011-07-07 08:21:25 +00001556 return 0;
1557}
1558
1559WebRtc_Word32
1560Channel::StopPlayout()
1561{
1562 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1563 "Channel::StopPlayout()");
1564 if (!_playing)
1565 {
1566 return 0;
1567 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001568
1569 if (!_externalMixing) {
1570 // Remove participant as candidates for mixing
1571 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1572 {
1573 _engineStatisticsPtr->SetLastError(
1574 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1575 "StopPlayout() failed to remove participant from mixer");
1576 return -1;
1577 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001578 }
1579
1580 _playing = false;
1581 _outputAudioLevel.Clear();
1582
1583 return 0;
1584}
1585
1586WebRtc_Word32
1587Channel::StartSend()
1588{
1589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001591 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001592 // A lock is needed because |_sending| can be accessed or modified by
1593 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001594 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001595
1596 if (_sending)
1597 {
1598 return 0;
1599 }
1600 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001601 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001602
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001603 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001604 {
1605 _engineStatisticsPtr->SetLastError(
1606 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1607 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001608 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001609 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001610 return -1;
1611 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001612
niklase@google.com470e71d2011-07-07 08:21:25 +00001613 return 0;
1614}
1615
1616WebRtc_Word32
1617Channel::StopSend()
1618{
1619 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1620 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001622 // A lock is needed because |_sending| can be accessed or modified by
1623 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001624 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001625
1626 if (!_sending)
1627 {
1628 return 0;
1629 }
1630 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001631 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001632
niklase@google.com470e71d2011-07-07 08:21:25 +00001633 // Reset sending SSRC and sequence number and triggers direct transmission
1634 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001635 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1636 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001637 {
1638 _engineStatisticsPtr->SetLastError(
1639 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1640 "StartSend() RTP/RTCP failed to stop sending");
1641 }
1642
niklase@google.com470e71d2011-07-07 08:21:25 +00001643 return 0;
1644}
1645
1646WebRtc_Word32
1647Channel::StartReceiving()
1648{
1649 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1650 "Channel::StartReceiving()");
1651 if (_receiving)
1652 {
1653 return 0;
1654 }
1655 // If external transport is used, we will only initialize/set the variables
1656 // after this section, since we are not using the WebRtc transport but
1657 // still need to keep track of e.g. if we are receiving.
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001658#ifndef WEBRTC_EXTERNAL_TRANSPORT
1659 if (!_externalTransport)
1660 {
1661 if (!_socketTransportModule.ReceiveSocketsInitialized())
1662 {
1663 _engineStatisticsPtr->SetLastError(
1664 VE_SOCKETS_NOT_INITED, kTraceError,
1665 "StartReceive() must set local receiver first");
1666 return -1;
1667 }
1668 if (_socketTransportModule.StartReceiving(KNumberOfSocketBuffers) != 0)
1669 {
1670 _engineStatisticsPtr->SetLastError(
1671 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
1672 "StartReceiving() failed to start receiving");
1673 return -1;
1674 }
1675 }
1676#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001677 _receiving = true;
1678 _numberOfDiscardedPackets = 0;
1679 return 0;
1680}
1681
1682WebRtc_Word32
1683Channel::StopReceiving()
1684{
1685 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1686 "Channel::StopReceiving()");
1687 if (!_receiving)
1688 {
1689 return 0;
1690 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001691
1692#ifndef WEBRTC_EXTERNAL_TRANSPORT
1693 if (!_externalTransport &&
1694 _socketTransportModule.ReceiveSocketsInitialized())
1695 {
1696 if (_socketTransportModule.StopReceiving() != 0)
1697 {
1698 _engineStatisticsPtr->SetLastError(
1699 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
1700 "StopReceiving() failed to stop receiving.");
1701 return -1;
1702 }
1703 }
1704#endif
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001705 // Recover DTMF detection status.
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001706 WebRtc_Word32 ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001707 if (ret != 0) {
1708 _engineStatisticsPtr->SetLastError(
1709 VE_INVALID_OPERATION, kTraceWarning,
1710 "StopReceiving() failed to restore telephone-event status.");
1711 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001712 RegisterReceiveCodecsToRTPModule();
1713 _receiving = false;
1714 return 0;
1715}
1716
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001717#ifndef WEBRTC_EXTERNAL_TRANSPORT
1718WebRtc_Word32
1719Channel::SetLocalReceiver(const WebRtc_UWord16 rtpPort,
1720 const WebRtc_UWord16 rtcpPort,
1721 const char ipAddr[64],
1722 const char multicastIpAddr[64])
1723{
1724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1725 "Channel::SetLocalReceiver()");
1726
1727 if (_externalTransport)
1728 {
1729 _engineStatisticsPtr->SetLastError(
1730 VE_EXTERNAL_TRANSPORT_ENABLED, kTraceError,
1731 "SetLocalReceiver() conflict with external transport");
1732 return -1;
1733 }
1734
1735 if (_sending)
1736 {
1737 _engineStatisticsPtr->SetLastError(
1738 VE_ALREADY_SENDING, kTraceError,
1739 "SetLocalReceiver() already sending");
1740 return -1;
1741 }
1742 if (_receiving)
1743 {
1744 _engineStatisticsPtr->SetLastError(
1745 VE_ALREADY_LISTENING, kTraceError,
1746 "SetLocalReceiver() already receiving");
1747 return -1;
1748 }
1749
1750 if (_socketTransportModule.InitializeReceiveSockets(this,
1751 rtpPort,
1752 ipAddr,
1753 multicastIpAddr,
1754 rtcpPort) != 0)
1755 {
1756 UdpTransport::ErrorCode lastSockError(
1757 _socketTransportModule.LastError());
1758 switch (lastSockError)
1759 {
1760 case UdpTransport::kIpAddressInvalid:
1761 _engineStatisticsPtr->SetLastError(
1762 VE_INVALID_IP_ADDRESS, kTraceError,
1763 "SetLocalReceiver() invalid IP address");
1764 break;
1765 case UdpTransport::kSocketInvalid:
1766 _engineStatisticsPtr->SetLastError(
1767 VE_SOCKET_ERROR, kTraceError,
1768 "SetLocalReceiver() invalid socket");
1769 break;
1770 case UdpTransport::kPortInvalid:
1771 _engineStatisticsPtr->SetLastError(
1772 VE_INVALID_PORT_NMBR, kTraceError,
1773 "SetLocalReceiver() invalid port");
1774 break;
1775 case UdpTransport::kFailedToBindPort:
1776 _engineStatisticsPtr->SetLastError(
1777 VE_BINDING_SOCKET_TO_LOCAL_ADDRESS_FAILED, kTraceError,
1778 "SetLocalReceiver() binding failed");
1779 break;
1780 default:
1781 _engineStatisticsPtr->SetLastError(
1782 VE_SOCKET_ERROR, kTraceError,
1783 "SetLocalReceiver() undefined socket error");
1784 break;
1785 }
1786 return -1;
1787 }
1788 return 0;
1789}
1790#endif
1791
1792#ifndef WEBRTC_EXTERNAL_TRANSPORT
1793WebRtc_Word32
1794Channel::GetLocalReceiver(int& port, int& RTCPport, char ipAddr[64])
1795{
1796 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1797 "Channel::GetLocalReceiver()");
1798
1799 if (_externalTransport)
1800 {
1801 _engineStatisticsPtr->SetLastError(
1802 VE_EXTERNAL_TRANSPORT_ENABLED, kTraceError,
1803 "SetLocalReceiver() conflict with external transport");
1804 return -1;
1805 }
1806
1807 char ipAddrTmp[UdpTransport::kIpAddressVersion6Length] = {0};
1808 WebRtc_UWord16 rtpPort(0);
1809 WebRtc_UWord16 rtcpPort(0);
1810 char multicastIpAddr[UdpTransport::kIpAddressVersion6Length] = {0};
1811
1812 // Acquire socket information from the socket module
1813 if (_socketTransportModule.ReceiveSocketInformation(ipAddrTmp,
1814 rtpPort,
1815 rtcpPort,
1816 multicastIpAddr) != 0)
1817 {
1818 _engineStatisticsPtr->SetLastError(
1819 VE_CANNOT_GET_SOCKET_INFO, kTraceError,
1820 "GetLocalReceiver() unable to retrieve socket information");
1821 return -1;
1822 }
1823
1824 // Deliver valid results to the user
1825 port = static_cast<int> (rtpPort);
1826 RTCPport = static_cast<int> (rtcpPort);
1827 if (ipAddr != NULL)
1828 {
1829 strcpy(ipAddr, ipAddrTmp);
1830 }
1831 return 0;
1832}
1833#endif
1834
1835#ifndef WEBRTC_EXTERNAL_TRANSPORT
1836WebRtc_Word32
1837Channel::SetSendDestination(const WebRtc_UWord16 rtpPort,
1838 const char ipAddr[64],
1839 const int sourcePort,
1840 const WebRtc_UWord16 rtcpPort)
1841{
1842 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1843 "Channel::SetSendDestination()");
1844
1845 if (_externalTransport)
1846 {
1847 _engineStatisticsPtr->SetLastError(
1848 VE_EXTERNAL_TRANSPORT_ENABLED, kTraceError,
1849 "SetSendDestination() conflict with external transport");
1850 return -1;
1851 }
1852
1853 // Initialize ports and IP address for the remote (destination) side.
1854 // By default, the sockets used for receiving are used for transmission as
1855 // well, hence the source ports for outgoing packets are the same as the
1856 // receiving ports specified in SetLocalReceiver.
1857 // If an extra send socket has been created, it will be utilized until a
1858 // new source port is specified or until the channel has been deleted and
1859 // recreated. If no socket exists, sockets will be created when the first
1860 // RTP and RTCP packets shall be transmitted (see e.g.
1861 // UdpTransportImpl::SendPacket()).
1862 //
1863 // NOTE: this function does not require that sockets exists; all it does is
1864 // to build send structures to be used with the sockets when they exist.
1865 // It is therefore possible to call this method before SetLocalReceiver.
1866 // However, sockets must exist if a multi-cast address is given as input.
1867
1868 // Build send structures and enable QoS (if enabled and supported)
1869 if (_socketTransportModule.InitializeSendSockets(
1870 ipAddr, rtpPort, rtcpPort) != UdpTransport::kNoSocketError)
1871 {
1872 UdpTransport::ErrorCode lastSockError(
1873 _socketTransportModule.LastError());
1874 switch (lastSockError)
1875 {
1876 case UdpTransport::kIpAddressInvalid:
1877 _engineStatisticsPtr->SetLastError(
1878 VE_INVALID_IP_ADDRESS, kTraceError,
1879 "SetSendDestination() invalid IP address 1");
1880 break;
1881 case UdpTransport::kSocketInvalid:
1882 _engineStatisticsPtr->SetLastError(
1883 VE_SOCKET_ERROR, kTraceError,
1884 "SetSendDestination() invalid socket 1");
1885 break;
1886 case UdpTransport::kQosError:
1887 _engineStatisticsPtr->SetLastError(
1888 VE_GQOS_ERROR, kTraceError,
1889 "SetSendDestination() failed to set QoS");
1890 break;
1891 case UdpTransport::kMulticastAddressInvalid:
1892 _engineStatisticsPtr->SetLastError(
1893 VE_INVALID_MULTICAST_ADDRESS, kTraceError,
1894 "SetSendDestination() invalid multicast address");
1895 break;
1896 default:
1897 _engineStatisticsPtr->SetLastError(
1898 VE_SOCKET_ERROR, kTraceError,
1899 "SetSendDestination() undefined socket error 1");
1900 break;
1901 }
1902 return -1;
1903 }
1904
1905 // Check if the user has specified a non-default source port different from
1906 // the local receive port.
1907 // If so, an extra local socket will be created unless the source port is
1908 // not unique.
1909 if (sourcePort != kVoEDefault)
1910 {
1911 WebRtc_UWord16 receiverRtpPort(0);
1912 WebRtc_UWord16 rtcpNA(0);
1913 if (_socketTransportModule.ReceiveSocketInformation(NULL,
1914 receiverRtpPort,
1915 rtcpNA,
1916 NULL) != 0)
1917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_CANNOT_GET_SOCKET_INFO, kTraceError,
1920 "SetSendDestination() failed to retrieve socket information");
1921 return -1;
1922 }
1923
1924 WebRtc_UWord16 sourcePortUW16 =
1925 static_cast<WebRtc_UWord16> (sourcePort);
1926
1927 // An extra socket will only be created if the specified source port
1928 // differs from the local receive port.
1929 if (sourcePortUW16 != receiverRtpPort)
1930 {
1931 // Initialize extra local socket to get a different source port
1932 // than the local
1933 // receiver port. Always use default source for RTCP.
1934 // Note that, this calls UdpTransport::CloseSendSockets().
1935 if (_socketTransportModule.InitializeSourcePorts(
1936 sourcePortUW16,
1937 sourcePortUW16+1) != 0)
1938 {
1939 UdpTransport::ErrorCode lastSockError(
1940 _socketTransportModule.LastError());
1941 switch (lastSockError)
1942 {
1943 case UdpTransport::kIpAddressInvalid:
1944 _engineStatisticsPtr->SetLastError(
1945 VE_INVALID_IP_ADDRESS, kTraceError,
1946 "SetSendDestination() invalid IP address 2");
1947 break;
1948 case UdpTransport::kSocketInvalid:
1949 _engineStatisticsPtr->SetLastError(
1950 VE_SOCKET_ERROR, kTraceError,
1951 "SetSendDestination() invalid socket 2");
1952 break;
1953 default:
1954 _engineStatisticsPtr->SetLastError(
1955 VE_SOCKET_ERROR, kTraceError,
1956 "SetSendDestination() undefined socket error 2");
1957 break;
1958 }
1959 return -1;
1960 }
1961 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1962 VoEId(_instanceId,_channelId),
1963 "SetSendDestination() extra local socket is created"
1964 " to facilitate unique source port");
1965 }
1966 else
1967 {
1968 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1969 VoEId(_instanceId,_channelId),
1970 "SetSendDestination() sourcePort equals the local"
1971 " receive port => no extra socket is created");
1972 }
1973 }
1974
1975 return 0;
1976}
1977#endif
1978
1979#ifndef WEBRTC_EXTERNAL_TRANSPORT
1980WebRtc_Word32
1981Channel::GetSendDestination(int& port,
1982 char ipAddr[64],
1983 int& sourcePort,
1984 int& RTCPport)
1985{
1986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1987 "Channel::GetSendDestination()");
1988
1989 if (_externalTransport)
1990 {
1991 _engineStatisticsPtr->SetLastError(
1992 VE_EXTERNAL_TRANSPORT_ENABLED, kTraceError,
1993 "GetSendDestination() conflict with external transport");
1994 return -1;
1995 }
1996
1997 char ipAddrTmp[UdpTransport::kIpAddressVersion6Length] = {0};
1998 WebRtc_UWord16 rtpPort(0);
1999 WebRtc_UWord16 rtcpPort(0);
2000 WebRtc_UWord16 rtpSourcePort(0);
2001 WebRtc_UWord16 rtcpSourcePort(0);
2002
2003 // Acquire sending socket information from the socket module
2004 _socketTransportModule.SendSocketInformation(ipAddrTmp, rtpPort, rtcpPort);
2005 _socketTransportModule.SourcePorts(rtpSourcePort, rtcpSourcePort);
2006
2007 // Deliver valid results to the user
2008 port = static_cast<int> (rtpPort);
2009 RTCPport = static_cast<int> (rtcpPort);
2010 sourcePort = static_cast<int> (rtpSourcePort);
2011 if (ipAddr != NULL)
2012 {
2013 strcpy(ipAddr, ipAddrTmp);
2014 }
2015
2016 return 0;
2017}
2018#endif
2019
2020
niklase@google.com470e71d2011-07-07 08:21:25 +00002021WebRtc_Word32
2022Channel::SetNetEQPlayoutMode(NetEqModes mode)
2023{
2024 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2025 "Channel::SetNetEQPlayoutMode()");
2026 AudioPlayoutMode playoutMode(voice);
2027 switch (mode)
2028 {
2029 case kNetEqDefault:
2030 playoutMode = voice;
2031 break;
2032 case kNetEqStreaming:
2033 playoutMode = streaming;
2034 break;
2035 case kNetEqFax:
2036 playoutMode = fax;
2037 break;
roosa@google.comb7186192012-12-12 21:59:14 +00002038 case kNetEqOff:
2039 playoutMode = off;
2040 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002041 }
2042 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
2043 {
2044 _engineStatisticsPtr->SetLastError(
2045 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2046 "SetNetEQPlayoutMode() failed to set playout mode");
2047 return -1;
2048 }
2049 return 0;
2050}
2051
2052WebRtc_Word32
2053Channel::GetNetEQPlayoutMode(NetEqModes& mode)
2054{
2055 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
2056 switch (playoutMode)
2057 {
2058 case voice:
2059 mode = kNetEqDefault;
2060 break;
2061 case streaming:
2062 mode = kNetEqStreaming;
2063 break;
2064 case fax:
2065 mode = kNetEqFax;
2066 break;
roosa@google.comb7186192012-12-12 21:59:14 +00002067 case off:
2068 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00002069 }
2070 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2071 VoEId(_instanceId,_channelId),
2072 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
2073 return 0;
2074}
2075
2076WebRtc_Word32
niklase@google.com470e71d2011-07-07 08:21:25 +00002077Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
2078{
2079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2080 "Channel::SetOnHoldStatus()");
2081 if (mode == kHoldSendAndPlay)
2082 {
2083 _outputIsOnHold = enable;
2084 _inputIsOnHold = enable;
2085 }
2086 else if (mode == kHoldPlayOnly)
2087 {
2088 _outputIsOnHold = enable;
2089 }
2090 if (mode == kHoldSendOnly)
2091 {
2092 _inputIsOnHold = enable;
2093 }
2094 return 0;
2095}
2096
2097WebRtc_Word32
2098Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
2099{
2100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2101 "Channel::GetOnHoldStatus()");
2102 enabled = (_outputIsOnHold || _inputIsOnHold);
2103 if (_outputIsOnHold && _inputIsOnHold)
2104 {
2105 mode = kHoldSendAndPlay;
2106 }
2107 else if (_outputIsOnHold && !_inputIsOnHold)
2108 {
2109 mode = kHoldPlayOnly;
2110 }
2111 else if (!_outputIsOnHold && _inputIsOnHold)
2112 {
2113 mode = kHoldSendOnly;
2114 }
2115 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2116 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
2117 enabled, mode);
2118 return 0;
2119}
2120
2121WebRtc_Word32
2122Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
2123{
2124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2125 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002126 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002127
2128 if (_voiceEngineObserverPtr)
2129 {
2130 _engineStatisticsPtr->SetLastError(
2131 VE_INVALID_OPERATION, kTraceError,
2132 "RegisterVoiceEngineObserver() observer already enabled");
2133 return -1;
2134 }
2135 _voiceEngineObserverPtr = &observer;
2136 return 0;
2137}
2138
2139WebRtc_Word32
2140Channel::DeRegisterVoiceEngineObserver()
2141{
2142 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2143 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002144 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002145
2146 if (!_voiceEngineObserverPtr)
2147 {
2148 _engineStatisticsPtr->SetLastError(
2149 VE_INVALID_OPERATION, kTraceWarning,
2150 "DeRegisterVoiceEngineObserver() observer already disabled");
2151 return 0;
2152 }
2153 _voiceEngineObserverPtr = NULL;
2154 return 0;
2155}
2156
2157WebRtc_Word32
niklase@google.com470e71d2011-07-07 08:21:25 +00002158Channel::GetSendCodec(CodecInst& codec)
2159{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002160 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00002161}
2162
2163WebRtc_Word32
2164Channel::GetRecCodec(CodecInst& codec)
2165{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002166 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00002167}
2168
2169WebRtc_Word32
2170Channel::SetSendCodec(const CodecInst& codec)
2171{
2172 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2173 "Channel::SetSendCodec()");
2174
2175 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
2176 {
2177 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
2178 "SetSendCodec() failed to register codec to ACM");
2179 return -1;
2180 }
2181
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002182 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002183 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002184 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2185 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002186 {
2187 WEBRTC_TRACE(
2188 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
2189 "SetSendCodec() failed to register codec to"
2190 " RTP/RTCP module");
2191 return -1;
2192 }
2193 }
2194
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002195 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002196 {
2197 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
2198 "SetSendCodec() failed to set audio packet size");
2199 return -1;
2200 }
2201
2202 return 0;
2203}
2204
2205WebRtc_Word32
2206Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
2207{
2208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2209 "Channel::SetVADStatus(mode=%d)", mode);
2210 // To disable VAD, DTX must be disabled too
2211 disableDTX = ((enableVAD == false) ? true : disableDTX);
2212 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
2213 {
2214 _engineStatisticsPtr->SetLastError(
2215 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2216 "SetVADStatus() failed to set VAD");
2217 return -1;
2218 }
2219 return 0;
2220}
2221
2222WebRtc_Word32
2223Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
2224{
2225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2226 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002227 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002228 {
2229 _engineStatisticsPtr->SetLastError(
2230 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2231 "GetVADStatus() failed to get VAD status");
2232 return -1;
2233 }
2234 disabledDTX = !disabledDTX;
2235 return 0;
2236}
2237
2238WebRtc_Word32
2239Channel::SetRecPayloadType(const CodecInst& codec)
2240{
2241 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2242 "Channel::SetRecPayloadType()");
2243
2244 if (_playing)
2245 {
2246 _engineStatisticsPtr->SetLastError(
2247 VE_ALREADY_PLAYING, kTraceError,
2248 "SetRecPayloadType() unable to set PT while playing");
2249 return -1;
2250 }
2251 if (_receiving)
2252 {
2253 _engineStatisticsPtr->SetLastError(
2254 VE_ALREADY_LISTENING, kTraceError,
2255 "SetRecPayloadType() unable to set PT while listening");
2256 return -1;
2257 }
2258
2259 if (codec.pltype == -1)
2260 {
2261 // De-register the selected codec (RTP/RTCP module and ACM)
2262
2263 WebRtc_Word8 pltype(-1);
2264 CodecInst rxCodec = codec;
2265
2266 // Get payload type for the given codec
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002267 _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00002268 rxCodec.pltype = pltype;
2269
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002270 if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002271 {
2272 _engineStatisticsPtr->SetLastError(
2273 VE_RTP_RTCP_MODULE_ERROR,
2274 kTraceError,
2275 "SetRecPayloadType() RTP/RTCP-module deregistration "
2276 "failed");
2277 return -1;
2278 }
2279 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
2280 {
2281 _engineStatisticsPtr->SetLastError(
2282 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2283 "SetRecPayloadType() ACM deregistration failed - 1");
2284 return -1;
2285 }
2286 return 0;
2287 }
2288
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002289 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002290 {
2291 // First attempt to register failed => de-register and try again
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002292 _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
2293 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002294 {
2295 _engineStatisticsPtr->SetLastError(
2296 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2297 "SetRecPayloadType() RTP/RTCP-module registration failed");
2298 return -1;
2299 }
2300 }
2301 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
2302 {
2303 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
2304 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
2305 {
2306 _engineStatisticsPtr->SetLastError(
2307 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2308 "SetRecPayloadType() ACM registration failed - 1");
2309 return -1;
2310 }
2311 }
2312 return 0;
2313}
2314
2315WebRtc_Word32
2316Channel::GetRecPayloadType(CodecInst& codec)
2317{
2318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2319 "Channel::GetRecPayloadType()");
2320 WebRtc_Word8 payloadType(-1);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002321 if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002322 {
2323 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00002324 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00002325 "GetRecPayloadType() failed to retrieve RX payload type");
2326 return -1;
2327 }
2328 codec.pltype = payloadType;
2329 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2330 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
2331 return 0;
2332}
2333
2334WebRtc_Word32
2335Channel::SetAMREncFormat(AmrMode mode)
2336{
2337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2338 "Channel::SetAMREncFormat()");
2339
2340 // ACM doesn't support AMR
2341 return -1;
2342}
2343
2344WebRtc_Word32
2345Channel::SetAMRDecFormat(AmrMode mode)
2346{
2347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2348 "Channel::SetAMRDecFormat()");
2349
2350 // ACM doesn't support AMR
2351 return -1;
2352}
2353
2354WebRtc_Word32
2355Channel::SetAMRWbEncFormat(AmrMode mode)
2356{
2357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2358 "Channel::SetAMRWbEncFormat()");
2359
2360 // ACM doesn't support AMR
2361 return -1;
2362
2363}
2364
2365WebRtc_Word32
2366Channel::SetAMRWbDecFormat(AmrMode mode)
2367{
2368 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2369 "Channel::SetAMRWbDecFormat()");
2370
2371 // ACM doesn't support AMR
2372 return -1;
2373}
2374
2375WebRtc_Word32
2376Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
2377{
2378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2379 "Channel::SetSendCNPayloadType()");
2380
2381 CodecInst codec;
2382 WebRtc_Word32 samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00002383 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002384 if (frequency == kFreq32000Hz)
2385 samplingFreqHz = 32000;
2386 else if (frequency == kFreq16000Hz)
2387 samplingFreqHz = 16000;
2388
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002389 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002390 {
2391 _engineStatisticsPtr->SetLastError(
2392 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2393 "SetSendCNPayloadType() failed to retrieve default CN codec "
2394 "settings");
2395 return -1;
2396 }
2397
2398 // Modify the payload type (must be set to dynamic range)
2399 codec.pltype = type;
2400
2401 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
2402 {
2403 _engineStatisticsPtr->SetLastError(
2404 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2405 "SetSendCNPayloadType() failed to register CN to ACM");
2406 return -1;
2407 }
2408
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002409 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002410 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002411 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2412 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002413 {
2414 _engineStatisticsPtr->SetLastError(
2415 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2416 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
2417 "module");
2418 return -1;
2419 }
2420 }
2421 return 0;
2422}
2423
2424WebRtc_Word32
2425Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
2426{
2427 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2428 "Channel::SetISACInitTargetRate()");
2429
2430 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002431 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002432 {
2433 _engineStatisticsPtr->SetLastError(
2434 VE_CODEC_ERROR, kTraceError,
2435 "SetISACInitTargetRate() failed to retrieve send codec");
2436 return -1;
2437 }
2438 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2439 {
2440 // This API is only valid if iSAC is setup to run in channel-adaptive
2441 // mode.
2442 // We do not validate the adaptive mode here. It is done later in the
2443 // ConfigISACBandwidthEstimator() API.
2444 _engineStatisticsPtr->SetLastError(
2445 VE_CODEC_ERROR, kTraceError,
2446 "SetISACInitTargetRate() send codec is not iSAC");
2447 return -1;
2448 }
2449
2450 WebRtc_UWord8 initFrameSizeMsec(0);
2451 if (16000 == sendCodec.plfreq)
2452 {
2453 // Note that 0 is a valid and corresponds to "use default
2454 if ((rateBps != 0 &&
2455 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
2456 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
2457 {
2458 _engineStatisticsPtr->SetLastError(
2459 VE_INVALID_ARGUMENT, kTraceError,
2460 "SetISACInitTargetRate() invalid target rate - 1");
2461 return -1;
2462 }
2463 // 30 or 60ms
2464 initFrameSizeMsec = (WebRtc_UWord8)(sendCodec.pacsize / 16);
2465 }
2466 else if (32000 == sendCodec.plfreq)
2467 {
2468 if ((rateBps != 0 &&
2469 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
2470 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
2471 {
2472 _engineStatisticsPtr->SetLastError(
2473 VE_INVALID_ARGUMENT, kTraceError,
2474 "SetISACInitTargetRate() invalid target rate - 2");
2475 return -1;
2476 }
2477 initFrameSizeMsec = (WebRtc_UWord8)(sendCodec.pacsize / 32); // 30ms
2478 }
2479
2480 if (_audioCodingModule.ConfigISACBandwidthEstimator(
2481 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
2482 {
2483 _engineStatisticsPtr->SetLastError(
2484 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2485 "SetISACInitTargetRate() iSAC BWE config failed");
2486 return -1;
2487 }
2488
2489 return 0;
2490}
2491
2492WebRtc_Word32
2493Channel::SetISACMaxRate(int rateBps)
2494{
2495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2496 "Channel::SetISACMaxRate()");
2497
2498 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002499 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002500 {
2501 _engineStatisticsPtr->SetLastError(
2502 VE_CODEC_ERROR, kTraceError,
2503 "SetISACMaxRate() failed to retrieve send codec");
2504 return -1;
2505 }
2506 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2507 {
2508 // This API is only valid if iSAC is selected as sending codec.
2509 _engineStatisticsPtr->SetLastError(
2510 VE_CODEC_ERROR, kTraceError,
2511 "SetISACMaxRate() send codec is not iSAC");
2512 return -1;
2513 }
2514 if (16000 == sendCodec.plfreq)
2515 {
2516 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2517 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2518 {
2519 _engineStatisticsPtr->SetLastError(
2520 VE_INVALID_ARGUMENT, kTraceError,
2521 "SetISACMaxRate() invalid max rate - 1");
2522 return -1;
2523 }
2524 }
2525 else if (32000 == sendCodec.plfreq)
2526 {
2527 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2528 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2529 {
2530 _engineStatisticsPtr->SetLastError(
2531 VE_INVALID_ARGUMENT, kTraceError,
2532 "SetISACMaxRate() invalid max rate - 2");
2533 return -1;
2534 }
2535 }
2536 if (_sending)
2537 {
2538 _engineStatisticsPtr->SetLastError(
2539 VE_SENDING, kTraceError,
2540 "SetISACMaxRate() unable to set max rate while sending");
2541 return -1;
2542 }
2543
2544 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2545 // and non-adaptive mode)
2546 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2547 {
2548 _engineStatisticsPtr->SetLastError(
2549 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2550 "SetISACMaxRate() failed to set max rate");
2551 return -1;
2552 }
2553
2554 return 0;
2555}
2556
2557WebRtc_Word32
2558Channel::SetISACMaxPayloadSize(int sizeBytes)
2559{
2560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2561 "Channel::SetISACMaxPayloadSize()");
2562 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002563 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002564 {
2565 _engineStatisticsPtr->SetLastError(
2566 VE_CODEC_ERROR, kTraceError,
2567 "SetISACMaxPayloadSize() failed to retrieve send codec");
2568 return -1;
2569 }
2570 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2571 {
2572 _engineStatisticsPtr->SetLastError(
2573 VE_CODEC_ERROR, kTraceError,
2574 "SetISACMaxPayloadSize() send codec is not iSAC");
2575 return -1;
2576 }
2577 if (16000 == sendCodec.plfreq)
2578 {
2579 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2580 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2581 {
2582 _engineStatisticsPtr->SetLastError(
2583 VE_INVALID_ARGUMENT, kTraceError,
2584 "SetISACMaxPayloadSize() invalid max payload - 1");
2585 return -1;
2586 }
2587 }
2588 else if (32000 == sendCodec.plfreq)
2589 {
2590 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2591 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2592 {
2593 _engineStatisticsPtr->SetLastError(
2594 VE_INVALID_ARGUMENT, kTraceError,
2595 "SetISACMaxPayloadSize() invalid max payload - 2");
2596 return -1;
2597 }
2598 }
2599 if (_sending)
2600 {
2601 _engineStatisticsPtr->SetLastError(
2602 VE_SENDING, kTraceError,
2603 "SetISACMaxPayloadSize() unable to set max rate while sending");
2604 return -1;
2605 }
2606
2607 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2608 {
2609 _engineStatisticsPtr->SetLastError(
2610 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2611 "SetISACMaxPayloadSize() failed to set max payload size");
2612 return -1;
2613 }
2614 return 0;
2615}
2616
2617WebRtc_Word32 Channel::RegisterExternalTransport(Transport& transport)
2618{
2619 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2620 "Channel::RegisterExternalTransport()");
2621
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002622 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002623
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002624#ifndef WEBRTC_EXTERNAL_TRANSPORT
2625 // Sanity checks for default (non external transport) to avoid conflict with
2626 // WebRtc sockets.
2627 if (_socketTransportModule.SendSocketsInitialized())
2628 {
2629 _engineStatisticsPtr->SetLastError(VE_SEND_SOCKETS_CONFLICT,
2630 kTraceError,
2631 "RegisterExternalTransport() send sockets already initialized");
2632 return -1;
2633 }
2634 if (_socketTransportModule.ReceiveSocketsInitialized())
2635 {
2636 _engineStatisticsPtr->SetLastError(VE_RECEIVE_SOCKETS_CONFLICT,
2637 kTraceError,
2638 "RegisterExternalTransport() receive sockets already initialized");
2639 return -1;
2640 }
2641#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00002642 if (_externalTransport)
2643 {
2644 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2645 kTraceError,
2646 "RegisterExternalTransport() external transport already enabled");
2647 return -1;
2648 }
2649 _externalTransport = true;
2650 _transportPtr = &transport;
2651 return 0;
2652}
2653
2654WebRtc_Word32
2655Channel::DeRegisterExternalTransport()
2656{
2657 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2658 "Channel::DeRegisterExternalTransport()");
2659
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002660 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002661
niklase@google.com470e71d2011-07-07 08:21:25 +00002662 if (!_transportPtr)
2663 {
2664 _engineStatisticsPtr->SetLastError(
2665 VE_INVALID_OPERATION, kTraceWarning,
2666 "DeRegisterExternalTransport() external transport already "
2667 "disabled");
2668 return 0;
2669 }
2670 _externalTransport = false;
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002671#ifdef WEBRTC_EXTERNAL_TRANSPORT
niklase@google.com470e71d2011-07-07 08:21:25 +00002672 _transportPtr = NULL;
2673 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2674 "DeRegisterExternalTransport() all transport is disabled");
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002675#else
2676 _transportPtr = &_socketTransportModule;
2677 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2678 "DeRegisterExternalTransport() internal Transport is enabled");
2679#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 return 0;
2681}
2682
2683WebRtc_Word32
2684Channel::ReceivedRTPPacket(const WebRtc_Word8* data, WebRtc_Word32 length)
2685{
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002686 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2687 "Channel::ReceivedRTPPacket()");
2688 const char dummyIP[] = "127.0.0.1";
2689 IncomingRTPPacket(data, length, dummyIP, 0);
2690 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002691}
2692
2693WebRtc_Word32
2694Channel::ReceivedRTCPPacket(const WebRtc_Word8* data, WebRtc_Word32 length)
2695{
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002696 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2697 "Channel::ReceivedRTCPPacket()");
2698 const char dummyIP[] = "127.0.0.1";
2699 IncomingRTCPPacket(data, length, dummyIP, 0);
2700 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002701}
2702
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00002703#ifndef WEBRTC_EXTERNAL_TRANSPORT
2704WebRtc_Word32
2705Channel::GetSourceInfo(int& rtpPort, int& rtcpPort, char ipAddr[64])
2706{
2707 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2708 "Channel::GetSourceInfo()");
2709
2710 WebRtc_UWord16 rtpPortModule;
2711 WebRtc_UWord16 rtcpPortModule;
2712 char ipaddr[UdpTransport::kIpAddressVersion6Length] = {0};
2713
2714 if (_socketTransportModule.RemoteSocketInformation(ipaddr,
2715 rtpPortModule,
2716 rtcpPortModule) != 0)
2717 {
2718 _engineStatisticsPtr->SetLastError(
2719 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
2720 "GetSourceInfo() failed to retrieve remote socket information");
2721 return -1;
2722 }
2723 strcpy(ipAddr, ipaddr);
2724 rtpPort = rtpPortModule;
2725 rtcpPort = rtcpPortModule;
2726
2727 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2728 "GetSourceInfo() => rtpPort=%d, rtcpPort=%d, ipAddr=%s",
2729 rtpPort, rtcpPort, ipAddr);
2730 return 0;
2731}
2732
2733WebRtc_Word32
2734Channel::EnableIPv6()
2735{
2736 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2737 "Channel::EnableIPv6()");
2738 if (_socketTransportModule.ReceiveSocketsInitialized() ||
2739 _socketTransportModule.SendSocketsInitialized())
2740 {
2741 _engineStatisticsPtr->SetLastError(
2742 VE_INVALID_OPERATION, kTraceError,
2743 "EnableIPv6() socket layer is already initialized");
2744 return -1;
2745 }
2746 if (_socketTransportModule.EnableIpV6() != 0)
2747 {
2748 _engineStatisticsPtr->SetLastError(
2749 VE_SOCKET_ERROR, kTraceError,
2750 "EnableIPv6() failed to enable IPv6");
2751 const UdpTransport::ErrorCode lastError =
2752 _socketTransportModule.LastError();
2753 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2754 "UdpTransport::LastError() => %d", lastError);
2755 return -1;
2756 }
2757 return 0;
2758}
2759
2760bool
2761Channel::IPv6IsEnabled() const
2762{
2763 bool isEnabled = _socketTransportModule.IpV6Enabled();
2764 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2765 "IPv6IsEnabled() => %d", isEnabled);
2766 return isEnabled;
2767}
2768
2769WebRtc_Word32
2770Channel::SetSourceFilter(int rtpPort, int rtcpPort, const char ipAddr[64])
2771{
2772 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2773 "Channel::SetSourceFilter()");
2774 if (_socketTransportModule.SetFilterPorts(
2775 static_cast<WebRtc_UWord16>(rtpPort),
2776 static_cast<WebRtc_UWord16>(rtcpPort)) != 0)
2777 {
2778 _engineStatisticsPtr->SetLastError(
2779 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
2780 "SetSourceFilter() failed to set filter ports");
2781 const UdpTransport::ErrorCode lastError =
2782 _socketTransportModule.LastError();
2783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2784 "UdpTransport::LastError() => %d",
2785 lastError);
2786 return -1;
2787 }
2788 const char* filterIpAddress = ipAddr;
2789 if (_socketTransportModule.SetFilterIP(filterIpAddress) != 0)
2790 {
2791 _engineStatisticsPtr->SetLastError(
2792 VE_INVALID_IP_ADDRESS, kTraceError,
2793 "SetSourceFilter() failed to set filter IP address");
2794 const UdpTransport::ErrorCode lastError =
2795 _socketTransportModule.LastError();
2796 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2797 "UdpTransport::LastError() => %d", lastError);
2798 return -1;
2799 }
2800 return 0;
2801}
2802
2803WebRtc_Word32
2804Channel::GetSourceFilter(int& rtpPort, int& rtcpPort, char ipAddr[64])
2805{
2806 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2807 "Channel::GetSourceFilter()");
2808 WebRtc_UWord16 rtpFilterPort(0);
2809 WebRtc_UWord16 rtcpFilterPort(0);
2810 if (_socketTransportModule.FilterPorts(rtpFilterPort, rtcpFilterPort) != 0)
2811 {
2812 _engineStatisticsPtr->SetLastError(
2813 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2814 "GetSourceFilter() failed to retrieve filter ports");
2815 }
2816 char ipAddrTmp[UdpTransport::kIpAddressVersion6Length] = {0};
2817 if (_socketTransportModule.FilterIP(ipAddrTmp) != 0)
2818 {
2819 // no filter has been configured (not seen as an error)
2820 memset(ipAddrTmp,
2821 0, UdpTransport::kIpAddressVersion6Length);
2822 }
2823 rtpPort = static_cast<int> (rtpFilterPort);
2824 rtcpPort = static_cast<int> (rtcpFilterPort);
2825 strcpy(ipAddr, ipAddrTmp);
2826 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2827 "GetSourceFilter() => rtpPort=%d, rtcpPort=%d, ipAddr=%s",
2828 rtpPort, rtcpPort, ipAddr);
2829 return 0;
2830}
2831
2832WebRtc_Word32
2833Channel::SetSendTOS(int DSCP, int priority, bool useSetSockopt)
2834{
2835 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2836 "Channel::SetSendTOS(DSCP=%d, useSetSockopt=%d)",
2837 DSCP, (int)useSetSockopt);
2838
2839 // Set TOS value and possibly try to force usage of setsockopt()
2840 if (_socketTransportModule.SetToS(DSCP, useSetSockopt) != 0)
2841 {
2842 UdpTransport::ErrorCode lastSockError(
2843 _socketTransportModule.LastError());
2844 switch (lastSockError)
2845 {
2846 case UdpTransport::kTosError:
2847 _engineStatisticsPtr->SetLastError(VE_TOS_ERROR, kTraceError,
2848 "SetSendTOS() TOS error");
2849 break;
2850 case UdpTransport::kQosError:
2851 _engineStatisticsPtr->SetLastError(
2852 VE_TOS_GQOS_CONFLICT, kTraceError,
2853 "SetSendTOS() GQOS error");
2854 break;
2855 case UdpTransport::kTosInvalid:
2856 // can't switch SetSockOpt method without disabling TOS first, or
2857 // SetSockopt() call failed
2858 _engineStatisticsPtr->SetLastError(VE_TOS_INVALID, kTraceError,
2859 "SetSendTOS() invalid TOS");
2860 break;
2861 case UdpTransport::kSocketInvalid:
2862 _engineStatisticsPtr->SetLastError(VE_SOCKET_ERROR, kTraceError,
2863 "SetSendTOS() invalid Socket");
2864 break;
2865 default:
2866 _engineStatisticsPtr->SetLastError(VE_TOS_ERROR, kTraceError,
2867 "SetSendTOS() TOS error");
2868 break;
2869 }
2870 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
2871 "UdpTransport => lastError = %d",
2872 lastSockError);
2873 return -1;
2874 }
2875
2876 // Set priority (PCP) value, -1 means don't change
2877 if (-1 != priority)
2878 {
2879 if (_socketTransportModule.SetPCP(priority) != 0)
2880 {
2881 UdpTransport::ErrorCode lastSockError(
2882 _socketTransportModule.LastError());
2883 switch (lastSockError)
2884 {
2885 case UdpTransport::kPcpError:
2886 _engineStatisticsPtr->SetLastError(VE_TOS_ERROR, kTraceError,
2887 "SetSendTOS() PCP error");
2888 break;
2889 case UdpTransport::kQosError:
2890 _engineStatisticsPtr->SetLastError(
2891 VE_TOS_GQOS_CONFLICT, kTraceError,
2892 "SetSendTOS() GQOS conflict");
2893 break;
2894 case UdpTransport::kSocketInvalid:
2895 _engineStatisticsPtr->SetLastError(
2896 VE_SOCKET_ERROR, kTraceError,
2897 "SetSendTOS() invalid Socket");
2898 break;
2899 default:
2900 _engineStatisticsPtr->SetLastError(VE_TOS_ERROR, kTraceError,
2901 "SetSendTOS() PCP error");
2902 break;
2903 }
2904 WEBRTC_TRACE(kTraceError, kTraceVoice,
2905 VoEId(_instanceId,_channelId),
2906 "UdpTransport => lastError = %d",
2907 lastSockError);
2908 return -1;
2909 }
2910 }
2911
2912 return 0;
2913}
2914
2915WebRtc_Word32
2916Channel::GetSendTOS(int &DSCP, int& priority, bool &useSetSockopt)
2917{
2918 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2919 "Channel::GetSendTOS(DSCP=?, useSetSockopt=?)");
2920 WebRtc_Word32 dscp(0), prio(0);
2921 bool setSockopt(false);
2922 if (_socketTransportModule.ToS(dscp, setSockopt) != 0)
2923 {
2924 _engineStatisticsPtr->SetLastError(
2925 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
2926 "GetSendTOS() failed to get TOS info");
2927 return -1;
2928 }
2929 if (_socketTransportModule.PCP(prio) != 0)
2930 {
2931 _engineStatisticsPtr->SetLastError(
2932 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
2933 "GetSendTOS() failed to get PCP info");
2934 return -1;
2935 }
2936 DSCP = static_cast<int> (dscp);
2937 priority = static_cast<int> (prio);
2938 useSetSockopt = setSockopt;
2939 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2940 "GetSendTOS() => DSCP=%d, priority=%d, useSetSockopt=%d",
2941 DSCP, priority, (int)useSetSockopt);
2942 return 0;
2943}
2944
2945#if defined(_WIN32)
2946WebRtc_Word32
2947Channel::SetSendGQoS(bool enable, int serviceType, int overrideDSCP)
2948{
2949 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2950 "Channel::SetSendGQoS(enable=%d, serviceType=%d, "
2951 "overrideDSCP=%d)",
2952 (int)enable, serviceType, overrideDSCP);
2953 if(!_socketTransportModule.ReceiveSocketsInitialized())
2954 {
2955 _engineStatisticsPtr->SetLastError(
2956 VE_SOCKETS_NOT_INITED, kTraceError,
2957 "SetSendGQoS() GQoS state must be set after sockets are created");
2958 return -1;
2959 }
2960 if(!_socketTransportModule.SendSocketsInitialized())
2961 {
2962 _engineStatisticsPtr->SetLastError(
2963 VE_DESTINATION_NOT_INITED, kTraceError,
2964 "SetSendGQoS() GQoS state must be set after sending side is "
2965 "initialized");
2966 return -1;
2967 }
2968 if (enable &&
2969 (serviceType != SERVICETYPE_BESTEFFORT) &&
2970 (serviceType != SERVICETYPE_CONTROLLEDLOAD) &&
2971 (serviceType != SERVICETYPE_GUARANTEED) &&
2972 (serviceType != SERVICETYPE_QUALITATIVE))
2973 {
2974 _engineStatisticsPtr->SetLastError(
2975 VE_INVALID_ARGUMENT, kTraceError,
2976 "SetSendGQoS() Invalid service type");
2977 return -1;
2978 }
2979 if (enable && ((overrideDSCP < 0) || (overrideDSCP > 63)))
2980 {
2981 _engineStatisticsPtr->SetLastError(
2982 VE_INVALID_ARGUMENT, kTraceError,
2983 "SetSendGQoS() Invalid overrideDSCP value");
2984 return -1;
2985 }
2986
2987 // Avoid GQoS/ToS conflict when user wants to override the default DSCP
2988 // mapping
2989 bool QoS(false);
2990 WebRtc_Word32 sType(0);
2991 WebRtc_Word32 ovrDSCP(0);
2992 if (_socketTransportModule.QoS(QoS, sType, ovrDSCP))
2993 {
2994 _engineStatisticsPtr->SetLastError(
2995 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceError,
2996 "SetSendGQoS() failed to get QOS info");
2997 return -1;
2998 }
2999 if (QoS && ovrDSCP == 0 && overrideDSCP != 0)
3000 {
3001 _engineStatisticsPtr->SetLastError(
3002 VE_TOS_GQOS_CONFLICT, kTraceError,
3003 "SetSendGQoS() QOS is already enabled and overrideDSCP differs,"
3004 " not allowed");
3005 return -1;
3006 }
3007 const WebRtc_Word32 maxBitrate(0);
3008 if (_socketTransportModule.SetQoS(enable,
3009 static_cast<WebRtc_Word32>(serviceType),
3010 maxBitrate,
3011 static_cast<WebRtc_Word32>(overrideDSCP),
3012 true))
3013 {
3014 UdpTransport::ErrorCode lastSockError(
3015 _socketTransportModule.LastError());
3016 switch (lastSockError)
3017 {
3018 case UdpTransport::kQosError:
3019 _engineStatisticsPtr->SetLastError(VE_GQOS_ERROR, kTraceError,
3020 "SetSendGQoS() QOS error");
3021 break;
3022 default:
3023 _engineStatisticsPtr->SetLastError(VE_SOCKET_ERROR, kTraceError,
3024 "SetSendGQoS() Socket error");
3025 break;
3026 }
3027 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3028 "UdpTransport() => lastError = %d",
3029 lastSockError);
3030 return -1;
3031 }
3032 return 0;
3033}
3034#endif
3035
3036#if defined(_WIN32)
3037WebRtc_Word32
3038Channel::GetSendGQoS(bool &enabled, int &serviceType, int &overrideDSCP)
3039{
3040 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3041 "Channel::GetSendGQoS(enable=?, serviceType=?, "
3042 "overrideDSCP=?)");
3043
3044 bool QoS(false);
3045 WebRtc_Word32 serviceTypeModule(0);
3046 WebRtc_Word32 overrideDSCPModule(0);
3047 _socketTransportModule.QoS(QoS, serviceTypeModule, overrideDSCPModule);
3048
3049 enabled = QoS;
3050 serviceType = static_cast<int> (serviceTypeModule);
3051 overrideDSCP = static_cast<int> (overrideDSCPModule);
3052
3053 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3054 "GetSendGQoS() => enabled=%d, serviceType=%d, overrideDSCP=%d",
3055 (int)enabled, serviceType, overrideDSCP);
3056 return 0;
3057}
3058#endif
3059#endif
3060
niklase@google.com470e71d2011-07-07 08:21:25 +00003061WebRtc_Word32
3062Channel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
3063{
3064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3065 "Channel::SetPacketTimeoutNotification()");
3066 if (enable)
3067 {
3068 const WebRtc_UWord32 RTPtimeoutMS = 1000*timeoutSeconds;
3069 const WebRtc_UWord32 RTCPtimeoutMS = 0;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003070 _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
niklase@google.com470e71d2011-07-07 08:21:25 +00003071 _rtpPacketTimeOutIsEnabled = true;
3072 _rtpTimeOutSeconds = timeoutSeconds;
3073 }
3074 else
3075 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003076 _rtpRtcpModule->SetPacketTimeout(0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003077 _rtpPacketTimeOutIsEnabled = false;
3078 _rtpTimeOutSeconds = 0;
3079 }
3080 return 0;
3081}
3082
3083WebRtc_Word32
3084Channel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3087 "Channel::GetPacketTimeoutNotification()");
3088 enabled = _rtpPacketTimeOutIsEnabled;
3089 if (enabled)
3090 {
3091 timeoutSeconds = _rtpTimeOutSeconds;
3092 }
3093 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
3094 "GetPacketTimeoutNotification() => enabled=%d,"
3095 " timeoutSeconds=%d",
3096 enabled, timeoutSeconds);
3097 return 0;
3098}
3099
3100WebRtc_Word32
3101Channel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
3102{
3103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3104 "Channel::RegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003105 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003106
3107 if (_connectionObserverPtr)
3108 {
3109 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
3110 "RegisterDeadOrAliveObserver() observer already enabled");
3111 return -1;
3112 }
3113
3114 _connectionObserverPtr = &observer;
3115 _connectionObserver = true;
3116
3117 return 0;
3118}
3119
3120WebRtc_Word32
3121Channel::DeRegisterDeadOrAliveObserver()
3122{
3123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3124 "Channel::DeRegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003125 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003126
3127 if (!_connectionObserverPtr)
3128 {
3129 _engineStatisticsPtr->SetLastError(
3130 VE_INVALID_OPERATION, kTraceWarning,
3131 "DeRegisterDeadOrAliveObserver() observer already disabled");
3132 return 0;
3133 }
3134
3135 _connectionObserver = false;
3136 _connectionObserverPtr = NULL;
3137
3138 return 0;
3139}
3140
3141WebRtc_Word32
3142Channel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
3143{
3144 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3145 "Channel::SetPeriodicDeadOrAliveStatus()");
3146 if (!_connectionObserverPtr)
3147 {
3148 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3149 "SetPeriodicDeadOrAliveStatus() connection observer has"
3150 " not been registered");
3151 }
3152 if (enable)
3153 {
3154 ResetDeadOrAliveCounters();
3155 }
3156 bool enabled(false);
3157 WebRtc_UWord8 currentSampleTimeSec(0);
3158 // Store last state (will be used later if dead-or-alive is disabled).
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003159 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00003160 // Update the dead-or-alive state.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003161 if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00003162 enable, (WebRtc_UWord8)sampleTimeSeconds) != 0)
3163 {
3164 _engineStatisticsPtr->SetLastError(
3165 VE_RTP_RTCP_MODULE_ERROR,
3166 kTraceError,
3167 "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
3168 "status");
3169 return -1;
3170 }
3171 if (!enable)
3172 {
3173 // Restore last utilized sample time.
3174 // Without this, the sample time would always be reset to default
3175 // (2 sec), each time dead-or-alived was disabled without sample-time
3176 // parameter.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003177 _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
niklase@google.com470e71d2011-07-07 08:21:25 +00003178 currentSampleTimeSec);
3179 }
3180 return 0;
3181}
3182
3183WebRtc_Word32
3184Channel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
3185{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003186 _rtpRtcpModule->PeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00003187 enabled,
3188 (WebRtc_UWord8&)sampleTimeSeconds);
3189 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
3190 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
3191 " sampleTimeSeconds=%d",
3192 enabled, sampleTimeSeconds);
3193 return 0;
3194}
3195
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00003196WebRtc_Word32
3197Channel::SendUDPPacket(const void* data,
3198 unsigned int length,
3199 int& transmittedBytes,
3200 bool useRtcpSocket)
3201{
3202 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3203 "Channel::SendUDPPacket()");
3204 if (_externalTransport)
3205 {
3206 _engineStatisticsPtr->SetLastError(
3207 VE_EXTERNAL_TRANSPORT_ENABLED, kTraceError,
3208 "SendUDPPacket() external transport is enabled");
3209 return -1;
3210 }
3211 if (useRtcpSocket && !_rtpRtcpModule->RTCP())
3212 {
3213 _engineStatisticsPtr->SetLastError(
3214 VE_RTCP_ERROR, kTraceError,
3215 "SendUDPPacket() RTCP is disabled");
3216 return -1;
3217 }
3218 if (!_sending)
3219 {
3220 _engineStatisticsPtr->SetLastError(
3221 VE_NOT_SENDING, kTraceError,
3222 "SendUDPPacket() not sending");
3223 return -1;
3224 }
3225
3226 char* dataC = new char[length];
3227 if (NULL == dataC)
3228 {
3229 _engineStatisticsPtr->SetLastError(
3230 VE_NO_MEMORY, kTraceError,
3231 "SendUDPPacket() memory allocation failed");
3232 return -1;
3233 }
3234 memcpy(dataC, data, length);
3235
3236 transmittedBytes = SendPacketRaw(dataC, length, useRtcpSocket);
3237
3238 delete [] dataC;
3239 dataC = NULL;
3240
3241 if (transmittedBytes <= 0)
3242 {
3243 _engineStatisticsPtr->SetLastError(
3244 VE_SEND_ERROR, kTraceError,
3245 "SendUDPPacket() transmission failed");
3246 transmittedBytes = 0;
3247 return -1;
3248 }
3249 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3250 "SendUDPPacket() => transmittedBytes=%d", transmittedBytes);
3251 return 0;
3252}
3253
3254
niklase@google.com470e71d2011-07-07 08:21:25 +00003255int Channel::StartPlayingFileLocally(const char* fileName,
3256 const bool loop,
3257 const FileFormats format,
3258 const int startPosition,
3259 const float volumeScaling,
3260 const int stopPosition,
3261 const CodecInst* codecInst)
3262{
3263 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3264 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
3265 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
3266 "stopPosition=%d)", fileName, loop, format, volumeScaling,
3267 startPosition, stopPosition);
3268
3269 if (_outputFilePlaying)
3270 {
3271 _engineStatisticsPtr->SetLastError(
3272 VE_ALREADY_PLAYING, kTraceError,
3273 "StartPlayingFileLocally() is already playing");
3274 return -1;
3275 }
3276
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003278 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003279
3280 if (_outputFilePlayerPtr)
3281 {
3282 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3283 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3284 _outputFilePlayerPtr = NULL;
3285 }
3286
3287 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
3288 _outputFilePlayerId, (const FileFormats)format);
3289
3290 if (_outputFilePlayerPtr == NULL)
3291 {
3292 _engineStatisticsPtr->SetLastError(
3293 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00003294 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003295 return -1;
3296 }
3297
3298 const WebRtc_UWord32 notificationTime(0);
3299
3300 if (_outputFilePlayerPtr->StartPlayingFile(
3301 fileName,
3302 loop,
3303 startPosition,
3304 volumeScaling,
3305 notificationTime,
3306 stopPosition,
3307 (const CodecInst*)codecInst) != 0)
3308 {
3309 _engineStatisticsPtr->SetLastError(
3310 VE_BAD_FILE, kTraceError,
3311 "StartPlayingFile() failed to start file playout");
3312 _outputFilePlayerPtr->StopPlayingFile();
3313 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3314 _outputFilePlayerPtr = NULL;
3315 return -1;
3316 }
3317 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
3318 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003319 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00003320
3321 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00003322 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003323
3324 return 0;
3325}
3326
3327int Channel::StartPlayingFileLocally(InStream* stream,
3328 const FileFormats format,
3329 const int startPosition,
3330 const float volumeScaling,
3331 const int stopPosition,
3332 const CodecInst* codecInst)
3333{
3334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3335 "Channel::StartPlayingFileLocally(format=%d,"
3336 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
3337 format, volumeScaling, startPosition, stopPosition);
3338
3339 if(stream == NULL)
3340 {
3341 _engineStatisticsPtr->SetLastError(
3342 VE_BAD_FILE, kTraceError,
3343 "StartPlayingFileLocally() NULL as input stream");
3344 return -1;
3345 }
3346
3347
3348 if (_outputFilePlaying)
3349 {
3350 _engineStatisticsPtr->SetLastError(
3351 VE_ALREADY_PLAYING, kTraceError,
3352 "StartPlayingFileLocally() is already playing");
3353 return -1;
3354 }
3355
niklase@google.com470e71d2011-07-07 08:21:25 +00003356 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003357 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003358
3359 // Destroy the old instance
3360 if (_outputFilePlayerPtr)
3361 {
3362 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3363 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3364 _outputFilePlayerPtr = NULL;
3365 }
3366
3367 // Create the instance
3368 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
3369 _outputFilePlayerId,
3370 (const FileFormats)format);
3371
3372 if (_outputFilePlayerPtr == NULL)
3373 {
3374 _engineStatisticsPtr->SetLastError(
3375 VE_INVALID_ARGUMENT, kTraceError,
3376 "StartPlayingFileLocally() filePlayer format isnot correct");
3377 return -1;
3378 }
3379
3380 const WebRtc_UWord32 notificationTime(0);
3381
3382 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
3383 volumeScaling,
3384 notificationTime,
3385 stopPosition, codecInst) != 0)
3386 {
3387 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
3388 "StartPlayingFile() failed to "
3389 "start file playout");
3390 _outputFilePlayerPtr->StopPlayingFile();
3391 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3392 _outputFilePlayerPtr = NULL;
3393 return -1;
3394 }
3395 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
3396 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003397 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00003398
3399 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00003400 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003401
niklase@google.com470e71d2011-07-07 08:21:25 +00003402 return 0;
3403}
3404
3405int Channel::StopPlayingFileLocally()
3406{
3407 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3408 "Channel::StopPlayingFileLocally()");
3409
3410 if (!_outputFilePlaying)
3411 {
3412 _engineStatisticsPtr->SetLastError(
3413 VE_INVALID_OPERATION, kTraceWarning,
3414 "StopPlayingFileLocally() isnot playing");
3415 return 0;
3416 }
3417
niklase@google.com470e71d2011-07-07 08:21:25 +00003418 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003419 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003420
3421 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
3422 {
3423 _engineStatisticsPtr->SetLastError(
3424 VE_STOP_RECORDING_FAILED, kTraceError,
3425 "StopPlayingFile() could not stop playing");
3426 return -1;
3427 }
3428 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3429 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3430 _outputFilePlayerPtr = NULL;
3431 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00003432 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003433 // _fileCritSect cannot be taken while calling
3434 // SetAnonymousMixibilityStatus. Refer to comments in
3435 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00003436 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
3437 {
3438 _engineStatisticsPtr->SetLastError(
3439 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00003440 "StopPlayingFile() failed to stop participant from playing as"
3441 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00003442 return -1;
3443 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003444
3445 return 0;
3446}
3447
3448int Channel::IsPlayingFileLocally() const
3449{
3450 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3451 "Channel::IsPlayingFileLocally()");
3452
3453 return (WebRtc_Word32)_outputFilePlaying;
3454}
3455
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00003456int Channel::RegisterFilePlayingToMixer()
3457{
3458 // Return success for not registering for file playing to mixer if:
3459 // 1. playing file before playout is started on that channel.
3460 // 2. starting playout without file playing on that channel.
3461 if (!_playing || !_outputFilePlaying)
3462 {
3463 return 0;
3464 }
3465
3466 // |_fileCritSect| cannot be taken while calling
3467 // SetAnonymousMixabilityStatus() since as soon as the participant is added
3468 // frames can be pulled by the mixer. Since the frames are generated from
3469 // the file, _fileCritSect will be taken. This would result in a deadlock.
3470 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
3471 {
3472 CriticalSectionScoped cs(&_fileCritSect);
3473 _outputFilePlaying = false;
3474 _engineStatisticsPtr->SetLastError(
3475 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
3476 "StartPlayingFile() failed to add participant as file to mixer");
3477 _outputFilePlayerPtr->StopPlayingFile();
3478 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
3479 _outputFilePlayerPtr = NULL;
3480 return -1;
3481 }
3482
3483 return 0;
3484}
3485
niklase@google.com470e71d2011-07-07 08:21:25 +00003486int Channel::ScaleLocalFilePlayout(const float scale)
3487{
3488 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3489 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
3490
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003491 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003492
3493 if (!_outputFilePlaying)
3494 {
3495 _engineStatisticsPtr->SetLastError(
3496 VE_INVALID_OPERATION, kTraceError,
3497 "ScaleLocalFilePlayout() isnot playing");
3498 return -1;
3499 }
3500 if ((_outputFilePlayerPtr == NULL) ||
3501 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
3502 {
3503 _engineStatisticsPtr->SetLastError(
3504 VE_BAD_ARGUMENT, kTraceError,
3505 "SetAudioScaling() failed to scale the playout");
3506 return -1;
3507 }
3508
3509 return 0;
3510}
3511
3512int Channel::GetLocalPlayoutPosition(int& positionMs)
3513{
3514 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3515 "Channel::GetLocalPlayoutPosition(position=?)");
3516
3517 WebRtc_UWord32 position;
3518
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003519 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003520
3521 if (_outputFilePlayerPtr == NULL)
3522 {
3523 _engineStatisticsPtr->SetLastError(
3524 VE_INVALID_OPERATION, kTraceError,
3525 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
3526 return -1;
3527 }
3528
3529 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
3530 {
3531 _engineStatisticsPtr->SetLastError(
3532 VE_BAD_FILE, kTraceError,
3533 "GetLocalPlayoutPosition() failed");
3534 return -1;
3535 }
3536 positionMs = position;
3537
3538 return 0;
3539}
3540
3541int Channel::StartPlayingFileAsMicrophone(const char* fileName,
3542 const bool loop,
3543 const FileFormats format,
3544 const int startPosition,
3545 const float volumeScaling,
3546 const int stopPosition,
3547 const CodecInst* codecInst)
3548{
3549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3550 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
3551 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
3552 "stopPosition=%d)", fileName, loop, format, volumeScaling,
3553 startPosition, stopPosition);
3554
3555 if (_inputFilePlaying)
3556 {
3557 _engineStatisticsPtr->SetLastError(
3558 VE_ALREADY_PLAYING, kTraceWarning,
3559 "StartPlayingFileAsMicrophone() filePlayer is playing");
3560 return 0;
3561 }
3562
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003563 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003564
3565 // Destroy the old instance
3566 if (_inputFilePlayerPtr)
3567 {
3568 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3569 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
3570 _inputFilePlayerPtr = NULL;
3571 }
3572
3573 // Create the instance
3574 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
3575 _inputFilePlayerId, (const FileFormats)format);
3576
3577 if (_inputFilePlayerPtr == NULL)
3578 {
3579 _engineStatisticsPtr->SetLastError(
3580 VE_INVALID_ARGUMENT, kTraceError,
3581 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
3582 return -1;
3583 }
3584
3585 const WebRtc_UWord32 notificationTime(0);
3586
3587 if (_inputFilePlayerPtr->StartPlayingFile(
3588 fileName,
3589 loop,
3590 startPosition,
3591 volumeScaling,
3592 notificationTime,
3593 stopPosition,
3594 (const CodecInst*)codecInst) != 0)
3595 {
3596 _engineStatisticsPtr->SetLastError(
3597 VE_BAD_FILE, kTraceError,
3598 "StartPlayingFile() failed to start file playout");
3599 _inputFilePlayerPtr->StopPlayingFile();
3600 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
3601 _inputFilePlayerPtr = NULL;
3602 return -1;
3603 }
3604 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
3605 _inputFilePlaying = true;
3606
3607 return 0;
3608}
3609
3610int Channel::StartPlayingFileAsMicrophone(InStream* stream,
3611 const FileFormats format,
3612 const int startPosition,
3613 const float volumeScaling,
3614 const int stopPosition,
3615 const CodecInst* codecInst)
3616{
3617 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3618 "Channel::StartPlayingFileAsMicrophone(format=%d, "
3619 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
3620 format, volumeScaling, startPosition, stopPosition);
3621
3622 if(stream == NULL)
3623 {
3624 _engineStatisticsPtr->SetLastError(
3625 VE_BAD_FILE, kTraceError,
3626 "StartPlayingFileAsMicrophone NULL as input stream");
3627 return -1;
3628 }
3629
3630 if (_inputFilePlaying)
3631 {
3632 _engineStatisticsPtr->SetLastError(
3633 VE_ALREADY_PLAYING, kTraceWarning,
3634 "StartPlayingFileAsMicrophone() is playing");
3635 return 0;
3636 }
3637
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003638 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003639
3640 // Destroy the old instance
3641 if (_inputFilePlayerPtr)
3642 {
3643 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3644 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
3645 _inputFilePlayerPtr = NULL;
3646 }
3647
3648 // Create the instance
3649 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
3650 _inputFilePlayerId, (const FileFormats)format);
3651
3652 if (_inputFilePlayerPtr == NULL)
3653 {
3654 _engineStatisticsPtr->SetLastError(
3655 VE_INVALID_ARGUMENT, kTraceError,
3656 "StartPlayingInputFile() filePlayer format isnot correct");
3657 return -1;
3658 }
3659
3660 const WebRtc_UWord32 notificationTime(0);
3661
3662 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
3663 volumeScaling, notificationTime,
3664 stopPosition, codecInst) != 0)
3665 {
3666 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
3667 "StartPlayingFile() failed to start "
3668 "file playout");
3669 _inputFilePlayerPtr->StopPlayingFile();
3670 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
3671 _inputFilePlayerPtr = NULL;
3672 return -1;
3673 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003674
niklase@google.com470e71d2011-07-07 08:21:25 +00003675 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
3676 _inputFilePlaying = true;
3677
3678 return 0;
3679}
3680
3681int Channel::StopPlayingFileAsMicrophone()
3682{
3683 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3684 "Channel::StopPlayingFileAsMicrophone()");
3685
3686 if (!_inputFilePlaying)
3687 {
3688 _engineStatisticsPtr->SetLastError(
3689 VE_INVALID_OPERATION, kTraceWarning,
3690 "StopPlayingFileAsMicrophone() isnot playing");
3691 return 0;
3692 }
3693
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003694 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003695 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
3696 {
3697 _engineStatisticsPtr->SetLastError(
3698 VE_STOP_RECORDING_FAILED, kTraceError,
3699 "StopPlayingFile() could not stop playing");
3700 return -1;
3701 }
3702 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
3703 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
3704 _inputFilePlayerPtr = NULL;
3705 _inputFilePlaying = false;
3706
3707 return 0;
3708}
3709
3710int Channel::IsPlayingFileAsMicrophone() const
3711{
3712 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3713 "Channel::IsPlayingFileAsMicrophone()");
3714
3715 return _inputFilePlaying;
3716}
3717
3718int Channel::ScaleFileAsMicrophonePlayout(const float scale)
3719{
3720 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3721 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
3722
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003723 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003724
3725 if (!_inputFilePlaying)
3726 {
3727 _engineStatisticsPtr->SetLastError(
3728 VE_INVALID_OPERATION, kTraceError,
3729 "ScaleFileAsMicrophonePlayout() isnot playing");
3730 return -1;
3731 }
3732
3733 if ((_inputFilePlayerPtr == NULL) ||
3734 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
3735 {
3736 _engineStatisticsPtr->SetLastError(
3737 VE_BAD_ARGUMENT, kTraceError,
3738 "SetAudioScaling() failed to scale playout");
3739 return -1;
3740 }
3741
3742 return 0;
3743}
3744
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003745int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00003746 const CodecInst* codecInst)
3747{
3748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3749 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
3750
3751 if (_outputFileRecording)
3752 {
3753 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
3754 "StartRecordingPlayout() is already recording");
3755 return 0;
3756 }
3757
3758 FileFormats format;
3759 const WebRtc_UWord32 notificationTime(0); // Not supported in VoE
3760 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
3761
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00003762 if ((codecInst != NULL) &&
3763 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00003764 {
3765 _engineStatisticsPtr->SetLastError(
3766 VE_BAD_ARGUMENT, kTraceError,
3767 "StartRecordingPlayout() invalid compression");
3768 return(-1);
3769 }
3770 if(codecInst == NULL)
3771 {
3772 format = kFileFormatPcm16kHzFile;
3773 codecInst=&dummyCodec;
3774 }
3775 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
3776 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
3777 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
3778 {
3779 format = kFileFormatWavFile;
3780 }
3781 else
3782 {
3783 format = kFileFormatCompressedFile;
3784 }
3785
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003786 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003787
3788 // Destroy the old instance
3789 if (_outputFileRecorderPtr)
3790 {
3791 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
3792 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
3793 _outputFileRecorderPtr = NULL;
3794 }
3795
3796 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
3797 _outputFileRecorderId, (const FileFormats)format);
3798 if (_outputFileRecorderPtr == NULL)
3799 {
3800 _engineStatisticsPtr->SetLastError(
3801 VE_INVALID_ARGUMENT, kTraceError,
3802 "StartRecordingPlayout() fileRecorder format isnot correct");
3803 return -1;
3804 }
3805
3806 if (_outputFileRecorderPtr->StartRecordingAudioFile(
3807 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
3808 {
3809 _engineStatisticsPtr->SetLastError(
3810 VE_BAD_FILE, kTraceError,
3811 "StartRecordingAudioFile() failed to start file recording");
3812 _outputFileRecorderPtr->StopRecording();
3813 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
3814 _outputFileRecorderPtr = NULL;
3815 return -1;
3816 }
3817 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
3818 _outputFileRecording = true;
3819
3820 return 0;
3821}
3822
3823int Channel::StartRecordingPlayout(OutStream* stream,
3824 const CodecInst* codecInst)
3825{
3826 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3827 "Channel::StartRecordingPlayout()");
3828
3829 if (_outputFileRecording)
3830 {
3831 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
3832 "StartRecordingPlayout() is already recording");
3833 return 0;
3834 }
3835
3836 FileFormats format;
3837 const WebRtc_UWord32 notificationTime(0); // Not supported in VoE
3838 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
3839
3840 if (codecInst != NULL && codecInst->channels != 1)
3841 {
3842 _engineStatisticsPtr->SetLastError(
3843 VE_BAD_ARGUMENT, kTraceError,
3844 "StartRecordingPlayout() invalid compression");
3845 return(-1);
3846 }
3847 if(codecInst == NULL)
3848 {
3849 format = kFileFormatPcm16kHzFile;
3850 codecInst=&dummyCodec;
3851 }
3852 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
3853 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
3854 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
3855 {
3856 format = kFileFormatWavFile;
3857 }
3858 else
3859 {
3860 format = kFileFormatCompressedFile;
3861 }
3862
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003863 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003864
3865 // Destroy the old instance
3866 if (_outputFileRecorderPtr)
3867 {
3868 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
3869 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
3870 _outputFileRecorderPtr = NULL;
3871 }
3872
3873 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
3874 _outputFileRecorderId, (const FileFormats)format);
3875 if (_outputFileRecorderPtr == NULL)
3876 {
3877 _engineStatisticsPtr->SetLastError(
3878 VE_INVALID_ARGUMENT, kTraceError,
3879 "StartRecordingPlayout() fileRecorder format isnot correct");
3880 return -1;
3881 }
3882
3883 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
3884 notificationTime) != 0)
3885 {
3886 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
3887 "StartRecordingPlayout() failed to "
3888 "start file recording");
3889 _outputFileRecorderPtr->StopRecording();
3890 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
3891 _outputFileRecorderPtr = NULL;
3892 return -1;
3893 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003894
niklase@google.com470e71d2011-07-07 08:21:25 +00003895 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
3896 _outputFileRecording = true;
3897
3898 return 0;
3899}
3900
3901int Channel::StopRecordingPlayout()
3902{
3903 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
3904 "Channel::StopRecordingPlayout()");
3905
3906 if (!_outputFileRecording)
3907 {
3908 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
3909 "StopRecordingPlayout() isnot recording");
3910 return -1;
3911 }
3912
3913
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003914 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003915
3916 if (_outputFileRecorderPtr->StopRecording() != 0)
3917 {
3918 _engineStatisticsPtr->SetLastError(
3919 VE_STOP_RECORDING_FAILED, kTraceError,
3920 "StopRecording() could not stop recording");
3921 return(-1);
3922 }
3923 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
3924 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
3925 _outputFileRecorderPtr = NULL;
3926 _outputFileRecording = false;
3927
3928 return 0;
3929}
3930
3931void
3932Channel::SetMixWithMicStatus(bool mix)
3933{
3934 _mixFileWithMicrophone=mix;
3935}
3936
3937int
3938Channel::GetSpeechOutputLevel(WebRtc_UWord32& level) const
3939{
3940 WebRtc_Word8 currentLevel = _outputAudioLevel.Level();
3941 level = static_cast<WebRtc_Word32> (currentLevel);
3942 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3943 VoEId(_instanceId,_channelId),
3944 "GetSpeechOutputLevel() => level=%u", level);
3945 return 0;
3946}
3947
3948int
3949Channel::GetSpeechOutputLevelFullRange(WebRtc_UWord32& level) const
3950{
3951 WebRtc_Word16 currentLevel = _outputAudioLevel.LevelFullRange();
3952 level = static_cast<WebRtc_Word32> (currentLevel);
3953 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3954 VoEId(_instanceId,_channelId),
3955 "GetSpeechOutputLevelFullRange() => level=%u", level);
3956 return 0;
3957}
3958
3959int
3960Channel::SetMute(bool enable)
3961{
3962 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3963 "Channel::SetMute(enable=%d)", enable);
3964 _mute = enable;
3965 return 0;
3966}
3967
3968bool
3969Channel::Mute() const
3970{
3971 return _mute;
3972}
3973
3974int
3975Channel::SetOutputVolumePan(float left, float right)
3976{
3977 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3978 "Channel::SetOutputVolumePan()");
3979 _panLeft = left;
3980 _panRight = right;
3981 return 0;
3982}
3983
3984int
3985Channel::GetOutputVolumePan(float& left, float& right) const
3986{
3987 left = _panLeft;
3988 right = _panRight;
3989 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3990 VoEId(_instanceId,_channelId),
3991 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3992 return 0;
3993}
3994
3995int
3996Channel::SetChannelOutputVolumeScaling(float scaling)
3997{
3998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3999 "Channel::SetChannelOutputVolumeScaling()");
4000 _outputGain = scaling;
4001 return 0;
4002}
4003
4004int
4005Channel::GetChannelOutputVolumeScaling(float& scaling) const
4006{
4007 scaling = _outputGain;
4008 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4009 VoEId(_instanceId,_channelId),
4010 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
4011 return 0;
4012}
4013
niklase@google.com470e71d2011-07-07 08:21:25 +00004014int
4015Channel::RegisterExternalEncryption(Encryption& encryption)
4016{
4017 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4018 "Channel::RegisterExternalEncryption()");
4019
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004020 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004021
4022 if (_encryptionPtr)
4023 {
4024 _engineStatisticsPtr->SetLastError(
4025 VE_INVALID_OPERATION, kTraceError,
4026 "RegisterExternalEncryption() encryption already enabled");
4027 return -1;
4028 }
4029
4030 _encryptionPtr = &encryption;
4031
4032 _decrypting = true;
4033 _encrypting = true;
4034
4035 return 0;
4036}
4037
4038int
4039Channel::DeRegisterExternalEncryption()
4040{
4041 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4042 "Channel::DeRegisterExternalEncryption()");
4043
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004044 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004045
4046 if (!_encryptionPtr)
4047 {
4048 _engineStatisticsPtr->SetLastError(
4049 VE_INVALID_OPERATION, kTraceWarning,
4050 "DeRegisterExternalEncryption() encryption already disabled");
4051 return 0;
4052 }
4053
4054 _decrypting = false;
4055 _encrypting = false;
4056
4057 _encryptionPtr = NULL;
4058
4059 return 0;
4060}
4061
4062int Channel::SendTelephoneEventOutband(unsigned char eventCode,
4063 int lengthMs, int attenuationDb,
4064 bool playDtmfEvent)
4065{
4066 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4067 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
4068 playDtmfEvent);
4069
4070 _playOutbandDtmfEvent = playDtmfEvent;
4071
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004072 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00004073 attenuationDb) != 0)
4074 {
4075 _engineStatisticsPtr->SetLastError(
4076 VE_SEND_DTMF_FAILED,
4077 kTraceWarning,
4078 "SendTelephoneEventOutband() failed to send event");
4079 return -1;
4080 }
4081 return 0;
4082}
4083
4084int Channel::SendTelephoneEventInband(unsigned char eventCode,
4085 int lengthMs,
4086 int attenuationDb,
4087 bool playDtmfEvent)
4088{
4089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4090 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
4091 playDtmfEvent);
4092
4093 _playInbandDtmfEvent = playDtmfEvent;
4094 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
4095
4096 return 0;
4097}
4098
4099int
4100Channel::SetDtmfPlayoutStatus(bool enable)
4101{
4102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4103 "Channel::SetDtmfPlayoutStatus()");
4104 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
4105 {
4106 _engineStatisticsPtr->SetLastError(
4107 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
4108 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
4109 return -1;
4110 }
4111 return 0;
4112}
4113
4114bool
4115Channel::DtmfPlayoutStatus() const
4116{
4117 return _audioCodingModule.DtmfPlayoutStatus();
4118}
4119
4120int
4121Channel::SetSendTelephoneEventPayloadType(unsigned char type)
4122{
4123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4124 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00004125 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00004126 {
4127 _engineStatisticsPtr->SetLastError(
4128 VE_INVALID_ARGUMENT, kTraceError,
4129 "SetSendTelephoneEventPayloadType() invalid type");
4130 return -1;
4131 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00004132 CodecInst codec;
4133 codec.plfreq = 8000;
4134 codec.pltype = type;
4135 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004136 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004137 {
4138 _engineStatisticsPtr->SetLastError(
4139 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4140 "SetSendTelephoneEventPayloadType() failed to register send"
4141 "payload type");
4142 return -1;
4143 }
4144 _sendTelephoneEventPayloadType = type;
4145 return 0;
4146}
4147
4148int
4149Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
4150{
4151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4152 "Channel::GetSendTelephoneEventPayloadType()");
4153 type = _sendTelephoneEventPayloadType;
4154 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4155 VoEId(_instanceId,_channelId),
4156 "GetSendTelephoneEventPayloadType() => type=%u", type);
4157 return 0;
4158}
4159
niklase@google.com470e71d2011-07-07 08:21:25 +00004160int
4161Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
4162{
4163 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4164 "Channel::UpdateRxVadDetection()");
4165
4166 int vadDecision = 1;
4167
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004168 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004169
4170 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
4171 {
4172 OnRxVadDetected(vadDecision);
4173 _oldVadDecision = vadDecision;
4174 }
4175
4176 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4177 "Channel::UpdateRxVadDetection() => vadDecision=%d",
4178 vadDecision);
4179 return 0;
4180}
4181
4182int
4183Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
4184{
4185 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4186 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004187 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004188
4189 if (_rxVadObserverPtr)
4190 {
4191 _engineStatisticsPtr->SetLastError(
4192 VE_INVALID_OPERATION, kTraceError,
4193 "RegisterRxVadObserver() observer already enabled");
4194 return -1;
4195 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004196 _rxVadObserverPtr = &observer;
4197 _RxVadDetection = true;
4198 return 0;
4199}
4200
4201int
4202Channel::DeRegisterRxVadObserver()
4203{
4204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4205 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004206 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004207
4208 if (!_rxVadObserverPtr)
4209 {
4210 _engineStatisticsPtr->SetLastError(
4211 VE_INVALID_OPERATION, kTraceWarning,
4212 "DeRegisterRxVadObserver() observer already disabled");
4213 return 0;
4214 }
4215 _rxVadObserverPtr = NULL;
4216 _RxVadDetection = false;
4217 return 0;
4218}
4219
4220int
4221Channel::VoiceActivityIndicator(int &activity)
4222{
4223 activity = _sendFrameType;
4224
4225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4226 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
4227 return 0;
4228}
4229
4230#ifdef WEBRTC_VOICE_ENGINE_AGC
4231
4232int
4233Channel::SetRxAgcStatus(const bool enable, const AgcModes mode)
4234{
4235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4236 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
4237 (int)enable, (int)mode);
4238
4239 GainControl::Mode agcMode(GainControl::kFixedDigital);
4240 switch (mode)
4241 {
4242 case kAgcDefault:
4243 agcMode = GainControl::kAdaptiveDigital;
4244 break;
4245 case kAgcUnchanged:
4246 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
4247 break;
4248 case kAgcFixedDigital:
4249 agcMode = GainControl::kFixedDigital;
4250 break;
4251 case kAgcAdaptiveDigital:
4252 agcMode =GainControl::kAdaptiveDigital;
4253 break;
4254 default:
4255 _engineStatisticsPtr->SetLastError(
4256 VE_INVALID_ARGUMENT, kTraceError,
4257 "SetRxAgcStatus() invalid Agc mode");
4258 return -1;
4259 }
4260
4261 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
4262 {
4263 _engineStatisticsPtr->SetLastError(
4264 VE_APM_ERROR, kTraceError,
4265 "SetRxAgcStatus() failed to set Agc mode");
4266 return -1;
4267 }
4268 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
4269 {
4270 _engineStatisticsPtr->SetLastError(
4271 VE_APM_ERROR, kTraceError,
4272 "SetRxAgcStatus() failed to set Agc state");
4273 return -1;
4274 }
4275
4276 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00004277 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
4278
4279 return 0;
4280}
4281
4282int
4283Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
4284{
4285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4286 "Channel::GetRxAgcStatus(enable=?, mode=?)");
4287
4288 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
4289 GainControl::Mode agcMode =
4290 _rxAudioProcessingModulePtr->gain_control()->mode();
4291
4292 enabled = enable;
4293
4294 switch (agcMode)
4295 {
4296 case GainControl::kFixedDigital:
4297 mode = kAgcFixedDigital;
4298 break;
4299 case GainControl::kAdaptiveDigital:
4300 mode = kAgcAdaptiveDigital;
4301 break;
4302 default:
4303 _engineStatisticsPtr->SetLastError(
4304 VE_APM_ERROR, kTraceError,
4305 "GetRxAgcStatus() invalid Agc mode");
4306 return -1;
4307 }
4308
4309 return 0;
4310}
4311
4312int
4313Channel::SetRxAgcConfig(const AgcConfig config)
4314{
4315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4316 "Channel::SetRxAgcConfig()");
4317
4318 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
4319 config.targetLeveldBOv) != 0)
4320 {
4321 _engineStatisticsPtr->SetLastError(
4322 VE_APM_ERROR, kTraceError,
4323 "SetRxAgcConfig() failed to set target peak |level|"
4324 "(or envelope) of the Agc");
4325 return -1;
4326 }
4327 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
4328 config.digitalCompressionGaindB) != 0)
4329 {
4330 _engineStatisticsPtr->SetLastError(
4331 VE_APM_ERROR, kTraceError,
4332 "SetRxAgcConfig() failed to set the range in |gain| the"
4333 " digital compression stage may apply");
4334 return -1;
4335 }
4336 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
4337 config.limiterEnable) != 0)
4338 {
4339 _engineStatisticsPtr->SetLastError(
4340 VE_APM_ERROR, kTraceError,
4341 "SetRxAgcConfig() failed to set hard limiter to the signal");
4342 return -1;
4343 }
4344
4345 return 0;
4346}
4347
4348int
4349Channel::GetRxAgcConfig(AgcConfig& config)
4350{
4351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4352 "Channel::GetRxAgcConfig(config=%?)");
4353
4354 config.targetLeveldBOv =
4355 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
4356 config.digitalCompressionGaindB =
4357 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
4358 config.limiterEnable =
4359 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
4360
4361 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4362 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
4363 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
4364 " limiterEnable=%d",
4365 config.targetLeveldBOv,
4366 config.digitalCompressionGaindB,
4367 config.limiterEnable);
4368
4369 return 0;
4370}
4371
4372#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
4373
4374#ifdef WEBRTC_VOICE_ENGINE_NR
4375
4376int
4377Channel::SetRxNsStatus(const bool enable, const NsModes mode)
4378{
4379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4380 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
4381 (int)enable, (int)mode);
4382
4383 NoiseSuppression::Level nsLevel(
4384 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
4385 switch (mode)
4386 {
4387
4388 case kNsDefault:
4389 nsLevel = (NoiseSuppression::Level)
4390 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
4391 break;
4392 case kNsUnchanged:
4393 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
4394 break;
4395 case kNsConference:
4396 nsLevel = NoiseSuppression::kHigh;
4397 break;
4398 case kNsLowSuppression:
4399 nsLevel = NoiseSuppression::kLow;
4400 break;
4401 case kNsModerateSuppression:
4402 nsLevel = NoiseSuppression::kModerate;
4403 break;
4404 case kNsHighSuppression:
4405 nsLevel = NoiseSuppression::kHigh;
4406 break;
4407 case kNsVeryHighSuppression:
4408 nsLevel = NoiseSuppression::kVeryHigh;
4409 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00004410 }
4411
4412 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
4413 != 0)
4414 {
4415 _engineStatisticsPtr->SetLastError(
4416 VE_APM_ERROR, kTraceError,
4417 "SetRxAgcStatus() failed to set Ns level");
4418 return -1;
4419 }
4420 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
4421 {
4422 _engineStatisticsPtr->SetLastError(
4423 VE_APM_ERROR, kTraceError,
4424 "SetRxAgcStatus() failed to set Agc state");
4425 return -1;
4426 }
4427
4428 _rxNsIsEnabled = enable;
4429 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
4430
4431 return 0;
4432}
4433
4434int
4435Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
4436{
4437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4438 "Channel::GetRxNsStatus(enable=?, mode=?)");
4439
4440 bool enable =
4441 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
4442 NoiseSuppression::Level ncLevel =
4443 _rxAudioProcessingModulePtr->noise_suppression()->level();
4444
4445 enabled = enable;
4446
4447 switch (ncLevel)
4448 {
4449 case NoiseSuppression::kLow:
4450 mode = kNsLowSuppression;
4451 break;
4452 case NoiseSuppression::kModerate:
4453 mode = kNsModerateSuppression;
4454 break;
4455 case NoiseSuppression::kHigh:
4456 mode = kNsHighSuppression;
4457 break;
4458 case NoiseSuppression::kVeryHigh:
4459 mode = kNsVeryHighSuppression;
4460 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00004461 }
4462
4463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4464 VoEId(_instanceId,_channelId),
4465 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
4466 return 0;
4467}
4468
4469#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
4470
4471int
4472Channel::RegisterRTPObserver(VoERTPObserver& observer)
4473{
4474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4475 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004476 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004477
4478 if (_rtpObserverPtr)
4479 {
4480 _engineStatisticsPtr->SetLastError(
4481 VE_INVALID_OPERATION, kTraceError,
4482 "RegisterRTPObserver() observer already enabled");
4483 return -1;
4484 }
4485
4486 _rtpObserverPtr = &observer;
4487 _rtpObserver = true;
4488
4489 return 0;
4490}
4491
4492int
4493Channel::DeRegisterRTPObserver()
4494{
4495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4496 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004497 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004498
4499 if (!_rtpObserverPtr)
4500 {
4501 _engineStatisticsPtr->SetLastError(
4502 VE_INVALID_OPERATION, kTraceWarning,
4503 "DeRegisterRTPObserver() observer already disabled");
4504 return 0;
4505 }
4506
4507 _rtpObserver = false;
4508 _rtpObserverPtr = NULL;
4509
4510 return 0;
4511}
4512
4513int
4514Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
4515{
4516 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4517 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004518 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004519
4520 if (_rtcpObserverPtr)
4521 {
4522 _engineStatisticsPtr->SetLastError(
4523 VE_INVALID_OPERATION, kTraceError,
4524 "RegisterRTCPObserver() observer already enabled");
4525 return -1;
4526 }
4527
4528 _rtcpObserverPtr = &observer;
4529 _rtcpObserver = true;
4530
4531 return 0;
4532}
4533
4534int
4535Channel::DeRegisterRTCPObserver()
4536{
4537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4538 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004539 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004540
4541 if (!_rtcpObserverPtr)
4542 {
4543 _engineStatisticsPtr->SetLastError(
4544 VE_INVALID_OPERATION, kTraceWarning,
4545 "DeRegisterRTCPObserver() observer already disabled");
4546 return 0;
4547 }
4548
4549 _rtcpObserver = false;
4550 _rtcpObserverPtr = NULL;
4551
4552 return 0;
4553}
4554
4555int
4556Channel::SetLocalSSRC(unsigned int ssrc)
4557{
4558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4559 "Channel::SetLocalSSRC()");
4560 if (_sending)
4561 {
4562 _engineStatisticsPtr->SetLastError(
4563 VE_ALREADY_SENDING, kTraceError,
4564 "SetLocalSSRC() already sending");
4565 return -1;
4566 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004567 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004568 {
4569 _engineStatisticsPtr->SetLastError(
4570 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4571 "SetLocalSSRC() failed to set SSRC");
4572 return -1;
4573 }
4574 return 0;
4575}
4576
4577int
4578Channel::GetLocalSSRC(unsigned int& ssrc)
4579{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004580 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004581 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4582 VoEId(_instanceId,_channelId),
4583 "GetLocalSSRC() => ssrc=%lu", ssrc);
4584 return 0;
4585}
4586
4587int
4588Channel::GetRemoteSSRC(unsigned int& ssrc)
4589{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004590 ssrc = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004591 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4592 VoEId(_instanceId,_channelId),
4593 "GetRemoteSSRC() => ssrc=%lu", ssrc);
4594 return 0;
4595}
4596
4597int
4598Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
4599{
4600 if (arrCSRC == NULL)
4601 {
4602 _engineStatisticsPtr->SetLastError(
4603 VE_INVALID_ARGUMENT, kTraceError,
4604 "GetRemoteCSRCs() invalid array argument");
4605 return -1;
4606 }
4607 WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize];
4608 WebRtc_Word32 CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004609 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004610 if (CSRCs > 0)
4611 {
4612 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(WebRtc_UWord32));
4613 for (int i = 0; i < (int) CSRCs; i++)
4614 {
4615 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4616 VoEId(_instanceId, _channelId),
4617 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
4618 }
4619 } else
4620 {
4621 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4622 VoEId(_instanceId, _channelId),
4623 "GetRemoteCSRCs() => list is empty!");
4624 }
4625 return CSRCs;
4626}
4627
4628int
4629Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
4630{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004631 if (_rtpAudioProc.get() == NULL)
4632 {
4633 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
4634 _channelId)));
4635 if (_rtpAudioProc.get() == NULL)
4636 {
4637 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
4638 "Failed to create AudioProcessing");
4639 return -1;
4640 }
4641 }
4642
4643 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
4644 AudioProcessing::kNoError)
4645 {
4646 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
4647 "Failed to enable AudioProcessing::level_estimator()");
4648 }
4649
niklase@google.com470e71d2011-07-07 08:21:25 +00004650 _includeAudioLevelIndication = enable;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004651 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00004652}
4653int
4654Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
4655{
4656 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4657 VoEId(_instanceId,_channelId),
4658 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
4659 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004660 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00004661}
4662
4663int
4664Channel::SetRTCPStatus(bool enable)
4665{
4666 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4667 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004668 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00004669 kRtcpCompound : kRtcpOff) != 0)
4670 {
4671 _engineStatisticsPtr->SetLastError(
4672 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4673 "SetRTCPStatus() failed to set RTCP status");
4674 return -1;
4675 }
4676 return 0;
4677}
4678
4679int
4680Channel::GetRTCPStatus(bool& enabled)
4681{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004682 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004683 enabled = (method != kRtcpOff);
4684 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4685 VoEId(_instanceId,_channelId),
4686 "GetRTCPStatus() => enabled=%d", enabled);
4687 return 0;
4688}
4689
4690int
4691Channel::SetRTCP_CNAME(const char cName[256])
4692{
4693 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4694 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004695 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004696 {
4697 _engineStatisticsPtr->SetLastError(
4698 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4699 "SetRTCP_CNAME() failed to set RTCP CNAME");
4700 return -1;
4701 }
4702 return 0;
4703}
4704
4705int
4706Channel::GetRTCP_CNAME(char cName[256])
4707{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004708 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004709 {
4710 _engineStatisticsPtr->SetLastError(
4711 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4712 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
4713 return -1;
4714 }
4715 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4716 VoEId(_instanceId, _channelId),
4717 "GetRTCP_CNAME() => cName=%s", cName);
4718 return 0;
4719}
4720
4721int
4722Channel::GetRemoteRTCP_CNAME(char cName[256])
4723{
4724 if (cName == NULL)
4725 {
4726 _engineStatisticsPtr->SetLastError(
4727 VE_INVALID_ARGUMENT, kTraceError,
4728 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
4729 return -1;
4730 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00004731 char cname[RTCP_CNAME_SIZE];
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004732 const WebRtc_UWord32 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4733 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004734 {
4735 _engineStatisticsPtr->SetLastError(
4736 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
4737 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
4738 return -1;
4739 }
4740 strcpy(cName, cname);
4741 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4742 VoEId(_instanceId, _channelId),
4743 "GetRemoteRTCP_CNAME() => cName=%s", cName);
4744 return 0;
4745}
4746
4747int
4748Channel::GetRemoteRTCPData(
4749 unsigned int& NTPHigh,
4750 unsigned int& NTPLow,
4751 unsigned int& timestamp,
4752 unsigned int& playoutTimestamp,
4753 unsigned int* jitter,
4754 unsigned short* fractionLost)
4755{
4756 // --- Information from sender info in received Sender Reports
4757
4758 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004759 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004760 {
4761 _engineStatisticsPtr->SetLastError(
4762 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004763 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00004764 "side");
4765 return -1;
4766 }
4767
4768 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
4769 // and octet count)
4770 NTPHigh = senderInfo.NTPseconds;
4771 NTPLow = senderInfo.NTPfraction;
4772 timestamp = senderInfo.RTPtimeStamp;
4773
4774 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4775 VoEId(_instanceId, _channelId),
4776 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
4777 "timestamp=%lu",
4778 NTPHigh, NTPLow, timestamp);
4779
4780 // --- Locally derived information
4781
4782 // This value is updated on each incoming RTCP packet (0 when no packet
4783 // has been received)
4784 playoutTimestamp = _playoutTimeStampRTCP;
4785
4786 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4787 VoEId(_instanceId, _channelId),
4788 "GetRemoteRTCPData() => playoutTimestamp=%lu",
4789 _playoutTimeStampRTCP);
4790
4791 if (NULL != jitter || NULL != fractionLost)
4792 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004793 // Get all RTCP receiver report blocks that have been received on this
4794 // channel. If we receive RTP packets from a remote source we know the
4795 // remote SSRC and use the report block from him.
4796 // Otherwise use the first report block.
4797 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004798 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004799 remote_stats.empty()) {
4800 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4801 VoEId(_instanceId, _channelId),
4802 "GetRemoteRTCPData() failed to measure statistics due"
4803 " to lack of received RTP and/or RTCP packets");
4804 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00004805 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004806
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004807 WebRtc_UWord32 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004808 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
4809 for (; it != remote_stats.end(); ++it) {
4810 if (it->remoteSSRC == remoteSSRC)
4811 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00004812 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004813
4814 if (it == remote_stats.end()) {
4815 // If we have not received any RTCP packets from this SSRC it probably
4816 // means that we have not received any RTP packets.
4817 // Use the first received report block instead.
4818 it = remote_stats.begin();
4819 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00004820 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004821
xians@webrtc.org79af7342012-01-31 12:22:14 +00004822 if (jitter) {
4823 *jitter = it->jitter;
4824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4825 VoEId(_instanceId, _channelId),
4826 "GetRemoteRTCPData() => jitter = %lu", *jitter);
4827 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00004828
xians@webrtc.org79af7342012-01-31 12:22:14 +00004829 if (fractionLost) {
4830 *fractionLost = it->fractionLost;
4831 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4832 VoEId(_instanceId, _channelId),
4833 "GetRemoteRTCPData() => fractionLost = %lu",
4834 *fractionLost);
4835 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004836 }
4837 return 0;
4838}
4839
4840int
4841Channel::SendApplicationDefinedRTCPPacket(const unsigned char subType,
4842 unsigned int name,
4843 const char* data,
4844 unsigned short dataLengthInBytes)
4845{
4846 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4847 "Channel::SendApplicationDefinedRTCPPacket()");
4848 if (!_sending)
4849 {
4850 _engineStatisticsPtr->SetLastError(
4851 VE_NOT_SENDING, kTraceError,
4852 "SendApplicationDefinedRTCPPacket() not sending");
4853 return -1;
4854 }
4855 if (NULL == data)
4856 {
4857 _engineStatisticsPtr->SetLastError(
4858 VE_INVALID_ARGUMENT, kTraceError,
4859 "SendApplicationDefinedRTCPPacket() invalid data value");
4860 return -1;
4861 }
4862 if (dataLengthInBytes % 4 != 0)
4863 {
4864 _engineStatisticsPtr->SetLastError(
4865 VE_INVALID_ARGUMENT, kTraceError,
4866 "SendApplicationDefinedRTCPPacket() invalid length value");
4867 return -1;
4868 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004869 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004870 if (status == kRtcpOff)
4871 {
4872 _engineStatisticsPtr->SetLastError(
4873 VE_RTCP_ERROR, kTraceError,
4874 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
4875 return -1;
4876 }
4877
4878 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004879 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00004880 subType,
4881 name,
4882 (const unsigned char*) data,
4883 dataLengthInBytes) != 0)
4884 {
4885 _engineStatisticsPtr->SetLastError(
4886 VE_SEND_ERROR, kTraceError,
4887 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
4888 return -1;
4889 }
4890 return 0;
4891}
4892
4893int
4894Channel::GetRTPStatistics(
4895 unsigned int& averageJitterMs,
4896 unsigned int& maxJitterMs,
4897 unsigned int& discardedPackets)
4898{
4899 WebRtc_UWord8 fraction_lost(0);
4900 WebRtc_UWord32 cum_lost(0);
4901 WebRtc_UWord32 ext_max(0);
4902 WebRtc_UWord32 jitter(0);
4903 WebRtc_UWord32 max_jitter(0);
4904
4905 // The jitter statistics is updated for each received RTP packet and is
4906 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004907 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00004908 &cum_lost,
4909 &ext_max,
4910 &jitter,
4911 &max_jitter) != 0)
4912 {
4913 _engineStatisticsPtr->SetLastError(
4914 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004915 "GetRTPStatistics() failed to read RTP statistics from the "
niklase@google.com470e71d2011-07-07 08:21:25 +00004916 "RTP/RTCP module");
4917 }
4918
4919 const WebRtc_Word32 playoutFrequency =
4920 _audioCodingModule.PlayoutFrequency();
4921 if (playoutFrequency > 0)
4922 {
4923 // Scale RTP statistics given the current playout frequency
4924 maxJitterMs = max_jitter / (playoutFrequency / 1000);
4925 averageJitterMs = jitter / (playoutFrequency / 1000);
4926 }
4927
4928 discardedPackets = _numberOfDiscardedPackets;
4929
4930 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4931 VoEId(_instanceId, _channelId),
4932 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004933 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004934 averageJitterMs, maxJitterMs, discardedPackets);
4935 return 0;
4936}
4937
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00004938int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
4939 if (sender_info == NULL) {
4940 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4941 "GetRemoteRTCPSenderInfo() invalid sender_info.");
4942 return -1;
4943 }
4944
4945 // Get the sender info from the latest received RTCP Sender Report.
4946 RTCPSenderInfo rtcp_sender_info;
4947 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
4948 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4949 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
4950 return -1;
4951 }
4952
4953 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
4954 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
4955 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
4956 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
4957 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
4958 return 0;
4959}
4960
4961int Channel::GetRemoteRTCPReportBlocks(
4962 std::vector<ReportBlock>* report_blocks) {
4963 if (report_blocks == NULL) {
4964 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4965 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4966 return -1;
4967 }
4968
4969 // Get the report blocks from the latest received RTCP Sender or Receiver
4970 // Report. Each element in the vector contains the sender's SSRC and a
4971 // report block according to RFC 3550.
4972 std::vector<RTCPReportBlock> rtcp_report_blocks;
4973 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4974 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4975 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4976 return -1;
4977 }
4978
4979 if (rtcp_report_blocks.empty())
4980 return 0;
4981
4982 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4983 for (; it != rtcp_report_blocks.end(); ++it) {
4984 ReportBlock report_block;
4985 report_block.sender_SSRC = it->remoteSSRC;
4986 report_block.source_SSRC = it->sourceSSRC;
4987 report_block.fraction_lost = it->fractionLost;
4988 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4989 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4990 report_block.interarrival_jitter = it->jitter;
4991 report_block.last_SR_timestamp = it->lastSR;
4992 report_block.delay_since_last_SR = it->delaySinceLastSR;
4993 report_blocks->push_back(report_block);
4994 }
4995 return 0;
4996}
4997
niklase@google.com470e71d2011-07-07 08:21:25 +00004998int
4999Channel::GetRTPStatistics(CallStatistics& stats)
5000{
5001 WebRtc_UWord8 fraction_lost(0);
5002 WebRtc_UWord32 cum_lost(0);
5003 WebRtc_UWord32 ext_max(0);
5004 WebRtc_UWord32 jitter(0);
5005 WebRtc_UWord32 max_jitter(0);
5006
5007 // --- Part one of the final structure (four values)
5008
5009 // The jitter statistics is updated for each received RTP packet and is
5010 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005011 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00005012 &cum_lost,
5013 &ext_max,
5014 &jitter,
5015 &max_jitter) != 0)
5016 {
5017 _engineStatisticsPtr->SetLastError(
5018 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
5019 "GetRTPStatistics() failed to read RTP statistics from the "
5020 "RTP/RTCP module");
5021 }
5022
5023 stats.fractionLost = fraction_lost;
5024 stats.cumulativeLost = cum_lost;
5025 stats.extendedMax = ext_max;
5026 stats.jitterSamples = jitter;
5027
5028 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5029 VoEId(_instanceId, _channelId),
5030 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005031 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00005032 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
5033 stats.jitterSamples);
5034
5035 // --- Part two of the final structure (one value)
5036
5037 WebRtc_UWord16 RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005038 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00005039 if (method == kRtcpOff)
5040 {
5041 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5042 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005043 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00005044 "measurements cannot be retrieved");
5045 } else
5046 {
5047 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005048 WebRtc_UWord32 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00005049 if (remoteSSRC > 0)
5050 {
5051 WebRtc_UWord16 avgRTT(0);
5052 WebRtc_UWord16 maxRTT(0);
5053 WebRtc_UWord16 minRTT(0);
5054
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005055 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00005056 != 0)
5057 {
5058 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5059 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005060 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00005061 "the RTP/RTCP module");
5062 }
5063 } else
5064 {
5065 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5066 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005067 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00005068 "RTP packets have been received yet");
5069 }
5070 }
5071
5072 stats.rttMs = static_cast<int> (RTT);
5073
5074 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5075 VoEId(_instanceId, _channelId),
5076 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
5077
5078 // --- Part three of the final structure (four values)
5079
5080 WebRtc_UWord32 bytesSent(0);
5081 WebRtc_UWord32 packetsSent(0);
5082 WebRtc_UWord32 bytesReceived(0);
5083 WebRtc_UWord32 packetsReceived(0);
5084
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005085 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
niklase@google.com470e71d2011-07-07 08:21:25 +00005086 &packetsSent,
5087 &bytesReceived,
5088 &packetsReceived) != 0)
5089 {
5090 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5091 VoEId(_instanceId, _channelId),
5092 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005093 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00005094 }
5095
5096 stats.bytesSent = bytesSent;
5097 stats.packetsSent = packetsSent;
5098 stats.bytesReceived = bytesReceived;
5099 stats.packetsReceived = packetsReceived;
5100
5101 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5102 VoEId(_instanceId, _channelId),
5103 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005104 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00005105 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
5106 stats.packetsReceived);
5107
5108 return 0;
5109}
5110
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005111int Channel::SetFECStatus(bool enable, int redPayloadtype) {
5112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
5113 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00005114
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005115 if (enable) {
5116 if (redPayloadtype < 0 || redPayloadtype > 127) {
5117 _engineStatisticsPtr->SetLastError(
5118 VE_PLTYPE_ERROR, kTraceError,
5119 "SetFECStatus() invalid RED payload type");
5120 return -1;
5121 }
5122
5123 if (SetRedPayloadType(redPayloadtype) < 0) {
5124 _engineStatisticsPtr->SetLastError(
5125 VE_CODEC_ERROR, kTraceError,
5126 "SetSecondarySendCodec() Failed to register RED ACM");
5127 return -1;
5128 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005129 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005130
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005131 if (_audioCodingModule.SetFECStatus(enable) != 0) {
5132 _engineStatisticsPtr->SetLastError(
5133 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5134 "SetFECStatus() failed to set FEC state in the ACM");
5135 return -1;
5136 }
5137 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005138}
5139
5140int
5141Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
5142{
5143 enabled = _audioCodingModule.FECStatus();
5144 if (enabled)
5145 {
5146 WebRtc_Word8 payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005147 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005148 {
5149 _engineStatisticsPtr->SetLastError(
5150 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5151 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
5152 "module");
5153 return -1;
5154 }
5155 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5156 VoEId(_instanceId, _channelId),
5157 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
5158 enabled, redPayloadtype);
5159 return 0;
5160 }
5161 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5162 VoEId(_instanceId, _channelId),
5163 "GetFECStatus() => enabled=%d", enabled);
5164 return 0;
5165}
5166
5167int
niklase@google.com470e71d2011-07-07 08:21:25 +00005168Channel::StartRTPDump(const char fileNameUTF8[1024],
5169 RTPDirections direction)
5170{
5171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
5172 "Channel::StartRTPDump()");
5173 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
5174 {
5175 _engineStatisticsPtr->SetLastError(
5176 VE_INVALID_ARGUMENT, kTraceError,
5177 "StartRTPDump() invalid RTP direction");
5178 return -1;
5179 }
5180 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
5181 &_rtpDumpIn : &_rtpDumpOut;
5182 if (rtpDumpPtr == NULL)
5183 {
5184 assert(false);
5185 return -1;
5186 }
5187 if (rtpDumpPtr->IsActive())
5188 {
5189 rtpDumpPtr->Stop();
5190 }
5191 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
5192 {
5193 _engineStatisticsPtr->SetLastError(
5194 VE_BAD_FILE, kTraceError,
5195 "StartRTPDump() failed to create file");
5196 return -1;
5197 }
5198 return 0;
5199}
5200
5201int
5202Channel::StopRTPDump(RTPDirections direction)
5203{
5204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
5205 "Channel::StopRTPDump()");
5206 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
5207 {
5208 _engineStatisticsPtr->SetLastError(
5209 VE_INVALID_ARGUMENT, kTraceError,
5210 "StopRTPDump() invalid RTP direction");
5211 return -1;
5212 }
5213 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
5214 &_rtpDumpIn : &_rtpDumpOut;
5215 if (rtpDumpPtr == NULL)
5216 {
5217 assert(false);
5218 return -1;
5219 }
5220 if (!rtpDumpPtr->IsActive())
5221 {
5222 return 0;
5223 }
5224 return rtpDumpPtr->Stop();
5225}
5226
5227bool
5228Channel::RTPDumpIsActive(RTPDirections direction)
5229{
5230 if ((direction != kRtpIncoming) &&
5231 (direction != kRtpOutgoing))
5232 {
5233 _engineStatisticsPtr->SetLastError(
5234 VE_INVALID_ARGUMENT, kTraceError,
5235 "RTPDumpIsActive() invalid RTP direction");
5236 return false;
5237 }
5238 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
5239 &_rtpDumpIn : &_rtpDumpOut;
5240 return rtpDumpPtr->IsActive();
5241}
5242
5243int
5244Channel::InsertExtraRTPPacket(unsigned char payloadType,
5245 bool markerBit,
5246 const char* payloadData,
5247 unsigned short payloadSize)
5248{
5249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
5250 "Channel::InsertExtraRTPPacket()");
5251 if (payloadType > 127)
5252 {
5253 _engineStatisticsPtr->SetLastError(
5254 VE_INVALID_PLTYPE, kTraceError,
5255 "InsertExtraRTPPacket() invalid payload type");
5256 return -1;
5257 }
5258 if (payloadData == NULL)
5259 {
5260 _engineStatisticsPtr->SetLastError(
5261 VE_INVALID_ARGUMENT, kTraceError,
5262 "InsertExtraRTPPacket() invalid payload data");
5263 return -1;
5264 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005265 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00005266 {
5267 _engineStatisticsPtr->SetLastError(
5268 VE_INVALID_ARGUMENT, kTraceError,
5269 "InsertExtraRTPPacket() invalid payload size");
5270 return -1;
5271 }
5272 if (!_sending)
5273 {
5274 _engineStatisticsPtr->SetLastError(
5275 VE_NOT_SENDING, kTraceError,
5276 "InsertExtraRTPPacket() not sending");
5277 return -1;
5278 }
5279
5280 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
5281 // Transport::SendPacket() will be called by the module when the RTP packet
5282 // is created.
5283 // The call to SendOutgoingData() does *not* modify the timestamp and
5284 // payloadtype to ensure that the RTP module generates a valid RTP packet
5285 // (user might utilize a non-registered payload type).
5286 // The marker bit and payload type will be replaced just before the actual
5287 // transmission, i.e., the actual modification is done *after* the RTP
5288 // module has delivered its RTP packet back to the VoE.
5289 // We will use the stored values above when the packet is modified
5290 // (see Channel::SendPacket()).
5291
5292 _extraPayloadType = payloadType;
5293 _extraMarkerBit = markerBit;
5294 _insertExtraRTPPacket = true;
5295
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005296 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00005297 _lastPayloadType,
5298 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00005299 // Leaving the time when this frame was
5300 // received from the capture device as
5301 // undefined for voice for now.
5302 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +00005303 (const WebRtc_UWord8*) payloadData,
5304 payloadSize) != 0)
5305 {
5306 _engineStatisticsPtr->SetLastError(
5307 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5308 "InsertExtraRTPPacket() failed to send extra RTP packet");
5309 return -1;
5310 }
5311
5312 return 0;
5313}
5314
5315WebRtc_UWord32
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005316Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00005317{
5318 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005319 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005320 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005321 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00005322 return 0;
5323}
5324
5325WebRtc_UWord32
xians@google.com0b0665a2011-08-08 08:18:44 +00005326Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00005327{
5328 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5329 "Channel::PrepareEncodeAndSend()");
5330
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005331 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005332 {
5333 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5334 "Channel::PrepareEncodeAndSend() invalid audio frame");
5335 return -1;
5336 }
5337
5338 if (_inputFilePlaying)
5339 {
5340 MixOrReplaceAudioWithFile(mixingFrequency);
5341 }
5342
5343 if (_mute)
5344 {
5345 AudioFrameOperations::Mute(_audioFrame);
5346 }
5347
5348 if (_inputExternalMedia)
5349 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00005350 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005351 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00005352 if (_inputExternalMediaCallbackPtr)
5353 {
5354 _inputExternalMediaCallbackPtr->Process(
5355 _channelId,
5356 kRecordingPerChannel,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005357 (WebRtc_Word16*)_audioFrame.data_,
5358 _audioFrame.samples_per_channel_,
5359 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00005360 isStereo);
5361 }
5362 }
5363
5364 InsertInbandDtmfTone();
5365
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005366 if (_includeAudioLevelIndication)
5367 {
5368 assert(_rtpAudioProc.get() != NULL);
5369
5370 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005371 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005372 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005373 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005374 AudioProcessing::kNoError)
5375 {
5376 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5377 VoEId(_instanceId, _channelId),
5378 "Error setting AudioProcessing sample rate");
5379 return -1;
5380 }
5381 }
5382
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005383 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005384 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005385 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
5386 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00005387 != AudioProcessing::kNoError)
5388 {
5389 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5390 VoEId(_instanceId, _channelId),
5391 "Error setting AudioProcessing channels");
5392 return -1;
5393 }
5394 }
5395
5396 // Performs level analysis only; does not affect the signal.
5397 _rtpAudioProc->ProcessStream(&_audioFrame);
5398 }
5399
niklase@google.com470e71d2011-07-07 08:21:25 +00005400 return 0;
5401}
5402
5403WebRtc_UWord32
5404Channel::EncodeAndSend()
5405{
5406 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5407 "Channel::EncodeAndSend()");
5408
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005409 assert(_audioFrame.num_channels_ <= 2);
5410 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005411 {
5412 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5413 "Channel::EncodeAndSend() invalid audio frame");
5414 return -1;
5415 }
5416
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005417 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00005418
5419 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
5420
5421 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005422 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005423 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
5424 {
5425 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
5426 "Channel::EncodeAndSend() ACM encoding failed");
5427 return -1;
5428 }
5429
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005430 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00005431
5432 // --- Encode if complete frame is ready
5433
5434 // This call will trigger AudioPacketizationCallback::SendData if encoding
5435 // is done and payload is ready for packetization and transmission.
5436 return _audioCodingModule.Process();
5437}
5438
5439int Channel::RegisterExternalMediaProcessing(
5440 ProcessingTypes type,
5441 VoEMediaProcess& processObject)
5442{
5443 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5444 "Channel::RegisterExternalMediaProcessing()");
5445
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00005446 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005447
5448 if (kPlaybackPerChannel == type)
5449 {
5450 if (_outputExternalMediaCallbackPtr)
5451 {
5452 _engineStatisticsPtr->SetLastError(
5453 VE_INVALID_OPERATION, kTraceError,
5454 "Channel::RegisterExternalMediaProcessing() "
5455 "output external media already enabled");
5456 return -1;
5457 }
5458 _outputExternalMediaCallbackPtr = &processObject;
5459 _outputExternalMedia = true;
5460 }
5461 else if (kRecordingPerChannel == type)
5462 {
5463 if (_inputExternalMediaCallbackPtr)
5464 {
5465 _engineStatisticsPtr->SetLastError(
5466 VE_INVALID_OPERATION, kTraceError,
5467 "Channel::RegisterExternalMediaProcessing() "
5468 "output external media already enabled");
5469 return -1;
5470 }
5471 _inputExternalMediaCallbackPtr = &processObject;
5472 _inputExternalMedia = true;
5473 }
5474 return 0;
5475}
5476
5477int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
5478{
5479 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5480 "Channel::DeRegisterExternalMediaProcessing()");
5481
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00005482 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005483
5484 if (kPlaybackPerChannel == type)
5485 {
5486 if (!_outputExternalMediaCallbackPtr)
5487 {
5488 _engineStatisticsPtr->SetLastError(
5489 VE_INVALID_OPERATION, kTraceWarning,
5490 "Channel::DeRegisterExternalMediaProcessing() "
5491 "output external media already disabled");
5492 return 0;
5493 }
5494 _outputExternalMedia = false;
5495 _outputExternalMediaCallbackPtr = NULL;
5496 }
5497 else if (kRecordingPerChannel == type)
5498 {
5499 if (!_inputExternalMediaCallbackPtr)
5500 {
5501 _engineStatisticsPtr->SetLastError(
5502 VE_INVALID_OPERATION, kTraceWarning,
5503 "Channel::DeRegisterExternalMediaProcessing() "
5504 "input external media already disabled");
5505 return 0;
5506 }
5507 _inputExternalMedia = false;
5508 _inputExternalMediaCallbackPtr = NULL;
5509 }
5510
5511 return 0;
5512}
5513
roosa@google.com1b60ceb2012-12-12 23:00:29 +00005514int Channel::SetExternalMixing(bool enabled) {
5515 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5516 "Channel::SetExternalMixing(enabled=%d)", enabled);
5517
5518 if (_playing)
5519 {
5520 _engineStatisticsPtr->SetLastError(
5521 VE_INVALID_OPERATION, kTraceError,
5522 "Channel::SetExternalMixing() "
5523 "external mixing cannot be changed while playing.");
5524 return -1;
5525 }
5526
5527 _externalMixing = enabled;
5528
5529 return 0;
5530}
5531
niklase@google.com470e71d2011-07-07 08:21:25 +00005532int
5533Channel::ResetRTCPStatistics()
5534{
5535 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5536 "Channel::ResetRTCPStatistics()");
5537 WebRtc_UWord32 remoteSSRC(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005538 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
5539 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00005540}
5541
5542int
5543Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
5544{
5545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5546 "Channel::GetRoundTripTimeSummary()");
5547 // Override default module outputs for the case when RTCP is disabled.
5548 // This is done to ensure that we are backward compatible with the
5549 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005550 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00005551 {
5552 delaysMs.min = -1;
5553 delaysMs.max = -1;
5554 delaysMs.average = -1;
5555 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5556 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
5557 " valid RTT measurements cannot be retrieved");
5558 return 0;
5559 }
5560
5561 WebRtc_UWord32 remoteSSRC;
5562 WebRtc_UWord16 RTT;
5563 WebRtc_UWord16 avgRTT;
5564 WebRtc_UWord16 maxRTT;
5565 WebRtc_UWord16 minRTT;
5566 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005567 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00005568 if (remoteSSRC == 0)
5569 {
5570 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5571 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
5572 " since no RTP packet has been received yet");
5573 }
5574
5575 // Retrieve RTT statistics from the RTP/RTCP module for the specified
5576 // channel and SSRC. The SSRC is required to parse out the correct source
5577 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005578 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005579 {
5580 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5581 "GetRoundTripTimeSummary unable to retrieve RTT values"
5582 " from the RTCP layer");
5583 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
5584 }
5585 else
5586 {
5587 delaysMs.min = minRTT;
5588 delaysMs.max = maxRTT;
5589 delaysMs.average = avgRTT;
5590 }
5591 return 0;
5592}
5593
5594int
5595Channel::GetNetworkStatistics(NetworkStatistics& stats)
5596{
5597 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5598 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005599 ACMNetworkStatistics acm_stats;
5600 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
5601 if (return_value >= 0) {
5602 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
5603 }
5604 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00005605}
5606
5607int
niklase@google.com470e71d2011-07-07 08:21:25 +00005608Channel::GetDelayEstimate(int& delayMs) const
5609{
5610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5611 "Channel::GetDelayEstimate()");
5612 delayMs = (_averageDelayMs + 5) / 10 + _recPacketDelayMs;
5613 return 0;
5614}
5615
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00005616int Channel::SetInitialPlayoutDelay(int delay_ms)
5617{
5618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5619 "Channel::SetInitialPlayoutDelay()");
5620 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
5621 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
5622 {
5623 _engineStatisticsPtr->SetLastError(
5624 VE_INVALID_ARGUMENT, kTraceError,
5625 "SetInitialPlayoutDelay() invalid min delay");
5626 return -1;
5627 }
5628 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
5629 {
5630 _engineStatisticsPtr->SetLastError(
5631 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5632 "SetInitialPlayoutDelay() failed to set min playout delay");
5633 return -1;
5634 }
5635 return 0;
5636}
5637
5638
niklase@google.com470e71d2011-07-07 08:21:25 +00005639int
5640Channel::SetMinimumPlayoutDelay(int delayMs)
5641{
5642 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5643 "Channel::SetMinimumPlayoutDelay()");
5644 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
5645 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
5646 {
5647 _engineStatisticsPtr->SetLastError(
5648 VE_INVALID_ARGUMENT, kTraceError,
5649 "SetMinimumPlayoutDelay() invalid min delay");
5650 return -1;
5651 }
5652 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
5653 {
5654 _engineStatisticsPtr->SetLastError(
5655 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5656 "SetMinimumPlayoutDelay() failed to set min playout delay");
5657 return -1;
5658 }
5659 return 0;
5660}
5661
5662int
5663Channel::GetPlayoutTimestamp(unsigned int& timestamp)
5664{
5665 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5666 "Channel::GetPlayoutTimestamp()");
5667 WebRtc_UWord32 playoutTimestamp(0);
5668 if (GetPlayoutTimeStamp(playoutTimestamp) != 0)
5669 {
5670 _engineStatisticsPtr->SetLastError(
5671 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
5672 "GetPlayoutTimestamp() failed to retrieve timestamp");
5673 return -1;
5674 }
5675 timestamp = playoutTimestamp;
5676 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
5677 VoEId(_instanceId,_channelId),
5678 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
5679 return 0;
5680}
5681
5682int
5683Channel::SetInitTimestamp(unsigned int timestamp)
5684{
5685 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5686 "Channel::SetInitTimestamp()");
5687 if (_sending)
5688 {
5689 _engineStatisticsPtr->SetLastError(
5690 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
5691 return -1;
5692 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005693 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005694 {
5695 _engineStatisticsPtr->SetLastError(
5696 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5697 "SetInitTimestamp() failed to set timestamp");
5698 return -1;
5699 }
5700 return 0;
5701}
5702
5703int
5704Channel::SetInitSequenceNumber(short sequenceNumber)
5705{
5706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5707 "Channel::SetInitSequenceNumber()");
5708 if (_sending)
5709 {
5710 _engineStatisticsPtr->SetLastError(
5711 VE_SENDING, kTraceError,
5712 "SetInitSequenceNumber() already sending");
5713 return -1;
5714 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005715 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00005716 {
5717 _engineStatisticsPtr->SetLastError(
5718 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5719 "SetInitSequenceNumber() failed to set sequence number");
5720 return -1;
5721 }
5722 return 0;
5723}
5724
5725int
5726Channel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
5727{
5728 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5729 "Channel::GetRtpRtcp()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005730 rtpRtcpModule = _rtpRtcpModule.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00005731 return 0;
5732}
5733
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005734// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
5735// a shared helper.
niklase@google.com470e71d2011-07-07 08:21:25 +00005736WebRtc_Word32
xians@google.com0b0665a2011-08-08 08:18:44 +00005737Channel::MixOrReplaceAudioWithFile(const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00005738{
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005739 scoped_array<WebRtc_Word16> fileBuffer(new WebRtc_Word16[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005740 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005741
5742 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00005743 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005744
5745 if (_inputFilePlayerPtr == NULL)
5746 {
5747 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5748 VoEId(_instanceId, _channelId),
5749 "Channel::MixOrReplaceAudioWithFile() fileplayer"
5750 " doesnt exist");
5751 return -1;
5752 }
5753
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005754 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00005755 fileSamples,
5756 mixingFrequency) == -1)
5757 {
5758 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5759 VoEId(_instanceId, _channelId),
5760 "Channel::MixOrReplaceAudioWithFile() file mixing "
5761 "failed");
5762 return -1;
5763 }
5764 if (fileSamples == 0)
5765 {
5766 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5767 VoEId(_instanceId, _channelId),
5768 "Channel::MixOrReplaceAudioWithFile() file is ended");
5769 return 0;
5770 }
5771 }
5772
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005773 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005774
5775 if (_mixFileWithMicrophone)
5776 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005777 // Currently file stream is always mono.
5778 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005779 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005780 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005781 fileBuffer.get(),
5782 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005783 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005784 }
5785 else
5786 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005787 // Replace ACM audio with file.
5788 // Currently file stream is always mono.
5789 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00005790 _audioFrame.UpdateFrame(_channelId,
5791 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005792 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005793 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00005794 mixingFrequency,
5795 AudioFrame::kNormalSpeech,
5796 AudioFrame::kVadUnknown,
5797 1);
5798
5799 }
5800 return 0;
5801}
5802
5803WebRtc_Word32
5804Channel::MixAudioWithFile(AudioFrame& audioFrame,
xians@google.com0b0665a2011-08-08 08:18:44 +00005805 const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00005806{
5807 assert(mixingFrequency <= 32000);
5808
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005809 scoped_array<WebRtc_Word16> fileBuffer(new WebRtc_Word16[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005810 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005811
5812 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00005813 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005814
5815 if (_outputFilePlayerPtr == NULL)
5816 {
5817 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5818 VoEId(_instanceId, _channelId),
5819 "Channel::MixAudioWithFile() file mixing failed");
5820 return -1;
5821 }
5822
5823 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005824 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00005825 fileSamples,
5826 mixingFrequency) == -1)
5827 {
5828 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5829 VoEId(_instanceId, _channelId),
5830 "Channel::MixAudioWithFile() file mixing failed");
5831 return -1;
5832 }
5833 }
5834
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005835 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00005836 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005837 // Currently file stream is always mono.
5838 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005839 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005840 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00005841 fileBuffer.get(),
5842 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00005843 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005844 }
5845 else
5846 {
5847 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005848 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00005849 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005850 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005851 return -1;
5852 }
5853
5854 return 0;
5855}
5856
5857int
5858Channel::InsertInbandDtmfTone()
5859{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005860 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00005861 if (_inbandDtmfQueue.PendingDtmf() &&
5862 !_inbandDtmfGenerator.IsAddingTone() &&
5863 _inbandDtmfGenerator.DelaySinceLastTone() >
5864 kMinTelephoneEventSeparationMs)
5865 {
5866 WebRtc_Word8 eventCode(0);
5867 WebRtc_UWord16 lengthMs(0);
5868 WebRtc_UWord8 attenuationDb(0);
5869
5870 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
5871 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
5872 if (_playInbandDtmfEvent)
5873 {
5874 // Add tone to output mixer using a reduced length to minimize
5875 // risk of echo.
5876 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
5877 attenuationDb);
5878 }
5879 }
5880
5881 if (_inbandDtmfGenerator.IsAddingTone())
5882 {
5883 WebRtc_UWord16 frequency(0);
5884 _inbandDtmfGenerator.GetSampleRate(frequency);
5885
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005886 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005887 {
5888 // Update sample rate of Dtmf tone since the mixing frequency
5889 // has changed.
5890 _inbandDtmfGenerator.SetSampleRate(
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005891 (WebRtc_UWord16) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005892 // Reset the tone to be added taking the new sample rate into
5893 // account.
5894 _inbandDtmfGenerator.ResetTone();
5895 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005896
niklase@google.com470e71d2011-07-07 08:21:25 +00005897 WebRtc_Word16 toneBuffer[320];
5898 WebRtc_UWord16 toneSamples(0);
5899 // Get 10ms tone segment and set time since last tone to zero
5900 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5901 {
5902 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5903 VoEId(_instanceId, _channelId),
5904 "Channel::EncodeAndSend() inserting Dtmf failed");
5905 return -1;
5906 }
5907
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005908 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005909 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005910 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005911 sample++)
5912 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005913 for (int channel = 0;
5914 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005915 channel++)
5916 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005917 const int index = sample * _audioFrame.num_channels_ + channel;
5918 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005919 }
5920 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005921
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005922 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005923 } else
5924 {
5925 // Add 10ms to "delay-since-last-tone" counter
5926 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5927 }
5928 return 0;
5929}
5930
5931WebRtc_Word32
5932Channel::GetPlayoutTimeStamp(WebRtc_UWord32& playoutTimestamp)
5933{
5934 WebRtc_UWord32 timestamp(0);
5935 CodecInst currRecCodec;
5936
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005937 if (_audioCodingModule.PlayoutTimestamp(&timestamp) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00005938 {
5939 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5940 "Channel::GetPlayoutTimeStamp() failed to read playout"
5941 " timestamp from the ACM");
5942 return -1;
5943 }
5944
5945 WebRtc_UWord16 delayMS(0);
5946 if (_audioDeviceModulePtr->PlayoutDelay(&delayMS) == -1)
5947 {
5948 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5949 "Channel::GetPlayoutTimeStamp() failed to read playout"
5950 " delay from the ADM");
5951 return -1;
5952 }
5953
5954 WebRtc_Word32 playoutFrequency = _audioCodingModule.PlayoutFrequency();
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005955 if (_audioCodingModule.ReceiveCodec(&currRecCodec) == 0) {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005956 if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) {
5957 playoutFrequency = 8000;
5958 } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) {
5959 playoutFrequency = 48000;
5960 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005961 }
5962 timestamp -= (delayMS * (playoutFrequency/1000));
5963
5964 playoutTimestamp = timestamp;
5965
5966 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5967 "Channel::GetPlayoutTimeStamp() => playoutTimestamp = %lu",
5968 playoutTimestamp);
5969 return 0;
5970}
5971
5972void
5973Channel::ResetDeadOrAliveCounters()
5974{
5975 _countDeadDetections = 0;
5976 _countAliveDetections = 0;
5977}
5978
5979void
5980Channel::UpdateDeadOrAliveCounters(bool alive)
5981{
5982 if (alive)
5983 _countAliveDetections++;
5984 else
5985 _countDeadDetections++;
5986}
5987
5988int
5989Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5990{
5991 bool enabled;
5992 WebRtc_UWord8 timeSec;
5993
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005994 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00005995 if (!enabled)
5996 return (-1);
5997
5998 countDead = static_cast<int> (_countDeadDetections);
5999 countAlive = static_cast<int> (_countAliveDetections);
6000 return 0;
6001}
6002
6003WebRtc_Word32
6004Channel::SendPacketRaw(const void *data, int len, bool RTCP)
6005{
6006 if (_transportPtr == NULL)
6007 {
6008 return -1;
6009 }
6010 if (!RTCP)
6011 {
6012 return _transportPtr->SendPacket(_channelId, data, len);
6013 }
6014 else
6015 {
6016 return _transportPtr->SendRTCPPacket(_channelId, data, len);
6017 }
6018}
6019
6020WebRtc_Word32
6021Channel::UpdatePacketDelay(const WebRtc_UWord32 timestamp,
6022 const WebRtc_UWord16 sequenceNumber)
6023{
6024 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
6025 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
6026 timestamp, sequenceNumber);
6027
6028 WebRtc_Word32 rtpReceiveFrequency(0);
6029
6030 // Get frequency of last received payload
6031 rtpReceiveFrequency = _audioCodingModule.ReceiveFrequency();
6032
6033 CodecInst currRecCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00006034 if (_audioCodingModule.ReceiveCodec(&currRecCodec) == 0) {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006035 if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) {
6036 // Even though the actual sampling rate for G.722 audio is
6037 // 16,000 Hz, the RTP clock rate for the G722 payload format is
6038 // 8,000 Hz because that value was erroneously assigned in
6039 // RFC 1890 and must remain unchanged for backward compatibility.
6040 rtpReceiveFrequency = 8000;
6041 } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) {
6042 // We are resampling Opus internally to 32,000 Hz until all our
6043 // DSP routines can operate at 48,000 Hz, but the RTP clock
6044 // rate for the Opus payload format is standardized to 48,000 Hz,
6045 // because that is the maximum supported decoding sampling rate.
6046 rtpReceiveFrequency = 48000;
6047 }
niklase@google.com470e71d2011-07-07 08:21:25 +00006048 }
6049
6050 const WebRtc_UWord32 timeStampDiff = timestamp - _playoutTimeStampRTP;
6051 WebRtc_UWord32 timeStampDiffMs(0);
6052
6053 if (timeStampDiff > 0)
6054 {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006055 switch (rtpReceiveFrequency) {
6056 case 8000:
6057 timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff >> 3);
6058 break;
6059 case 16000:
6060 timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff >> 4);
6061 break;
6062 case 32000:
6063 timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff >> 5);
6064 break;
6065 case 48000:
6066 timeStampDiffMs = static_cast<WebRtc_UWord32>(timeStampDiff / 48);
6067 break;
6068 default:
6069 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
6070 VoEId(_instanceId, _channelId),
6071 "Channel::UpdatePacketDelay() invalid sample rate");
6072 timeStampDiffMs = 0;
6073 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00006074 }
niklas.enbom@webrtc.org218c5422013-01-17 22:25:49 +00006075 if (timeStampDiffMs > (2 * kVoiceEngineMaxMinPlayoutDelayMs))
niklase@google.com470e71d2011-07-07 08:21:25 +00006076 {
6077 timeStampDiffMs = 0;
6078 }
6079
6080 if (_averageDelayMs == 0)
6081 {
niklas.enbom@webrtc.org218c5422013-01-17 22:25:49 +00006082 _averageDelayMs = timeStampDiffMs * 10;
niklase@google.com470e71d2011-07-07 08:21:25 +00006083 }
6084 else
6085 {
6086 // Filter average delay value using exponential filter (alpha is
6087 // 7/8). We derive 10*_averageDelayMs here (reduces risk of
6088 // rounding error) and compensate for it in GetDelayEstimate()
6089 // later. Adding 4/8 results in correct rounding.
6090 _averageDelayMs = ((_averageDelayMs*7 + 10*timeStampDiffMs + 4)>>3);
6091 }
6092
6093 if (sequenceNumber - _previousSequenceNumber == 1)
6094 {
6095 WebRtc_UWord16 packetDelayMs = 0;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006096 switch (rtpReceiveFrequency) {
6097 case 8000:
6098 packetDelayMs = static_cast<WebRtc_UWord16>(
niklase@google.com470e71d2011-07-07 08:21:25 +00006099 (timestamp - _previousTimestamp) >> 3);
6100 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006101 case 16000:
6102 packetDelayMs = static_cast<WebRtc_UWord16>(
niklase@google.com470e71d2011-07-07 08:21:25 +00006103 (timestamp - _previousTimestamp) >> 4);
6104 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006105 case 32000:
6106 packetDelayMs = static_cast<WebRtc_UWord16>(
niklase@google.com470e71d2011-07-07 08:21:25 +00006107 (timestamp - _previousTimestamp) >> 5);
6108 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00006109 case 48000:
6110 packetDelayMs = static_cast<WebRtc_UWord16>(
6111 (timestamp - _previousTimestamp) / 48);
6112 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00006113 }
6114
6115 if (packetDelayMs >= 10 && packetDelayMs <= 60)
6116 _recPacketDelayMs = packetDelayMs;
6117 }
6118 }
6119
6120 _previousSequenceNumber = sequenceNumber;
6121 _previousTimestamp = timestamp;
6122
6123 return 0;
6124}
6125
6126void
6127Channel::RegisterReceiveCodecsToRTPModule()
6128{
6129 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
6130 "Channel::RegisterReceiveCodecsToRTPModule()");
6131
6132
6133 CodecInst codec;
6134 const WebRtc_UWord8 nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
6135
6136 for (int idx = 0; idx < nSupportedCodecs; idx++)
6137 {
6138 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00006139 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00006140 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00006141 {
6142 WEBRTC_TRACE(
6143 kTraceWarning,
6144 kTraceVoice,
6145 VoEId(_instanceId, _channelId),
6146 "Channel::RegisterReceiveCodecsToRTPModule() unable"
6147 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
6148 codec.plname, codec.pltype, codec.plfreq,
6149 codec.channels, codec.rate);
6150 }
6151 else
6152 {
6153 WEBRTC_TRACE(
6154 kTraceInfo,
6155 kTraceVoice,
6156 VoEId(_instanceId, _channelId),
6157 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00006158 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00006159 "receiver",
6160 codec.plname, codec.pltype, codec.plfreq,
6161 codec.channels, codec.rate);
6162 }
6163 }
6164}
6165
andrew@webrtc.org50419b02012-11-14 19:07:54 +00006166int Channel::ApmProcessRx(AudioFrame& frame) {
6167 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
6168 // Register the (possibly new) frame parameters.
6169 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00006170 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00006171 }
6172 if (audioproc->set_num_channels(frame.num_channels_,
6173 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00006174 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00006175 }
6176 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00006177 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00006178 }
6179 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00006180}
6181
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006182int Channel::SetSecondarySendCodec(const CodecInst& codec,
6183 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00006184 // Sanity check for payload type.
6185 if (red_payload_type < 0 || red_payload_type > 127) {
6186 _engineStatisticsPtr->SetLastError(
6187 VE_PLTYPE_ERROR, kTraceError,
6188 "SetRedPayloadType() invalid RED payload type");
6189 return -1;
6190 }
6191
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006192 if (SetRedPayloadType(red_payload_type) < 0) {
6193 _engineStatisticsPtr->SetLastError(
6194 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
6195 "SetSecondarySendCodec() Failed to register RED ACM");
6196 return -1;
6197 }
6198 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
6199 _engineStatisticsPtr->SetLastError(
6200 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
6201 "SetSecondarySendCodec() Failed to register secondary send codec in "
6202 "ACM");
6203 return -1;
6204 }
6205
6206 return 0;
6207}
6208
6209void Channel::RemoveSecondarySendCodec() {
6210 _audioCodingModule.UnregisterSecondarySendCodec();
6211}
6212
6213int Channel::GetSecondarySendCodec(CodecInst* codec) {
6214 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
6215 _engineStatisticsPtr->SetLastError(
6216 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
6217 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
6218 return -1;
6219 }
6220 return 0;
6221}
6222
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00006223// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006224int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006225 CodecInst codec;
6226 bool found_red = false;
6227
6228 // Get default RED settings from the ACM database
6229 const int num_codecs = AudioCodingModule::NumberOfCodecs();
6230 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00006231 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006232 if (!STR_CASE_CMP(codec.plname, "RED")) {
6233 found_red = true;
6234 break;
6235 }
6236 }
6237
6238 if (!found_red) {
6239 _engineStatisticsPtr->SetLastError(
6240 VE_CODEC_ERROR, kTraceError,
6241 "SetRedPayloadType() RED is not supported");
6242 return -1;
6243 }
6244
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00006245 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00006246 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
6247 _engineStatisticsPtr->SetLastError(
6248 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
6249 "SetRedPayloadType() RED registration in ACM module failed");
6250 return -1;
6251 }
6252
6253 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
6254 _engineStatisticsPtr->SetLastError(
6255 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
6256 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
6257 return -1;
6258 }
6259 return 0;
6260}
6261
niklase@google.com470e71d2011-07-07 08:21:25 +00006262} // namespace voe
niklase@google.com470e71d2011-07-07 08:21:25 +00006263} // namespace webrtc