blob: 0702d85bddf9102117186ca9f435280ed0d79b42 [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
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000016#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/utility/interface/audio_frame_operations.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/utility/interface/rtp_dump.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/voice_engine/include/voe_base.h"
27#include "webrtc/voice_engine/include/voe_external_media.h"
28#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
29#include "webrtc/voice_engine/output_mixer.h"
30#include "webrtc/voice_engine/statistics.h"
31#include "webrtc/voice_engine/transmit_mixer.h"
32#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34#if defined(_WIN32)
35#include <Qos.h>
36#endif
37
andrew@webrtc.org50419b02012-11-14 19:07:54 +000038namespace webrtc {
39namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000040
pbos@webrtc.org6141e132013-04-09 10:09:10 +000041int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000042Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000043 uint8_t payloadType,
44 uint32_t timeStamp,
45 const uint8_t* payloadData,
46 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000047 const RTPFragmentationHeader* fragmentation)
48{
49 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
50 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
51 " payloadSize=%u, fragmentation=0x%x)",
52 frameType, payloadType, timeStamp, payloadSize, fragmentation);
53
54 if (_includeAudioLevelIndication)
55 {
56 // Store current audio level in the RTP/RTCP module.
57 // The level will be used in combination with voice-activity state
58 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000059 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000060 }
61
62 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
63 // packetization.
64 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000065 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000066 payloadType,
67 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000068 // Leaving the time when this frame was
69 // received from the capture device as
70 // undefined for voice for now.
71 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000072 payloadData,
73 payloadSize,
74 fragmentation) == -1)
75 {
76 _engineStatisticsPtr->SetLastError(
77 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
78 "Channel::SendData() failed to send data to RTP/RTCP module");
79 return -1;
80 }
81
82 _lastLocalTimeStamp = timeStamp;
83 _lastPayloadType = payloadType;
84
85 return 0;
86}
87
pbos@webrtc.org6141e132013-04-09 10:09:10 +000088int32_t
89Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +000090{
91 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
92 "Channel::InFrameType(frameType=%d)", frameType);
93
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000094 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000095 // 1 indicates speech
96 _sendFrameType = (frameType == 1) ? 1 : 0;
97 return 0;
98}
99
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000100int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000101Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000102{
103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
104 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
105
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000106 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 if (_rxVadObserverPtr)
108 {
109 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
110 }
111
112 return 0;
113}
114
115int
116Channel::SendPacket(int channel, const void *data, int len)
117{
118 channel = VoEChannelId(channel);
119 assert(channel == _channelId);
120
121 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
122 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
123
124 if (_transportPtr == NULL)
125 {
126 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
127 "Channel::SendPacket() failed to send RTP packet due to"
128 " invalid transport object");
129 return -1;
130 }
131
132 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
133 // API
134 if (_insertExtraRTPPacket)
135 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136 uint8_t* rtpHdr = (uint8_t*)data;
137 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (_extraMarkerBit)
139 {
140 M_PT = 0x80; // set the M-bit
141 }
142 M_PT += _extraPayloadType; // set the payload type
143 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
144 _insertExtraRTPPacket = false; // insert one packet only
145 }
146
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 uint8_t* bufferToSendPtr = (uint8_t*)data;
148 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
150 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 {
153 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
154 VoEId(_instanceId,_channelId),
155 "Channel::SendPacket() RTP dump to output file failed");
156 }
157
158 // SRTP or External encryption
159 if (_encrypting)
160 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000161 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
163 if (_encryptionPtr)
164 {
165 if (!_encryptionRTPBufferPtr)
166 {
167 // Allocate memory for encryption buffer one time only
168 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000170 memset(_encryptionRTPBufferPtr, 0,
171 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
173
174 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000175 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 _encryptionPtr->encrypt(_channelId,
177 bufferToSendPtr,
178 _encryptionRTPBufferPtr,
179 bufferLength,
180 (int*)&encryptedBufferLength);
181 if (encryptedBufferLength <= 0)
182 {
183 _engineStatisticsPtr->SetLastError(
184 VE_ENCRYPTION_FAILED,
185 kTraceError, "Channel::SendPacket() encryption failed");
186 return -1;
187 }
188
189 // Replace default data buffer with encrypted buffer
190 bufferToSendPtr = _encryptionRTPBufferPtr;
191 bufferLength = encryptedBufferLength;
192 }
193 }
194
195 // Packet transmission using WebRtc socket transport
196 if (!_externalTransport)
197 {
198 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
199 bufferLength);
200 if (n < 0)
201 {
202 WEBRTC_TRACE(kTraceError, kTraceVoice,
203 VoEId(_instanceId,_channelId),
204 "Channel::SendPacket() RTP transmission using WebRtc"
205 " sockets failed");
206 return -1;
207 }
208 return n;
209 }
210
211 // Packet transmission using external transport transport
212 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000213 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
215 int n = _transportPtr->SendPacket(channel,
216 bufferToSendPtr,
217 bufferLength);
218 if (n < 0)
219 {
220 WEBRTC_TRACE(kTraceError, kTraceVoice,
221 VoEId(_instanceId,_channelId),
222 "Channel::SendPacket() RTP transmission using external"
223 " transport failed");
224 return -1;
225 }
226 return n;
227 }
228}
229
230int
231Channel::SendRTCPPacket(int channel, const void *data, int len)
232{
233 channel = VoEChannelId(channel);
234 assert(channel == _channelId);
235
236 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
237 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
238
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000240 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000241 if (_transportPtr == NULL)
242 {
243 WEBRTC_TRACE(kTraceError, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendRTCPPacket() failed to send RTCP packet"
246 " due to invalid transport object");
247 return -1;
248 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 uint8_t* bufferToSendPtr = (uint8_t*)data;
252 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000255 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
258 VoEId(_instanceId,_channelId),
259 "Channel::SendPacket() RTCP dump to output file failed");
260 }
261
262 // SRTP or External encryption
263 if (_encrypting)
264 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000265 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
267 if (_encryptionPtr)
268 {
269 if (!_encryptionRTCPBufferPtr)
270 {
271 // Allocate memory for encryption buffer one time only
272 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000273 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
276 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000277 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 _encryptionPtr->encrypt_rtcp(_channelId,
279 bufferToSendPtr,
280 _encryptionRTCPBufferPtr,
281 bufferLength,
282 (int*)&encryptedBufferLength);
283 if (encryptedBufferLength <= 0)
284 {
285 _engineStatisticsPtr->SetLastError(
286 VE_ENCRYPTION_FAILED, kTraceError,
287 "Channel::SendRTCPPacket() encryption failed");
288 return -1;
289 }
290
291 // Replace default data buffer with encrypted buffer
292 bufferToSendPtr = _encryptionRTCPBufferPtr;
293 bufferLength = encryptedBufferLength;
294 }
295 }
296
297 // Packet transmission using WebRtc socket transport
298 if (!_externalTransport)
299 {
300 int n = _transportPtr->SendRTCPPacket(channel,
301 bufferToSendPtr,
302 bufferLength);
303 if (n < 0)
304 {
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
306 VoEId(_instanceId,_channelId),
307 "Channel::SendRTCPPacket() transmission using WebRtc"
308 " sockets failed");
309 return -1;
310 }
311 return n;
312 }
313
314 // Packet transmission using external transport transport
315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000316 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000317 if (_transportPtr == NULL)
318 {
319 return -1;
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 int n = _transportPtr->SendRTCPPacket(channel,
322 bufferToSendPtr,
323 bufferLength);
324 if (n < 0)
325 {
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using external"
329 " transport failed");
330 return -1;
331 }
332 return n;
333 }
334
335 return len;
336}
337
338void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000339Channel::OnPlayTelephoneEvent(int32_t id,
340 uint8_t event,
341 uint16_t lengthMs,
342 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343{
344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
345 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000346 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
348 if (!_playOutbandDtmfEvent || (event > 15))
349 {
350 // Ignore callback since feedback is disabled or event is not a
351 // Dtmf tone event.
352 return;
353 }
354
355 assert(_outputMixerPtr != NULL);
356
357 // Start playing out the Dtmf tone (if playout is enabled).
358 // Reduce length of tone with 80ms to the reduce risk of echo.
359 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
360}
361
362void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000363Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000367 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000369 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 assert(channel == _channelId);
371
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000372 // Update ssrc so that NTP for AV sync can be updated.
373 _rtpRtcpModule->SetRemoteSSRC(ssrc);
374
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 if (_rtpObserver)
376 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000377 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
379 if (_rtpObserverPtr)
380 {
381 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000382 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 }
384 }
385}
386
pbos@webrtc.org92135212013-05-14 08:31:39 +0000387void Channel::OnIncomingCSRCChanged(int32_t id,
388 uint32_t CSRC,
389 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000390{
391 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
392 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
393 id, CSRC, added);
394
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000395 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 assert(channel == _channelId);
397
398 if (_rtpObserver)
399 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000400 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000401
402 if (_rtpObserverPtr)
403 {
404 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
405 }
406 }
407}
408
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000409void Channel::ResetStatistics(uint32_t ssrc) {
410 StreamStatistician* statistician =
411 rtp_receive_statistics_->GetStatistician(ssrc);
412 if (statistician) {
413 statistician->ResetStatistics();
414 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000415}
416
niklase@google.com470e71d2011-07-07 08:21:25 +0000417void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000418Channel::OnApplicationDataReceived(int32_t id,
419 uint8_t subType,
420 uint32_t name,
421 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000422 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000423{
424 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
425 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
426 " name=%u, length=%u)",
427 id, subType, name, length);
428
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000429 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 assert(channel == _channelId);
431
432 if (_rtcpObserver)
433 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000434 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000435
436 if (_rtcpObserverPtr)
437 {
438 _rtcpObserverPtr->OnApplicationDataReceived(channel,
439 subType,
440 name,
441 data,
442 length);
443 }
444 }
445}
446
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000447int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000448Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000449 int32_t id,
450 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000451 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000452 int frequency,
453 uint8_t channels,
454 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000455{
456 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
457 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
458 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
459 id, payloadType, payloadName, frequency, channels, rate);
460
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000461 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000462
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000463 CodecInst receiveCodec = {0};
464 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000465
466 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 receiveCodec.plfreq = frequency;
468 receiveCodec.channels = channels;
469 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000470 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000471
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000472 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 receiveCodec.pacsize = dummyCodec.pacsize;
474
475 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000476 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 {
478 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000479 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 "Channel::OnInitializeDecoder() invalid codec ("
481 "pt=%d, name=%s) received - 1", payloadType, payloadName);
482 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
483 return -1;
484 }
485
486 return 0;
487}
488
489void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000490Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000491{
492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
493 "Channel::OnPacketTimeout(id=%d)", id);
494
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000495 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 if (_voiceEngineObserverPtr)
497 {
498 if (_receiving || _externalTransport)
499 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000500 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 assert(channel == _channelId);
502 // Ensure that next OnReceivedPacket() callback will trigger
503 // a VE_PACKET_RECEIPT_RESTARTED callback.
504 _rtpPacketTimedOut = true;
505 // Deliver callback to the observer
506 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
507 VoEId(_instanceId,_channelId),
508 "Channel::OnPacketTimeout() => "
509 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
510 _voiceEngineObserverPtr->CallbackOnError(channel,
511 VE_RECEIVE_PACKET_TIMEOUT);
512 }
513 }
514}
515
516void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000517Channel::OnReceivedPacket(int32_t id,
518 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000519{
520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
521 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
522 id, packetType);
523
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000524 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
526 // Notify only for the case when we have restarted an RTP session.
527 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
528 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000529 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 if (_voiceEngineObserverPtr)
531 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000532 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 assert(channel == _channelId);
534 // Reset timeout mechanism
535 _rtpPacketTimedOut = false;
536 // Deliver callback to the observer
537 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
538 VoEId(_instanceId,_channelId),
539 "Channel::OnPacketTimeout() =>"
540 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
541 _voiceEngineObserverPtr->CallbackOnError(
542 channel,
543 VE_PACKET_RECEIPT_RESTARTED);
544 }
545 }
546}
547
548void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000549Channel::OnPeriodicDeadOrAlive(int32_t id,
550 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000551{
552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
553 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
554
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000555 {
556 CriticalSectionScoped cs(&_callbackCritSect);
557 if (!_connectionObserver)
558 return;
559 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000560
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000561 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 assert(channel == _channelId);
563
564 // Use Alive as default to limit risk of false Dead detections
565 bool isAlive(true);
566
567 // Always mark the connection as Dead when the module reports kRtpDead
568 if (kRtpDead == alive)
569 {
570 isAlive = false;
571 }
572
573 // It is possible that the connection is alive even if no RTP packet has
574 // been received for a long time since the other side might use VAD/DTX
575 // and a low SID-packet update rate.
576 if ((kRtpNoRtp == alive) && _playing)
577 {
578 // Detect Alive for all NetEQ states except for the case when we are
579 // in PLC_CNG state.
580 // PLC_CNG <=> background noise only due to long expand or error.
581 // Note that, the case where the other side stops sending during CNG
582 // state will be detected as Alive. Dead is is not set until after
583 // missing RTCP packets for at least twelve seconds (handled
584 // internally by the RTP/RTCP module).
585 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
586 }
587
588 UpdateDeadOrAliveCounters(isAlive);
589
590 // Send callback to the registered observer
591 if (_connectionObserver)
592 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000593 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 if (_connectionObserverPtr)
595 {
596 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
597 }
598 }
599}
600
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000601int32_t
602Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000603 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 const WebRtcRTPHeader* rtpHeader)
605{
606 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
607 "Channel::OnReceivedPayloadData(payloadSize=%d,"
608 " payloadType=%u, audioChannel=%u)",
609 payloadSize,
610 rtpHeader->header.payloadType,
611 rtpHeader->type.Audio.channel);
612
roosa@google.com0870f022012-12-12 21:31:41 +0000613 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
614
niklase@google.com470e71d2011-07-07 08:21:25 +0000615 if (!_playing)
616 {
617 // Avoid inserting into NetEQ when we are not playing. Count the
618 // packet as discarded.
619 WEBRTC_TRACE(kTraceStream, kTraceVoice,
620 VoEId(_instanceId, _channelId),
621 "received packet is discarded since playing is not"
622 " activated");
623 _numberOfDiscardedPackets++;
624 return 0;
625 }
626
627 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000628 if (audio_coding_->IncomingPacket(payloadData,
629 payloadSize,
630 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 {
632 _engineStatisticsPtr->SetLastError(
633 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
634 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
635 return -1;
636 }
637
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000638 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 UpdatePacketDelay(rtpHeader->header.timestamp,
640 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000641
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000642 uint16_t round_trip_time = 0;
643 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
644 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000645
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000646 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000647 round_trip_time);
648 if (!nack_list.empty()) {
649 // Can't use nack_list.data() since it's not supported by all
650 // compilers.
651 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000652 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 return 0;
654}
655
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000656bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
657 int rtp_packet_length) {
658 RTPHeader header;
659 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
660 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
661 "IncomingPacket invalid RTP header");
662 return false;
663 }
664 header.payload_type_frequency =
665 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
666 if (header.payload_type_frequency < 0)
667 return false;
668 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
669}
670
pbos@webrtc.org92135212013-05-14 08:31:39 +0000671int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000672{
673 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
674 "Channel::GetAudioFrame(id=%d)", id);
675
676 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000677 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
678 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 {
680 WEBRTC_TRACE(kTraceError, kTraceVoice,
681 VoEId(_instanceId,_channelId),
682 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000683 // In all likelihood, the audio in this frame is garbage. We return an
684 // error so that the audio mixer module doesn't add it to the mix. As
685 // a result, it won't be played out and the actions skipped here are
686 // irrelevant.
687 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000688 }
689
690 if (_RxVadDetection)
691 {
692 UpdateRxVadDetection(audioFrame);
693 }
694
695 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000698 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000699
700 // Perform far-end AudioProcessing module processing on the received signal
701 if (_rxApmIsEnabled)
702 {
703 ApmProcessRx(audioFrame);
704 }
705
706 // Output volume scaling
707 if (_outputGain < 0.99f || _outputGain > 1.01f)
708 {
709 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
710 }
711
712 // Scale left and/or right channel(s) if stereo and master balance is
713 // active
714
715 if (_panLeft != 1.0f || _panRight != 1.0f)
716 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000717 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
719 // Emulate stereo mode since panning is active.
720 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000721 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 }
723 // For true stereo mode (when we are receiving a stereo signal), no
724 // action is needed.
725
726 // Do the panning operation (the audio frame contains stereo at this
727 // stage)
728 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
729 }
730
731 // Mix decoded PCM output with file if file mixing is enabled
732 if (_outputFilePlaying)
733 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000734 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 }
736
737 // Place channel in on-hold state (~muted) if on-hold is activated
738 if (_outputIsOnHold)
739 {
740 AudioFrameOperations::Mute(audioFrame);
741 }
742
743 // External media
744 if (_outputExternalMedia)
745 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000746 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000747 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 if (_outputExternalMediaCallbackPtr)
749 {
750 _outputExternalMediaCallbackPtr->Process(
751 _channelId,
752 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000753 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000754 audioFrame.samples_per_channel_,
755 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 isStereo);
757 }
758 }
759
760 // Record playout if enabled
761 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000762 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000763
764 if (_outputFileRecording && _outputFileRecorderPtr)
765 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000766 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 }
768 }
769
770 // Measure audio level (0-9)
771 _outputAudioLevel.ComputeLevel(audioFrame);
772
773 return 0;
774}
775
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000776int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000777Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000778{
779 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
780 "Channel::NeededFrequency(id=%d)", id);
781
782 int highestNeeded = 0;
783
784 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000785 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000786
787 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000788 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000790 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 }
792 else
793 {
794 highestNeeded = receiveFrequency;
795 }
796
797 // Special case, if we're playing a file on the playout side
798 // we take that frequency into consideration as well
799 // This is not needed on sending side, since the codec will
800 // limit the spectrum anyway.
801 if (_outputFilePlaying)
802 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000803 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 if (_outputFilePlayerPtr && _outputFilePlaying)
805 {
806 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
807 {
808 highestNeeded=_outputFilePlayerPtr->Frequency();
809 }
810 }
811 }
812
813 return(highestNeeded);
814}
815
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000816int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000817Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000818 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000819 uint32_t instanceId,
820 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000821{
822 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
823 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
824 channelId, instanceId);
825
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000826 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000827 if (channel == NULL)
828 {
829 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
830 VoEId(instanceId,channelId),
831 "Channel::CreateChannel() unable to allocate memory for"
832 " channel");
833 return -1;
834 }
835 return 0;
836}
837
838void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000839Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000840{
841 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
842 "Channel::PlayNotification(id=%d, durationMs=%d)",
843 id, durationMs);
844
845 // Not implement yet
846}
847
848void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000849Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000850{
851 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
852 "Channel::RecordNotification(id=%d, durationMs=%d)",
853 id, durationMs);
854
855 // Not implement yet
856}
857
858void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000859Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860{
861 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
862 "Channel::PlayFileEnded(id=%d)", id);
863
864 if (id == _inputFilePlayerId)
865 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000866 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000867
868 _inputFilePlaying = false;
869 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
870 VoEId(_instanceId,_channelId),
871 "Channel::PlayFileEnded() => input file player module is"
872 " shutdown");
873 }
874 else if (id == _outputFilePlayerId)
875 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000876 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 _outputFilePlaying = false;
879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_instanceId,_channelId),
881 "Channel::PlayFileEnded() => output file player module is"
882 " shutdown");
883 }
884}
885
886void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000887Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000888{
889 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
890 "Channel::RecordFileEnded(id=%d)", id);
891
892 assert(id == _outputFileRecorderId);
893
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000894 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000895
896 _outputFileRecording = false;
897 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
898 VoEId(_instanceId,_channelId),
899 "Channel::RecordFileEnded() => output file recorder module is"
900 " shutdown");
901}
902
pbos@webrtc.org92135212013-05-14 08:31:39 +0000903Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000904 uint32_t instanceId,
905 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
907 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000909 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000910 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000911 rtp_payload_registry_(
912 new RTPPayloadRegistry(channelId,
913 RTPPayloadStrategy::CreateStrategy(true))),
914 rtp_receive_statistics_(ReceiveStatistics::Create(
915 Clock::GetRealTimeClock())),
916 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
917 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
918 this, this, rtp_payload_registry_.get())),
919 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000920 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000921 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 _rtpDumpIn(*RtpDump::CreateRtpDump()),
923 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 _inputFilePlayerPtr(NULL),
927 _outputFilePlayerPtr(NULL),
928 _outputFileRecorderPtr(NULL),
929 // Avoid conflict with other channels by adding 1024 - 1026,
930 // won't use as much as 1024 channels.
931 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
932 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
933 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
934 _inputFilePlaying(false),
935 _outputFilePlaying(false),
936 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000937 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
938 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000939 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000940 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 _inputExternalMediaCallbackPtr(NULL),
942 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000943 _encryptionRTPBufferPtr(NULL),
944 _decryptionRTPBufferPtr(NULL),
945 _encryptionRTCPBufferPtr(NULL),
946 _decryptionRTCPBufferPtr(NULL),
947 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
948 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000949 playout_timestamp_rtp_(0),
950 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000951 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000952 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000953 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000954 _outputMixerPtr(NULL),
955 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000956 _moduleProcessThreadPtr(NULL),
957 _audioDeviceModulePtr(NULL),
958 _voiceEngineObserverPtr(NULL),
959 _callbackCritSectPtr(NULL),
960 _transportPtr(NULL),
961 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000962 rtp_audioproc_(NULL),
963 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000964 _rxVadObserverPtr(NULL),
965 _oldVadDecision(-1),
966 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 _rtpObserverPtr(NULL),
968 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000969 _outputIsOnHold(false),
970 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000971 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000972 _inputIsOnHold(false),
973 _playing(false),
974 _sending(false),
975 _receiving(false),
976 _mixFileWithMicrophone(false),
977 _rtpObserver(false),
978 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 _mute(false),
980 _panLeft(1.0f),
981 _panRight(1.0f),
982 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000983 _encrypting(false),
984 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 _playOutbandDtmfEvent(false),
986 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 _extraPayloadType(0),
988 _insertExtraRTPPacket(false),
989 _extraMarkerBit(false),
990 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000991 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000993 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 _rtpPacketTimedOut(false),
995 _rtpPacketTimeOutIsEnabled(false),
996 _rtpTimeOutSeconds(0),
997 _connectionObserver(false),
998 _connectionObserverPtr(NULL),
999 _countAliveDetections(0),
1000 _countDeadDetections(0),
1001 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001002 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00001003 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 _previousTimestamp(0),
1005 _recPacketDelayMs(20),
1006 _RxVadDetection(false),
1007 _rxApmIsEnabled(false),
1008 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001009 _rxNsIsEnabled(false),
1010 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001011{
1012 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1013 "Channel::Channel() - ctor");
1014 _inbandDtmfQueue.ResetDtmf();
1015 _inbandDtmfGenerator.Init();
1016 _outputAudioLevel.Clear();
1017
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001018 RtpRtcp::Configuration configuration;
1019 configuration.id = VoEModuleId(instanceId, channelId);
1020 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001021 configuration.outgoing_transport = this;
1022 configuration.rtcp_feedback = this;
1023 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001024 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001025
1026 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
niklase@google.com470e71d2011-07-07 08:21:25 +00001027}
1028
1029Channel::~Channel()
1030{
1031 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1032 "Channel::~Channel() - dtor");
1033
1034 if (_outputExternalMedia)
1035 {
1036 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1037 }
1038 if (_inputExternalMedia)
1039 {
1040 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1041 }
1042 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 StopPlayout();
1044
1045 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001046 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 if (_inputFilePlayerPtr)
1048 {
1049 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1050 _inputFilePlayerPtr->StopPlayingFile();
1051 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1052 _inputFilePlayerPtr = NULL;
1053 }
1054 if (_outputFilePlayerPtr)
1055 {
1056 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1057 _outputFilePlayerPtr->StopPlayingFile();
1058 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1059 _outputFilePlayerPtr = NULL;
1060 }
1061 if (_outputFileRecorderPtr)
1062 {
1063 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1064 _outputFileRecorderPtr->StopRecording();
1065 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1066 _outputFileRecorderPtr = NULL;
1067 }
1068 }
1069
1070 // The order to safely shutdown modules in a channel is:
1071 // 1. De-register callbacks in modules
1072 // 2. De-register modules in process thread
1073 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001074 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 {
1076 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1077 VoEId(_instanceId,_channelId),
1078 "~Channel() failed to de-register transport callback"
1079 " (Audio coding module)");
1080 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001081 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001082 {
1083 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1084 VoEId(_instanceId,_channelId),
1085 "~Channel() failed to de-register VAD callback"
1086 " (Audio coding module)");
1087 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001089 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 {
1091 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1092 VoEId(_instanceId,_channelId),
1093 "~Channel() failed to deregister RTP/RTCP module");
1094 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 // End of modules shutdown
1096
1097 // Delete other objects
1098 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1099 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1100 delete [] _encryptionRTPBufferPtr;
1101 delete [] _decryptionRTPBufferPtr;
1102 delete [] _encryptionRTCPBufferPtr;
1103 delete [] _decryptionRTCPBufferPtr;
1104 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 delete &_fileCritSect;
1106}
1107
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001108int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001109Channel::Init()
1110{
1111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1112 "Channel::Init()");
1113
1114 // --- Initial sanity
1115
1116 if ((_engineStatisticsPtr == NULL) ||
1117 (_moduleProcessThreadPtr == NULL))
1118 {
1119 WEBRTC_TRACE(kTraceError, kTraceVoice,
1120 VoEId(_instanceId,_channelId),
1121 "Channel::Init() must call SetEngineInformation() first");
1122 return -1;
1123 }
1124
1125 // --- Add modules to process thread (for periodic schedulation)
1126
1127 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001128 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 if (processThreadFail)
1131 {
1132 _engineStatisticsPtr->SetLastError(
1133 VE_CANNOT_INIT_CHANNEL, kTraceError,
1134 "Channel::Init() modules not registered");
1135 return -1;
1136 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001137 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001138
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001139 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001140#ifdef WEBRTC_CODEC_AVT
1141 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001142 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001143#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001144 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 {
1146 _engineStatisticsPtr->SetLastError(
1147 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1148 "Channel::Init() unable to initialize the ACM - 1");
1149 return -1;
1150 }
1151
1152 // --- RTP/RTCP module initialization
1153
1154 // Ensure that RTCP is enabled by default for the created channel.
1155 // Note that, the module will keep generating RTCP until it is explicitly
1156 // disabled by the user.
1157 // After StopListen (when no sockets exists), RTCP packets will no longer
1158 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001159 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1160 // RTCP is enabled by default.
1161 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
1163 _engineStatisticsPtr->SetLastError(
1164 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1165 "Channel::Init() RTP/RTCP module not initialized");
1166 return -1;
1167 }
1168
1169 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001171 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1172 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001173
1174 if (fail)
1175 {
1176 _engineStatisticsPtr->SetLastError(
1177 VE_CANNOT_INIT_CHANNEL, kTraceError,
1178 "Channel::Init() callbacks not registered");
1179 return -1;
1180 }
1181
1182 // --- Register all supported codecs to the receiving side of the
1183 // RTP/RTCP module
1184
1185 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001186 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001187
1188 for (int idx = 0; idx < nSupportedCodecs; idx++)
1189 {
1190 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001191 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001192 (rtp_receiver_->RegisterReceivePayload(
1193 codec.plname,
1194 codec.pltype,
1195 codec.plfreq,
1196 codec.channels,
1197 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 {
1199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1202 "to RTP/RTCP receiver",
1203 codec.plname, codec.pltype, codec.plfreq,
1204 codec.channels, codec.rate);
1205 }
1206 else
1207 {
1208 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1209 VoEId(_instanceId,_channelId),
1210 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1211 "the RTP/RTCP receiver",
1212 codec.plname, codec.pltype, codec.plfreq,
1213 codec.channels, codec.rate);
1214 }
1215
1216 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001217 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 {
1219 SetSendCodec(codec);
1220 }
1221
1222 // Register default PT for outband 'telephone-event'
1223 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1224 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001225 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001226 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 {
1228 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1229 VoEId(_instanceId,_channelId),
1230 "Channel::Init() failed to register outband "
1231 "'telephone-event' (%d/%d) correctly",
1232 codec.pltype, codec.plfreq);
1233 }
1234 }
1235
1236 if (!STR_CASE_CMP(codec.plname, "CN"))
1237 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001238 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1239 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001240 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 {
1242 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1243 VoEId(_instanceId,_channelId),
1244 "Channel::Init() failed to register CN (%d/%d) "
1245 "correctly - 1",
1246 codec.pltype, codec.plfreq);
1247 }
1248 }
1249#ifdef WEBRTC_CODEC_RED
1250 // Register RED to the receiving side of the ACM.
1251 // We will not receive an OnInitializeDecoder() callback for RED.
1252 if (!STR_CASE_CMP(codec.plname, "RED"))
1253 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001254 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 {
1256 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1257 VoEId(_instanceId,_channelId),
1258 "Channel::Init() failed to register RED (%d/%d) "
1259 "correctly",
1260 codec.pltype, codec.plfreq);
1261 }
1262 }
1263#endif
1264 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001265
niklase@google.com470e71d2011-07-07 08:21:25 +00001266
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001267 if (rx_audioproc_->set_sample_rate_hz(8000))
niklase@google.com470e71d2011-07-07 08:21:25 +00001268 {
1269 _engineStatisticsPtr->SetLastError(
1270 VE_APM_ERROR, kTraceWarning,
1271 "Channel::Init() failed to set the sample rate to 8K for"
1272 " far-end AP module");
1273 }
1274
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001275 if (rx_audioproc_->set_num_channels(1, 1) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 {
1277 _engineStatisticsPtr->SetLastError(
1278 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001279 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 }
1281
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001282 if (rx_audioproc_->high_pass_filter()->Enable(
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1284 {
1285 _engineStatisticsPtr->SetLastError(
1286 VE_APM_ERROR, kTraceWarning,
1287 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001288 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 }
1290
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001291 if (rx_audioproc_->noise_suppression()->set_level(
niklase@google.com470e71d2011-07-07 08:21:25 +00001292 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1293 {
1294 _engineStatisticsPtr->SetLastError(
1295 VE_APM_ERROR, kTraceWarning,
1296 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001297 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001298 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001299 if (rx_audioproc_->noise_suppression()->Enable(
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1301 {
1302 _engineStatisticsPtr->SetLastError(
1303 VE_APM_ERROR, kTraceWarning,
1304 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001305 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 }
1307
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001308 if (rx_audioproc_->gain_control()->set_mode(
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1310 {
1311 _engineStatisticsPtr->SetLastError(
1312 VE_APM_ERROR, kTraceWarning,
1313 "Init() failed to set AGC mode for far-end AP module");
1314 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00001315 if (rx_audioproc_->gain_control()->Enable(
niklase@google.com470e71d2011-07-07 08:21:25 +00001316 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1317 {
1318 _engineStatisticsPtr->SetLastError(
1319 VE_APM_ERROR, kTraceWarning,
1320 "Init() failed to set AGC state for far-end AP module");
1321 }
1322
1323 return 0;
1324}
1325
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001326int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001327Channel::SetEngineInformation(Statistics& engineStatistics,
1328 OutputMixer& outputMixer,
1329 voe::TransmitMixer& transmitMixer,
1330 ProcessThread& moduleProcessThread,
1331 AudioDeviceModule& audioDeviceModule,
1332 VoiceEngineObserver* voiceEngineObserver,
1333 CriticalSectionWrapper* callbackCritSect)
1334{
1335 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1336 "Channel::SetEngineInformation()");
1337 _engineStatisticsPtr = &engineStatistics;
1338 _outputMixerPtr = &outputMixer;
1339 _transmitMixerPtr = &transmitMixer,
1340 _moduleProcessThreadPtr = &moduleProcessThread;
1341 _audioDeviceModulePtr = &audioDeviceModule;
1342 _voiceEngineObserverPtr = voiceEngineObserver;
1343 _callbackCritSectPtr = callbackCritSect;
1344 return 0;
1345}
1346
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001347int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001348Channel::UpdateLocalTimeStamp()
1349{
1350
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001351 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 return 0;
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::StartPlayout()
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::StartPlayout()");
1360 if (_playing)
1361 {
1362 return 0;
1363 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001364
1365 if (!_externalMixing) {
1366 // Add participant as candidates for mixing.
1367 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1368 {
1369 _engineStatisticsPtr->SetLastError(
1370 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1371 "StartPlayout() failed to add participant to mixer");
1372 return -1;
1373 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 }
1375
1376 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001377
1378 if (RegisterFilePlayingToMixer() != 0)
1379 return -1;
1380
niklase@google.com470e71d2011-07-07 08:21:25 +00001381 return 0;
1382}
1383
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001384int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001385Channel::StopPlayout()
1386{
1387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1388 "Channel::StopPlayout()");
1389 if (!_playing)
1390 {
1391 return 0;
1392 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001393
1394 if (!_externalMixing) {
1395 // Remove participant as candidates for mixing
1396 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1397 {
1398 _engineStatisticsPtr->SetLastError(
1399 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1400 "StopPlayout() failed to remove participant from mixer");
1401 return -1;
1402 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 }
1404
1405 _playing = false;
1406 _outputAudioLevel.Clear();
1407
1408 return 0;
1409}
1410
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001411int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001412Channel::StartSend()
1413{
1414 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1415 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001416 // Resume the previous sequence number which was reset by StopSend().
1417 // This needs to be done before |_sending| is set to true.
1418 if (send_sequence_number_)
1419 SetInitSequenceNumber(send_sequence_number_);
1420
niklase@google.com470e71d2011-07-07 08:21:25 +00001421 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001422 // A lock is needed because |_sending| can be accessed or modified by
1423 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001424 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001425
1426 if (_sending)
1427 {
1428 return 0;
1429 }
1430 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001432
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001433 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001434 {
1435 _engineStatisticsPtr->SetLastError(
1436 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1437 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001438 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001439 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 return -1;
1441 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001442
niklase@google.com470e71d2011-07-07 08:21:25 +00001443 return 0;
1444}
1445
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001446int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001447Channel::StopSend()
1448{
1449 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1450 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001451 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001452 // A lock is needed because |_sending| can be accessed or modified by
1453 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001454 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001455
1456 if (!_sending)
1457 {
1458 return 0;
1459 }
1460 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001461 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001462
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001463 // Store the sequence number to be able to pick up the same sequence for
1464 // the next StartSend(). This is needed for restarting device, otherwise
1465 // it might cause libSRTP to complain about packets being replayed.
1466 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1467 // CL is landed. See issue
1468 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1469 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1470
niklase@google.com470e71d2011-07-07 08:21:25 +00001471 // Reset sending SSRC and sequence number and triggers direct transmission
1472 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001473 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1474 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 {
1476 _engineStatisticsPtr->SetLastError(
1477 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1478 "StartSend() RTP/RTCP failed to stop sending");
1479 }
1480
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 return 0;
1482}
1483
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001484int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001485Channel::StartReceiving()
1486{
1487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "Channel::StartReceiving()");
1489 if (_receiving)
1490 {
1491 return 0;
1492 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001493 _receiving = true;
1494 _numberOfDiscardedPackets = 0;
1495 return 0;
1496}
1497
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001498int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001499Channel::StopReceiving()
1500{
1501 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1502 "Channel::StopReceiving()");
1503 if (!_receiving)
1504 {
1505 return 0;
1506 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001507
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001508 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001509 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001510 RegisterReceiveCodecsToRTPModule();
1511 _receiving = false;
1512 return 0;
1513}
1514
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001515int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001516Channel::SetNetEQPlayoutMode(NetEqModes mode)
1517{
1518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1519 "Channel::SetNetEQPlayoutMode()");
1520 AudioPlayoutMode playoutMode(voice);
1521 switch (mode)
1522 {
1523 case kNetEqDefault:
1524 playoutMode = voice;
1525 break;
1526 case kNetEqStreaming:
1527 playoutMode = streaming;
1528 break;
1529 case kNetEqFax:
1530 playoutMode = fax;
1531 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001532 case kNetEqOff:
1533 playoutMode = off;
1534 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001536 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 {
1538 _engineStatisticsPtr->SetLastError(
1539 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1540 "SetNetEQPlayoutMode() failed to set playout mode");
1541 return -1;
1542 }
1543 return 0;
1544}
1545
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001546int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001547Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1548{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001549 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001550 switch (playoutMode)
1551 {
1552 case voice:
1553 mode = kNetEqDefault;
1554 break;
1555 case streaming:
1556 mode = kNetEqStreaming;
1557 break;
1558 case fax:
1559 mode = kNetEqFax;
1560 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001561 case off:
1562 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001563 }
1564 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1565 VoEId(_instanceId,_channelId),
1566 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1567 return 0;
1568}
1569
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001571Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1572{
1573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574 "Channel::SetOnHoldStatus()");
1575 if (mode == kHoldSendAndPlay)
1576 {
1577 _outputIsOnHold = enable;
1578 _inputIsOnHold = enable;
1579 }
1580 else if (mode == kHoldPlayOnly)
1581 {
1582 _outputIsOnHold = enable;
1583 }
1584 if (mode == kHoldSendOnly)
1585 {
1586 _inputIsOnHold = enable;
1587 }
1588 return 0;
1589}
1590
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001591int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001592Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1593{
1594 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1595 "Channel::GetOnHoldStatus()");
1596 enabled = (_outputIsOnHold || _inputIsOnHold);
1597 if (_outputIsOnHold && _inputIsOnHold)
1598 {
1599 mode = kHoldSendAndPlay;
1600 }
1601 else if (_outputIsOnHold && !_inputIsOnHold)
1602 {
1603 mode = kHoldPlayOnly;
1604 }
1605 else if (!_outputIsOnHold && _inputIsOnHold)
1606 {
1607 mode = kHoldSendOnly;
1608 }
1609 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1610 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1611 enabled, mode);
1612 return 0;
1613}
1614
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001615int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001616Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1617{
1618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1619 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001620 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001621
1622 if (_voiceEngineObserverPtr)
1623 {
1624 _engineStatisticsPtr->SetLastError(
1625 VE_INVALID_OPERATION, kTraceError,
1626 "RegisterVoiceEngineObserver() observer already enabled");
1627 return -1;
1628 }
1629 _voiceEngineObserverPtr = &observer;
1630 return 0;
1631}
1632
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001633int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001634Channel::DeRegisterVoiceEngineObserver()
1635{
1636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1637 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001638 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001639
1640 if (!_voiceEngineObserverPtr)
1641 {
1642 _engineStatisticsPtr->SetLastError(
1643 VE_INVALID_OPERATION, kTraceWarning,
1644 "DeRegisterVoiceEngineObserver() observer already disabled");
1645 return 0;
1646 }
1647 _voiceEngineObserverPtr = NULL;
1648 return 0;
1649}
1650
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001651int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001652Channel::GetSendCodec(CodecInst& codec)
1653{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001654 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001655}
1656
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001657int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001658Channel::GetRecCodec(CodecInst& codec)
1659{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001660 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001661}
1662
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001663int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001664Channel::SetSendCodec(const CodecInst& codec)
1665{
1666 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1667 "Channel::SetSendCodec()");
1668
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001669 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 {
1671 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1672 "SetSendCodec() failed to register codec to ACM");
1673 return -1;
1674 }
1675
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001676 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001677 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001678 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1679 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001680 {
1681 WEBRTC_TRACE(
1682 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1683 "SetSendCodec() failed to register codec to"
1684 " RTP/RTCP module");
1685 return -1;
1686 }
1687 }
1688
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001689 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001690 {
1691 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1692 "SetSendCodec() failed to set audio packet size");
1693 return -1;
1694 }
1695
1696 return 0;
1697}
1698
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001699int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001700Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1701{
1702 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1703 "Channel::SetVADStatus(mode=%d)", mode);
1704 // To disable VAD, DTX must be disabled too
1705 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001706 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001707 {
1708 _engineStatisticsPtr->SetLastError(
1709 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1710 "SetVADStatus() failed to set VAD");
1711 return -1;
1712 }
1713 return 0;
1714}
1715
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001716int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001717Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1718{
1719 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1720 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001721 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001722 {
1723 _engineStatisticsPtr->SetLastError(
1724 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1725 "GetVADStatus() failed to get VAD status");
1726 return -1;
1727 }
1728 disabledDTX = !disabledDTX;
1729 return 0;
1730}
1731
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001732int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001733Channel::SetRecPayloadType(const CodecInst& codec)
1734{
1735 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1736 "Channel::SetRecPayloadType()");
1737
1738 if (_playing)
1739 {
1740 _engineStatisticsPtr->SetLastError(
1741 VE_ALREADY_PLAYING, kTraceError,
1742 "SetRecPayloadType() unable to set PT while playing");
1743 return -1;
1744 }
1745 if (_receiving)
1746 {
1747 _engineStatisticsPtr->SetLastError(
1748 VE_ALREADY_LISTENING, kTraceError,
1749 "SetRecPayloadType() unable to set PT while listening");
1750 return -1;
1751 }
1752
1753 if (codec.pltype == -1)
1754 {
1755 // De-register the selected codec (RTP/RTCP module and ACM)
1756
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001757 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001758 CodecInst rxCodec = codec;
1759
1760 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001761 rtp_payload_registry_->ReceivePayloadType(
1762 rxCodec.plname,
1763 rxCodec.plfreq,
1764 rxCodec.channels,
1765 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1766 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001767 rxCodec.pltype = pltype;
1768
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001769 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001770 {
1771 _engineStatisticsPtr->SetLastError(
1772 VE_RTP_RTCP_MODULE_ERROR,
1773 kTraceError,
1774 "SetRecPayloadType() RTP/RTCP-module deregistration "
1775 "failed");
1776 return -1;
1777 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001778 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001779 {
1780 _engineStatisticsPtr->SetLastError(
1781 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1782 "SetRecPayloadType() ACM deregistration failed - 1");
1783 return -1;
1784 }
1785 return 0;
1786 }
1787
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001788 if (rtp_receiver_->RegisterReceivePayload(
1789 codec.plname,
1790 codec.pltype,
1791 codec.plfreq,
1792 codec.channels,
1793 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001794 {
1795 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001796 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1797 if (rtp_receiver_->RegisterReceivePayload(
1798 codec.plname,
1799 codec.pltype,
1800 codec.plfreq,
1801 codec.channels,
1802 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001803 {
1804 _engineStatisticsPtr->SetLastError(
1805 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1806 "SetRecPayloadType() RTP/RTCP-module registration failed");
1807 return -1;
1808 }
1809 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001810 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001811 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001812 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1813 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001814 {
1815 _engineStatisticsPtr->SetLastError(
1816 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1817 "SetRecPayloadType() ACM registration failed - 1");
1818 return -1;
1819 }
1820 }
1821 return 0;
1822}
1823
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001824int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001825Channel::GetRecPayloadType(CodecInst& codec)
1826{
1827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1828 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001829 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001830 if (rtp_payload_registry_->ReceivePayloadType(
1831 codec.plname,
1832 codec.plfreq,
1833 codec.channels,
1834 (codec.rate < 0) ? 0 : codec.rate,
1835 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001836 {
1837 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001838 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001839 "GetRecPayloadType() failed to retrieve RX payload type");
1840 return -1;
1841 }
1842 codec.pltype = payloadType;
1843 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1844 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1845 return 0;
1846}
1847
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001849Channel::SetAMREncFormat(AmrMode mode)
1850{
1851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1852 "Channel::SetAMREncFormat()");
1853
1854 // ACM doesn't support AMR
1855 return -1;
1856}
1857
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001858int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001859Channel::SetAMRDecFormat(AmrMode mode)
1860{
1861 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1862 "Channel::SetAMRDecFormat()");
1863
1864 // ACM doesn't support AMR
1865 return -1;
1866}
1867
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001868int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001869Channel::SetAMRWbEncFormat(AmrMode mode)
1870{
1871 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1872 "Channel::SetAMRWbEncFormat()");
1873
1874 // ACM doesn't support AMR
1875 return -1;
1876
1877}
1878
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001879int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001880Channel::SetAMRWbDecFormat(AmrMode mode)
1881{
1882 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1883 "Channel::SetAMRWbDecFormat()");
1884
1885 // ACM doesn't support AMR
1886 return -1;
1887}
1888
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001889int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001890Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1891{
1892 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1893 "Channel::SetSendCNPayloadType()");
1894
1895 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001896 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001897 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001898 if (frequency == kFreq32000Hz)
1899 samplingFreqHz = 32000;
1900 else if (frequency == kFreq16000Hz)
1901 samplingFreqHz = 16000;
1902
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001903 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001904 {
1905 _engineStatisticsPtr->SetLastError(
1906 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1907 "SetSendCNPayloadType() failed to retrieve default CN codec "
1908 "settings");
1909 return -1;
1910 }
1911
1912 // Modify the payload type (must be set to dynamic range)
1913 codec.pltype = type;
1914
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001915 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001916 {
1917 _engineStatisticsPtr->SetLastError(
1918 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1919 "SetSendCNPayloadType() failed to register CN to ACM");
1920 return -1;
1921 }
1922
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001923 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001924 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001925 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1926 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001927 {
1928 _engineStatisticsPtr->SetLastError(
1929 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1930 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1931 "module");
1932 return -1;
1933 }
1934 }
1935 return 0;
1936}
1937
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001938int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001939Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1940{
1941 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1942 "Channel::SetISACInitTargetRate()");
1943
1944 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001945 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001946 {
1947 _engineStatisticsPtr->SetLastError(
1948 VE_CODEC_ERROR, kTraceError,
1949 "SetISACInitTargetRate() failed to retrieve send codec");
1950 return -1;
1951 }
1952 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1953 {
1954 // This API is only valid if iSAC is setup to run in channel-adaptive
1955 // mode.
1956 // We do not validate the adaptive mode here. It is done later in the
1957 // ConfigISACBandwidthEstimator() API.
1958 _engineStatisticsPtr->SetLastError(
1959 VE_CODEC_ERROR, kTraceError,
1960 "SetISACInitTargetRate() send codec is not iSAC");
1961 return -1;
1962 }
1963
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001964 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001965 if (16000 == sendCodec.plfreq)
1966 {
1967 // Note that 0 is a valid and corresponds to "use default
1968 if ((rateBps != 0 &&
1969 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1970 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1971 {
1972 _engineStatisticsPtr->SetLastError(
1973 VE_INVALID_ARGUMENT, kTraceError,
1974 "SetISACInitTargetRate() invalid target rate - 1");
1975 return -1;
1976 }
1977 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001978 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001979 }
1980 else if (32000 == sendCodec.plfreq)
1981 {
1982 if ((rateBps != 0 &&
1983 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1984 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1985 {
1986 _engineStatisticsPtr->SetLastError(
1987 VE_INVALID_ARGUMENT, kTraceError,
1988 "SetISACInitTargetRate() invalid target rate - 2");
1989 return -1;
1990 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001991 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 }
1993
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001994 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001995 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1996 {
1997 _engineStatisticsPtr->SetLastError(
1998 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1999 "SetISACInitTargetRate() iSAC BWE config failed");
2000 return -1;
2001 }
2002
2003 return 0;
2004}
2005
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002006int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002007Channel::SetISACMaxRate(int rateBps)
2008{
2009 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2010 "Channel::SetISACMaxRate()");
2011
2012 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002013 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002014 {
2015 _engineStatisticsPtr->SetLastError(
2016 VE_CODEC_ERROR, kTraceError,
2017 "SetISACMaxRate() failed to retrieve send codec");
2018 return -1;
2019 }
2020 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2021 {
2022 // This API is only valid if iSAC is selected as sending codec.
2023 _engineStatisticsPtr->SetLastError(
2024 VE_CODEC_ERROR, kTraceError,
2025 "SetISACMaxRate() send codec is not iSAC");
2026 return -1;
2027 }
2028 if (16000 == sendCodec.plfreq)
2029 {
2030 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2031 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2032 {
2033 _engineStatisticsPtr->SetLastError(
2034 VE_INVALID_ARGUMENT, kTraceError,
2035 "SetISACMaxRate() invalid max rate - 1");
2036 return -1;
2037 }
2038 }
2039 else if (32000 == sendCodec.plfreq)
2040 {
2041 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2042 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2043 {
2044 _engineStatisticsPtr->SetLastError(
2045 VE_INVALID_ARGUMENT, kTraceError,
2046 "SetISACMaxRate() invalid max rate - 2");
2047 return -1;
2048 }
2049 }
2050 if (_sending)
2051 {
2052 _engineStatisticsPtr->SetLastError(
2053 VE_SENDING, kTraceError,
2054 "SetISACMaxRate() unable to set max rate while sending");
2055 return -1;
2056 }
2057
2058 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2059 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002060 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002061 {
2062 _engineStatisticsPtr->SetLastError(
2063 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2064 "SetISACMaxRate() failed to set max rate");
2065 return -1;
2066 }
2067
2068 return 0;
2069}
2070
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002071int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002072Channel::SetISACMaxPayloadSize(int sizeBytes)
2073{
2074 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2075 "Channel::SetISACMaxPayloadSize()");
2076 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002077 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002078 {
2079 _engineStatisticsPtr->SetLastError(
2080 VE_CODEC_ERROR, kTraceError,
2081 "SetISACMaxPayloadSize() failed to retrieve send codec");
2082 return -1;
2083 }
2084 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2085 {
2086 _engineStatisticsPtr->SetLastError(
2087 VE_CODEC_ERROR, kTraceError,
2088 "SetISACMaxPayloadSize() send codec is not iSAC");
2089 return -1;
2090 }
2091 if (16000 == sendCodec.plfreq)
2092 {
2093 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2094 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2095 {
2096 _engineStatisticsPtr->SetLastError(
2097 VE_INVALID_ARGUMENT, kTraceError,
2098 "SetISACMaxPayloadSize() invalid max payload - 1");
2099 return -1;
2100 }
2101 }
2102 else if (32000 == sendCodec.plfreq)
2103 {
2104 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2105 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2106 {
2107 _engineStatisticsPtr->SetLastError(
2108 VE_INVALID_ARGUMENT, kTraceError,
2109 "SetISACMaxPayloadSize() invalid max payload - 2");
2110 return -1;
2111 }
2112 }
2113 if (_sending)
2114 {
2115 _engineStatisticsPtr->SetLastError(
2116 VE_SENDING, kTraceError,
2117 "SetISACMaxPayloadSize() unable to set max rate while sending");
2118 return -1;
2119 }
2120
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002121 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002122 {
2123 _engineStatisticsPtr->SetLastError(
2124 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2125 "SetISACMaxPayloadSize() failed to set max payload size");
2126 return -1;
2127 }
2128 return 0;
2129}
2130
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002131int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002132{
2133 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2134 "Channel::RegisterExternalTransport()");
2135
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002136 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002137
niklase@google.com470e71d2011-07-07 08:21:25 +00002138 if (_externalTransport)
2139 {
2140 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2141 kTraceError,
2142 "RegisterExternalTransport() external transport already enabled");
2143 return -1;
2144 }
2145 _externalTransport = true;
2146 _transportPtr = &transport;
2147 return 0;
2148}
2149
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002150int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002151Channel::DeRegisterExternalTransport()
2152{
2153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2154 "Channel::DeRegisterExternalTransport()");
2155
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002156 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002157
niklase@google.com470e71d2011-07-07 08:21:25 +00002158 if (!_transportPtr)
2159 {
2160 _engineStatisticsPtr->SetLastError(
2161 VE_INVALID_OPERATION, kTraceWarning,
2162 "DeRegisterExternalTransport() external transport already "
2163 "disabled");
2164 return 0;
2165 }
2166 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002167 _transportPtr = NULL;
2168 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2169 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002170 return 0;
2171}
2172
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002173int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002174 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2175 "Channel::ReceivedRTPPacket()");
2176
2177 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002178 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002179
2180 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002181 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2182 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002183 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2184 VoEId(_instanceId,_channelId),
2185 "Channel::SendPacket() RTP dump to input file failed");
2186 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002187 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002188 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002189 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2190 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2191 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002192 return -1;
2193 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002194 header.payload_type_frequency =
2195 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002196 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002197 return -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002198 rtp_receive_statistics_->IncomingPacket(header, length,
2199 IsPacketRetransmitted(header));
2200 rtp_payload_registry_->SetIncomingPayloadType(header);
2201 return ReceivePacket(received_packet, length, header,
2202 IsPacketInOrder(header)) ? 0 : -1;
2203}
2204
2205bool Channel::ReceivePacket(const uint8_t* packet,
2206 int packet_length,
2207 const RTPHeader& header,
2208 bool in_order) {
2209 if (rtp_payload_registry_->IsEncapsulated(header)) {
2210 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002211 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002212 const uint8_t* payload = packet + header.headerLength;
2213 int payload_length = packet_length - header.headerLength;
2214 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002215 PayloadUnion payload_specific;
2216 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002217 &payload_specific)) {
2218 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002219 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002220 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2221 payload_specific, in_order);
2222}
2223
2224bool Channel::HandleEncapsulation(const uint8_t* packet,
2225 int packet_length,
2226 const RTPHeader& header) {
2227 if (!rtp_payload_registry_->IsRtx(header))
2228 return false;
2229
2230 // Remove the RTX header and parse the original RTP header.
2231 if (packet_length < header.headerLength)
2232 return false;
2233 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2234 return false;
2235 if (restored_packet_in_use_) {
2236 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2237 "Multiple RTX headers detected, dropping packet");
2238 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002239 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002240 uint8_t* restored_packet_ptr = restored_packet_;
2241 if (!rtp_payload_registry_->RestoreOriginalPacket(
2242 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2243 header)) {
2244 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2245 "Incoming RTX packet: invalid RTP header");
2246 return false;
2247 }
2248 restored_packet_in_use_ = true;
2249 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2250 restored_packet_in_use_ = false;
2251 return ret;
2252}
2253
2254bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2255 StreamStatistician* statistician =
2256 rtp_receive_statistics_->GetStatistician(header.ssrc);
2257 if (!statistician)
2258 return false;
2259 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002260}
2261
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002262bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002263 // Retransmissions are handled separately if RTX is enabled.
2264 if (rtp_payload_registry_->RtxEnabled())
2265 return false;
2266 StreamStatistician* statistician =
2267 rtp_receive_statistics_->GetStatistician(header.ssrc);
2268 if (!statistician)
2269 return false;
2270 // Check if this is a retransmission.
2271 uint16_t min_rtt = 0;
2272 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
2273 return !IsPacketInOrder(header) &&
2274 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002275}
2276
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002277int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002278 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2279 "Channel::ReceivedRTCPPacket()");
2280 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002281 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002282
2283 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002284 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2285 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002286 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2287 VoEId(_instanceId,_channelId),
2288 "Channel::SendPacket() RTCP dump to input file failed");
2289 }
2290
2291 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002292 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2293 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002294 _engineStatisticsPtr->SetLastError(
2295 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2296 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2297 }
2298 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002299}
2300
niklase@google.com470e71d2011-07-07 08:21:25 +00002301int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002302 bool loop,
2303 FileFormats format,
2304 int startPosition,
2305 float volumeScaling,
2306 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002307 const CodecInst* codecInst)
2308{
2309 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2310 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2311 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2312 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2313 startPosition, stopPosition);
2314
2315 if (_outputFilePlaying)
2316 {
2317 _engineStatisticsPtr->SetLastError(
2318 VE_ALREADY_PLAYING, kTraceError,
2319 "StartPlayingFileLocally() is already playing");
2320 return -1;
2321 }
2322
niklase@google.com470e71d2011-07-07 08:21:25 +00002323 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002324 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002325
2326 if (_outputFilePlayerPtr)
2327 {
2328 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2329 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2330 _outputFilePlayerPtr = NULL;
2331 }
2332
2333 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2334 _outputFilePlayerId, (const FileFormats)format);
2335
2336 if (_outputFilePlayerPtr == NULL)
2337 {
2338 _engineStatisticsPtr->SetLastError(
2339 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002340 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002341 return -1;
2342 }
2343
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002344 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002345
2346 if (_outputFilePlayerPtr->StartPlayingFile(
2347 fileName,
2348 loop,
2349 startPosition,
2350 volumeScaling,
2351 notificationTime,
2352 stopPosition,
2353 (const CodecInst*)codecInst) != 0)
2354 {
2355 _engineStatisticsPtr->SetLastError(
2356 VE_BAD_FILE, kTraceError,
2357 "StartPlayingFile() failed to start file playout");
2358 _outputFilePlayerPtr->StopPlayingFile();
2359 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2360 _outputFilePlayerPtr = NULL;
2361 return -1;
2362 }
2363 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2364 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002365 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002366
2367 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002368 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002369
2370 return 0;
2371}
2372
2373int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002374 FileFormats format,
2375 int startPosition,
2376 float volumeScaling,
2377 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002378 const CodecInst* codecInst)
2379{
2380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2381 "Channel::StartPlayingFileLocally(format=%d,"
2382 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2383 format, volumeScaling, startPosition, stopPosition);
2384
2385 if(stream == NULL)
2386 {
2387 _engineStatisticsPtr->SetLastError(
2388 VE_BAD_FILE, kTraceError,
2389 "StartPlayingFileLocally() NULL as input stream");
2390 return -1;
2391 }
2392
2393
2394 if (_outputFilePlaying)
2395 {
2396 _engineStatisticsPtr->SetLastError(
2397 VE_ALREADY_PLAYING, kTraceError,
2398 "StartPlayingFileLocally() is already playing");
2399 return -1;
2400 }
2401
niklase@google.com470e71d2011-07-07 08:21:25 +00002402 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002403 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002404
2405 // Destroy the old instance
2406 if (_outputFilePlayerPtr)
2407 {
2408 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2409 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2410 _outputFilePlayerPtr = NULL;
2411 }
2412
2413 // Create the instance
2414 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2415 _outputFilePlayerId,
2416 (const FileFormats)format);
2417
2418 if (_outputFilePlayerPtr == NULL)
2419 {
2420 _engineStatisticsPtr->SetLastError(
2421 VE_INVALID_ARGUMENT, kTraceError,
2422 "StartPlayingFileLocally() filePlayer format isnot correct");
2423 return -1;
2424 }
2425
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002426 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002427
2428 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2429 volumeScaling,
2430 notificationTime,
2431 stopPosition, codecInst) != 0)
2432 {
2433 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2434 "StartPlayingFile() failed to "
2435 "start file playout");
2436 _outputFilePlayerPtr->StopPlayingFile();
2437 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2438 _outputFilePlayerPtr = NULL;
2439 return -1;
2440 }
2441 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2442 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002443 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002444
2445 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002446 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002447
niklase@google.com470e71d2011-07-07 08:21:25 +00002448 return 0;
2449}
2450
2451int Channel::StopPlayingFileLocally()
2452{
2453 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2454 "Channel::StopPlayingFileLocally()");
2455
2456 if (!_outputFilePlaying)
2457 {
2458 _engineStatisticsPtr->SetLastError(
2459 VE_INVALID_OPERATION, kTraceWarning,
2460 "StopPlayingFileLocally() isnot playing");
2461 return 0;
2462 }
2463
niklase@google.com470e71d2011-07-07 08:21:25 +00002464 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002465 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002466
2467 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2468 {
2469 _engineStatisticsPtr->SetLastError(
2470 VE_STOP_RECORDING_FAILED, kTraceError,
2471 "StopPlayingFile() could not stop playing");
2472 return -1;
2473 }
2474 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2475 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2476 _outputFilePlayerPtr = NULL;
2477 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002478 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002479 // _fileCritSect cannot be taken while calling
2480 // SetAnonymousMixibilityStatus. Refer to comments in
2481 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002482 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2483 {
2484 _engineStatisticsPtr->SetLastError(
2485 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002486 "StopPlayingFile() failed to stop participant from playing as"
2487 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002488 return -1;
2489 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002490
2491 return 0;
2492}
2493
2494int Channel::IsPlayingFileLocally() const
2495{
2496 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2497 "Channel::IsPlayingFileLocally()");
2498
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002499 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002500}
2501
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002502int Channel::RegisterFilePlayingToMixer()
2503{
2504 // Return success for not registering for file playing to mixer if:
2505 // 1. playing file before playout is started on that channel.
2506 // 2. starting playout without file playing on that channel.
2507 if (!_playing || !_outputFilePlaying)
2508 {
2509 return 0;
2510 }
2511
2512 // |_fileCritSect| cannot be taken while calling
2513 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2514 // frames can be pulled by the mixer. Since the frames are generated from
2515 // the file, _fileCritSect will be taken. This would result in a deadlock.
2516 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2517 {
2518 CriticalSectionScoped cs(&_fileCritSect);
2519 _outputFilePlaying = false;
2520 _engineStatisticsPtr->SetLastError(
2521 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2522 "StartPlayingFile() failed to add participant as file to mixer");
2523 _outputFilePlayerPtr->StopPlayingFile();
2524 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2525 _outputFilePlayerPtr = NULL;
2526 return -1;
2527 }
2528
2529 return 0;
2530}
2531
pbos@webrtc.org92135212013-05-14 08:31:39 +00002532int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002533{
2534 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2535 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2536
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002537 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002538
2539 if (!_outputFilePlaying)
2540 {
2541 _engineStatisticsPtr->SetLastError(
2542 VE_INVALID_OPERATION, kTraceError,
2543 "ScaleLocalFilePlayout() isnot playing");
2544 return -1;
2545 }
2546 if ((_outputFilePlayerPtr == NULL) ||
2547 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2548 {
2549 _engineStatisticsPtr->SetLastError(
2550 VE_BAD_ARGUMENT, kTraceError,
2551 "SetAudioScaling() failed to scale the playout");
2552 return -1;
2553 }
2554
2555 return 0;
2556}
2557
2558int Channel::GetLocalPlayoutPosition(int& positionMs)
2559{
2560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2561 "Channel::GetLocalPlayoutPosition(position=?)");
2562
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002563 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002564
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002565 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002566
2567 if (_outputFilePlayerPtr == NULL)
2568 {
2569 _engineStatisticsPtr->SetLastError(
2570 VE_INVALID_OPERATION, kTraceError,
2571 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2572 return -1;
2573 }
2574
2575 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2576 {
2577 _engineStatisticsPtr->SetLastError(
2578 VE_BAD_FILE, kTraceError,
2579 "GetLocalPlayoutPosition() failed");
2580 return -1;
2581 }
2582 positionMs = position;
2583
2584 return 0;
2585}
2586
2587int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002588 bool loop,
2589 FileFormats format,
2590 int startPosition,
2591 float volumeScaling,
2592 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002593 const CodecInst* codecInst)
2594{
2595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2596 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2597 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2598 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2599 startPosition, stopPosition);
2600
2601 if (_inputFilePlaying)
2602 {
2603 _engineStatisticsPtr->SetLastError(
2604 VE_ALREADY_PLAYING, kTraceWarning,
2605 "StartPlayingFileAsMicrophone() filePlayer is playing");
2606 return 0;
2607 }
2608
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002609 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002610
2611 // Destroy the old instance
2612 if (_inputFilePlayerPtr)
2613 {
2614 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2615 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2616 _inputFilePlayerPtr = NULL;
2617 }
2618
2619 // Create the instance
2620 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2621 _inputFilePlayerId, (const FileFormats)format);
2622
2623 if (_inputFilePlayerPtr == NULL)
2624 {
2625 _engineStatisticsPtr->SetLastError(
2626 VE_INVALID_ARGUMENT, kTraceError,
2627 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2628 return -1;
2629 }
2630
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002631 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002632
2633 if (_inputFilePlayerPtr->StartPlayingFile(
2634 fileName,
2635 loop,
2636 startPosition,
2637 volumeScaling,
2638 notificationTime,
2639 stopPosition,
2640 (const CodecInst*)codecInst) != 0)
2641 {
2642 _engineStatisticsPtr->SetLastError(
2643 VE_BAD_FILE, kTraceError,
2644 "StartPlayingFile() failed to start file playout");
2645 _inputFilePlayerPtr->StopPlayingFile();
2646 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2647 _inputFilePlayerPtr = NULL;
2648 return -1;
2649 }
2650 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2651 _inputFilePlaying = true;
2652
2653 return 0;
2654}
2655
2656int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002657 FileFormats format,
2658 int startPosition,
2659 float volumeScaling,
2660 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002661 const CodecInst* codecInst)
2662{
2663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2664 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2665 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2666 format, volumeScaling, startPosition, stopPosition);
2667
2668 if(stream == NULL)
2669 {
2670 _engineStatisticsPtr->SetLastError(
2671 VE_BAD_FILE, kTraceError,
2672 "StartPlayingFileAsMicrophone NULL as input stream");
2673 return -1;
2674 }
2675
2676 if (_inputFilePlaying)
2677 {
2678 _engineStatisticsPtr->SetLastError(
2679 VE_ALREADY_PLAYING, kTraceWarning,
2680 "StartPlayingFileAsMicrophone() is playing");
2681 return 0;
2682 }
2683
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002684 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002685
2686 // Destroy the old instance
2687 if (_inputFilePlayerPtr)
2688 {
2689 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2690 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2691 _inputFilePlayerPtr = NULL;
2692 }
2693
2694 // Create the instance
2695 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2696 _inputFilePlayerId, (const FileFormats)format);
2697
2698 if (_inputFilePlayerPtr == NULL)
2699 {
2700 _engineStatisticsPtr->SetLastError(
2701 VE_INVALID_ARGUMENT, kTraceError,
2702 "StartPlayingInputFile() filePlayer format isnot correct");
2703 return -1;
2704 }
2705
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002706 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002707
2708 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2709 volumeScaling, notificationTime,
2710 stopPosition, codecInst) != 0)
2711 {
2712 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2713 "StartPlayingFile() failed to start "
2714 "file playout");
2715 _inputFilePlayerPtr->StopPlayingFile();
2716 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2717 _inputFilePlayerPtr = NULL;
2718 return -1;
2719 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002720
niklase@google.com470e71d2011-07-07 08:21:25 +00002721 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2722 _inputFilePlaying = true;
2723
2724 return 0;
2725}
2726
2727int Channel::StopPlayingFileAsMicrophone()
2728{
2729 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2730 "Channel::StopPlayingFileAsMicrophone()");
2731
2732 if (!_inputFilePlaying)
2733 {
2734 _engineStatisticsPtr->SetLastError(
2735 VE_INVALID_OPERATION, kTraceWarning,
2736 "StopPlayingFileAsMicrophone() isnot playing");
2737 return 0;
2738 }
2739
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002740 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002741 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2742 {
2743 _engineStatisticsPtr->SetLastError(
2744 VE_STOP_RECORDING_FAILED, kTraceError,
2745 "StopPlayingFile() could not stop playing");
2746 return -1;
2747 }
2748 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2749 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2750 _inputFilePlayerPtr = NULL;
2751 _inputFilePlaying = false;
2752
2753 return 0;
2754}
2755
2756int Channel::IsPlayingFileAsMicrophone() const
2757{
2758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2759 "Channel::IsPlayingFileAsMicrophone()");
2760
2761 return _inputFilePlaying;
2762}
2763
pbos@webrtc.org92135212013-05-14 08:31:39 +00002764int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002765{
2766 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2767 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2768
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002769 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002770
2771 if (!_inputFilePlaying)
2772 {
2773 _engineStatisticsPtr->SetLastError(
2774 VE_INVALID_OPERATION, kTraceError,
2775 "ScaleFileAsMicrophonePlayout() isnot playing");
2776 return -1;
2777 }
2778
2779 if ((_inputFilePlayerPtr == NULL) ||
2780 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2781 {
2782 _engineStatisticsPtr->SetLastError(
2783 VE_BAD_ARGUMENT, kTraceError,
2784 "SetAudioScaling() failed to scale playout");
2785 return -1;
2786 }
2787
2788 return 0;
2789}
2790
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002791int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002792 const CodecInst* codecInst)
2793{
2794 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2795 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2796
2797 if (_outputFileRecording)
2798 {
2799 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2800 "StartRecordingPlayout() is already recording");
2801 return 0;
2802 }
2803
2804 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002805 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002806 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2807
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002808 if ((codecInst != NULL) &&
2809 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002810 {
2811 _engineStatisticsPtr->SetLastError(
2812 VE_BAD_ARGUMENT, kTraceError,
2813 "StartRecordingPlayout() invalid compression");
2814 return(-1);
2815 }
2816 if(codecInst == NULL)
2817 {
2818 format = kFileFormatPcm16kHzFile;
2819 codecInst=&dummyCodec;
2820 }
2821 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2822 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2823 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2824 {
2825 format = kFileFormatWavFile;
2826 }
2827 else
2828 {
2829 format = kFileFormatCompressedFile;
2830 }
2831
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002832 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002833
2834 // Destroy the old instance
2835 if (_outputFileRecorderPtr)
2836 {
2837 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2838 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2839 _outputFileRecorderPtr = NULL;
2840 }
2841
2842 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2843 _outputFileRecorderId, (const FileFormats)format);
2844 if (_outputFileRecorderPtr == NULL)
2845 {
2846 _engineStatisticsPtr->SetLastError(
2847 VE_INVALID_ARGUMENT, kTraceError,
2848 "StartRecordingPlayout() fileRecorder format isnot correct");
2849 return -1;
2850 }
2851
2852 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2853 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2854 {
2855 _engineStatisticsPtr->SetLastError(
2856 VE_BAD_FILE, kTraceError,
2857 "StartRecordingAudioFile() failed to start file recording");
2858 _outputFileRecorderPtr->StopRecording();
2859 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2860 _outputFileRecorderPtr = NULL;
2861 return -1;
2862 }
2863 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2864 _outputFileRecording = true;
2865
2866 return 0;
2867}
2868
2869int Channel::StartRecordingPlayout(OutStream* stream,
2870 const CodecInst* codecInst)
2871{
2872 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2873 "Channel::StartRecordingPlayout()");
2874
2875 if (_outputFileRecording)
2876 {
2877 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2878 "StartRecordingPlayout() is already recording");
2879 return 0;
2880 }
2881
2882 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002883 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002884 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2885
2886 if (codecInst != NULL && codecInst->channels != 1)
2887 {
2888 _engineStatisticsPtr->SetLastError(
2889 VE_BAD_ARGUMENT, kTraceError,
2890 "StartRecordingPlayout() invalid compression");
2891 return(-1);
2892 }
2893 if(codecInst == NULL)
2894 {
2895 format = kFileFormatPcm16kHzFile;
2896 codecInst=&dummyCodec;
2897 }
2898 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2899 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2900 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2901 {
2902 format = kFileFormatWavFile;
2903 }
2904 else
2905 {
2906 format = kFileFormatCompressedFile;
2907 }
2908
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002909 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002910
2911 // Destroy the old instance
2912 if (_outputFileRecorderPtr)
2913 {
2914 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2915 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2916 _outputFileRecorderPtr = NULL;
2917 }
2918
2919 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2920 _outputFileRecorderId, (const FileFormats)format);
2921 if (_outputFileRecorderPtr == NULL)
2922 {
2923 _engineStatisticsPtr->SetLastError(
2924 VE_INVALID_ARGUMENT, kTraceError,
2925 "StartRecordingPlayout() fileRecorder format isnot correct");
2926 return -1;
2927 }
2928
2929 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2930 notificationTime) != 0)
2931 {
2932 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2933 "StartRecordingPlayout() failed to "
2934 "start file recording");
2935 _outputFileRecorderPtr->StopRecording();
2936 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2937 _outputFileRecorderPtr = NULL;
2938 return -1;
2939 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002940
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2942 _outputFileRecording = true;
2943
2944 return 0;
2945}
2946
2947int Channel::StopRecordingPlayout()
2948{
2949 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2950 "Channel::StopRecordingPlayout()");
2951
2952 if (!_outputFileRecording)
2953 {
2954 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2955 "StopRecordingPlayout() isnot recording");
2956 return -1;
2957 }
2958
2959
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002960 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002961
2962 if (_outputFileRecorderPtr->StopRecording() != 0)
2963 {
2964 _engineStatisticsPtr->SetLastError(
2965 VE_STOP_RECORDING_FAILED, kTraceError,
2966 "StopRecording() could not stop recording");
2967 return(-1);
2968 }
2969 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2970 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2971 _outputFileRecorderPtr = NULL;
2972 _outputFileRecording = false;
2973
2974 return 0;
2975}
2976
2977void
2978Channel::SetMixWithMicStatus(bool mix)
2979{
2980 _mixFileWithMicrophone=mix;
2981}
2982
2983int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002984Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002985{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002986 int8_t currentLevel = _outputAudioLevel.Level();
2987 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002988 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2989 VoEId(_instanceId,_channelId),
2990 "GetSpeechOutputLevel() => level=%u", level);
2991 return 0;
2992}
2993
2994int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002995Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002996{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002997 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2998 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002999 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3000 VoEId(_instanceId,_channelId),
3001 "GetSpeechOutputLevelFullRange() => level=%u", level);
3002 return 0;
3003}
3004
3005int
3006Channel::SetMute(bool enable)
3007{
3008 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3009 "Channel::SetMute(enable=%d)", enable);
3010 _mute = enable;
3011 return 0;
3012}
3013
3014bool
3015Channel::Mute() const
3016{
3017 return _mute;
3018}
3019
3020int
3021Channel::SetOutputVolumePan(float left, float right)
3022{
3023 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3024 "Channel::SetOutputVolumePan()");
3025 _panLeft = left;
3026 _panRight = right;
3027 return 0;
3028}
3029
3030int
3031Channel::GetOutputVolumePan(float& left, float& right) const
3032{
3033 left = _panLeft;
3034 right = _panRight;
3035 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3036 VoEId(_instanceId,_channelId),
3037 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3038 return 0;
3039}
3040
3041int
3042Channel::SetChannelOutputVolumeScaling(float scaling)
3043{
3044 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3045 "Channel::SetChannelOutputVolumeScaling()");
3046 _outputGain = scaling;
3047 return 0;
3048}
3049
3050int
3051Channel::GetChannelOutputVolumeScaling(float& scaling) const
3052{
3053 scaling = _outputGain;
3054 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3055 VoEId(_instanceId,_channelId),
3056 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3057 return 0;
3058}
3059
niklase@google.com470e71d2011-07-07 08:21:25 +00003060int
3061Channel::RegisterExternalEncryption(Encryption& encryption)
3062{
3063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3064 "Channel::RegisterExternalEncryption()");
3065
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003066 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003067
3068 if (_encryptionPtr)
3069 {
3070 _engineStatisticsPtr->SetLastError(
3071 VE_INVALID_OPERATION, kTraceError,
3072 "RegisterExternalEncryption() encryption already enabled");
3073 return -1;
3074 }
3075
3076 _encryptionPtr = &encryption;
3077
3078 _decrypting = true;
3079 _encrypting = true;
3080
3081 return 0;
3082}
3083
3084int
3085Channel::DeRegisterExternalEncryption()
3086{
3087 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3088 "Channel::DeRegisterExternalEncryption()");
3089
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003090 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003091
3092 if (!_encryptionPtr)
3093 {
3094 _engineStatisticsPtr->SetLastError(
3095 VE_INVALID_OPERATION, kTraceWarning,
3096 "DeRegisterExternalEncryption() encryption already disabled");
3097 return 0;
3098 }
3099
3100 _decrypting = false;
3101 _encrypting = false;
3102
3103 _encryptionPtr = NULL;
3104
3105 return 0;
3106}
3107
3108int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003109 int lengthMs, int attenuationDb,
3110 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003111{
3112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3113 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3114 playDtmfEvent);
3115
3116 _playOutbandDtmfEvent = playDtmfEvent;
3117
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003118 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 attenuationDb) != 0)
3120 {
3121 _engineStatisticsPtr->SetLastError(
3122 VE_SEND_DTMF_FAILED,
3123 kTraceWarning,
3124 "SendTelephoneEventOutband() failed to send event");
3125 return -1;
3126 }
3127 return 0;
3128}
3129
3130int Channel::SendTelephoneEventInband(unsigned char eventCode,
3131 int lengthMs,
3132 int attenuationDb,
3133 bool playDtmfEvent)
3134{
3135 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3136 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3137 playDtmfEvent);
3138
3139 _playInbandDtmfEvent = playDtmfEvent;
3140 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3141
3142 return 0;
3143}
3144
3145int
3146Channel::SetDtmfPlayoutStatus(bool enable)
3147{
3148 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3149 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003150 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003151 {
3152 _engineStatisticsPtr->SetLastError(
3153 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3154 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3155 return -1;
3156 }
3157 return 0;
3158}
3159
3160bool
3161Channel::DtmfPlayoutStatus() const
3162{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003163 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003164}
3165
3166int
3167Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3168{
3169 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3170 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003171 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003172 {
3173 _engineStatisticsPtr->SetLastError(
3174 VE_INVALID_ARGUMENT, kTraceError,
3175 "SetSendTelephoneEventPayloadType() invalid type");
3176 return -1;
3177 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003178 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003179 codec.plfreq = 8000;
3180 codec.pltype = type;
3181 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003182 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003183 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003184 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3185 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3186 _engineStatisticsPtr->SetLastError(
3187 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3188 "SetSendTelephoneEventPayloadType() failed to register send"
3189 "payload type");
3190 return -1;
3191 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003192 }
3193 _sendTelephoneEventPayloadType = type;
3194 return 0;
3195}
3196
3197int
3198Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3199{
3200 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3201 "Channel::GetSendTelephoneEventPayloadType()");
3202 type = _sendTelephoneEventPayloadType;
3203 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3204 VoEId(_instanceId,_channelId),
3205 "GetSendTelephoneEventPayloadType() => type=%u", type);
3206 return 0;
3207}
3208
niklase@google.com470e71d2011-07-07 08:21:25 +00003209int
3210Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3211{
3212 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3213 "Channel::UpdateRxVadDetection()");
3214
3215 int vadDecision = 1;
3216
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003217 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003218
3219 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3220 {
3221 OnRxVadDetected(vadDecision);
3222 _oldVadDecision = vadDecision;
3223 }
3224
3225 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3226 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3227 vadDecision);
3228 return 0;
3229}
3230
3231int
3232Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3233{
3234 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3235 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003236 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003237
3238 if (_rxVadObserverPtr)
3239 {
3240 _engineStatisticsPtr->SetLastError(
3241 VE_INVALID_OPERATION, kTraceError,
3242 "RegisterRxVadObserver() observer already enabled");
3243 return -1;
3244 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003245 _rxVadObserverPtr = &observer;
3246 _RxVadDetection = true;
3247 return 0;
3248}
3249
3250int
3251Channel::DeRegisterRxVadObserver()
3252{
3253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3254 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003255 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003256
3257 if (!_rxVadObserverPtr)
3258 {
3259 _engineStatisticsPtr->SetLastError(
3260 VE_INVALID_OPERATION, kTraceWarning,
3261 "DeRegisterRxVadObserver() observer already disabled");
3262 return 0;
3263 }
3264 _rxVadObserverPtr = NULL;
3265 _RxVadDetection = false;
3266 return 0;
3267}
3268
3269int
3270Channel::VoiceActivityIndicator(int &activity)
3271{
3272 activity = _sendFrameType;
3273
3274 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3275 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3276 return 0;
3277}
3278
3279#ifdef WEBRTC_VOICE_ENGINE_AGC
3280
3281int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003282Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003283{
3284 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3285 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3286 (int)enable, (int)mode);
3287
3288 GainControl::Mode agcMode(GainControl::kFixedDigital);
3289 switch (mode)
3290 {
3291 case kAgcDefault:
3292 agcMode = GainControl::kAdaptiveDigital;
3293 break;
3294 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003295 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 break;
3297 case kAgcFixedDigital:
3298 agcMode = GainControl::kFixedDigital;
3299 break;
3300 case kAgcAdaptiveDigital:
3301 agcMode =GainControl::kAdaptiveDigital;
3302 break;
3303 default:
3304 _engineStatisticsPtr->SetLastError(
3305 VE_INVALID_ARGUMENT, kTraceError,
3306 "SetRxAgcStatus() invalid Agc mode");
3307 return -1;
3308 }
3309
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003310 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003311 {
3312 _engineStatisticsPtr->SetLastError(
3313 VE_APM_ERROR, kTraceError,
3314 "SetRxAgcStatus() failed to set Agc mode");
3315 return -1;
3316 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003317 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003318 {
3319 _engineStatisticsPtr->SetLastError(
3320 VE_APM_ERROR, kTraceError,
3321 "SetRxAgcStatus() failed to set Agc state");
3322 return -1;
3323 }
3324
3325 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003326 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3327
3328 return 0;
3329}
3330
3331int
3332Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3333{
3334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3335 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3336
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003337 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003338 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003339 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003340
3341 enabled = enable;
3342
3343 switch (agcMode)
3344 {
3345 case GainControl::kFixedDigital:
3346 mode = kAgcFixedDigital;
3347 break;
3348 case GainControl::kAdaptiveDigital:
3349 mode = kAgcAdaptiveDigital;
3350 break;
3351 default:
3352 _engineStatisticsPtr->SetLastError(
3353 VE_APM_ERROR, kTraceError,
3354 "GetRxAgcStatus() invalid Agc mode");
3355 return -1;
3356 }
3357
3358 return 0;
3359}
3360
3361int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003362Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003363{
3364 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3365 "Channel::SetRxAgcConfig()");
3366
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003367 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003368 config.targetLeveldBOv) != 0)
3369 {
3370 _engineStatisticsPtr->SetLastError(
3371 VE_APM_ERROR, kTraceError,
3372 "SetRxAgcConfig() failed to set target peak |level|"
3373 "(or envelope) of the Agc");
3374 return -1;
3375 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003376 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003377 config.digitalCompressionGaindB) != 0)
3378 {
3379 _engineStatisticsPtr->SetLastError(
3380 VE_APM_ERROR, kTraceError,
3381 "SetRxAgcConfig() failed to set the range in |gain| the"
3382 " digital compression stage may apply");
3383 return -1;
3384 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003385 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003386 config.limiterEnable) != 0)
3387 {
3388 _engineStatisticsPtr->SetLastError(
3389 VE_APM_ERROR, kTraceError,
3390 "SetRxAgcConfig() failed to set hard limiter to the signal");
3391 return -1;
3392 }
3393
3394 return 0;
3395}
3396
3397int
3398Channel::GetRxAgcConfig(AgcConfig& config)
3399{
3400 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3401 "Channel::GetRxAgcConfig(config=%?)");
3402
3403 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003404 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003405 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003406 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003407 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003408 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003409
3410 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3411 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3412 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3413 " limiterEnable=%d",
3414 config.targetLeveldBOv,
3415 config.digitalCompressionGaindB,
3416 config.limiterEnable);
3417
3418 return 0;
3419}
3420
3421#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3422
3423#ifdef WEBRTC_VOICE_ENGINE_NR
3424
3425int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003426Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003427{
3428 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3429 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3430 (int)enable, (int)mode);
3431
3432 NoiseSuppression::Level nsLevel(
3433 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3434 switch (mode)
3435 {
3436
3437 case kNsDefault:
3438 nsLevel = (NoiseSuppression::Level)
3439 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3440 break;
3441 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003442 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003443 break;
3444 case kNsConference:
3445 nsLevel = NoiseSuppression::kHigh;
3446 break;
3447 case kNsLowSuppression:
3448 nsLevel = NoiseSuppression::kLow;
3449 break;
3450 case kNsModerateSuppression:
3451 nsLevel = NoiseSuppression::kModerate;
3452 break;
3453 case kNsHighSuppression:
3454 nsLevel = NoiseSuppression::kHigh;
3455 break;
3456 case kNsVeryHighSuppression:
3457 nsLevel = NoiseSuppression::kVeryHigh;
3458 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003459 }
3460
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003461 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003462 != 0)
3463 {
3464 _engineStatisticsPtr->SetLastError(
3465 VE_APM_ERROR, kTraceError,
3466 "SetRxAgcStatus() failed to set Ns level");
3467 return -1;
3468 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003469 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003470 {
3471 _engineStatisticsPtr->SetLastError(
3472 VE_APM_ERROR, kTraceError,
3473 "SetRxAgcStatus() failed to set Agc state");
3474 return -1;
3475 }
3476
3477 _rxNsIsEnabled = enable;
3478 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3479
3480 return 0;
3481}
3482
3483int
3484Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3485{
3486 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3487 "Channel::GetRxNsStatus(enable=?, mode=?)");
3488
3489 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003490 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003491 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003492 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003493
3494 enabled = enable;
3495
3496 switch (ncLevel)
3497 {
3498 case NoiseSuppression::kLow:
3499 mode = kNsLowSuppression;
3500 break;
3501 case NoiseSuppression::kModerate:
3502 mode = kNsModerateSuppression;
3503 break;
3504 case NoiseSuppression::kHigh:
3505 mode = kNsHighSuppression;
3506 break;
3507 case NoiseSuppression::kVeryHigh:
3508 mode = kNsVeryHighSuppression;
3509 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003510 }
3511
3512 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3513 VoEId(_instanceId,_channelId),
3514 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3515 return 0;
3516}
3517
3518#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3519
3520int
3521Channel::RegisterRTPObserver(VoERTPObserver& observer)
3522{
3523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3524 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003525 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003526
3527 if (_rtpObserverPtr)
3528 {
3529 _engineStatisticsPtr->SetLastError(
3530 VE_INVALID_OPERATION, kTraceError,
3531 "RegisterRTPObserver() observer already enabled");
3532 return -1;
3533 }
3534
3535 _rtpObserverPtr = &observer;
3536 _rtpObserver = true;
3537
3538 return 0;
3539}
3540
3541int
3542Channel::DeRegisterRTPObserver()
3543{
3544 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3545 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003546 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003547
3548 if (!_rtpObserverPtr)
3549 {
3550 _engineStatisticsPtr->SetLastError(
3551 VE_INVALID_OPERATION, kTraceWarning,
3552 "DeRegisterRTPObserver() observer already disabled");
3553 return 0;
3554 }
3555
3556 _rtpObserver = false;
3557 _rtpObserverPtr = NULL;
3558
3559 return 0;
3560}
3561
3562int
3563Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3564{
3565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3566 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003567 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003568
3569 if (_rtcpObserverPtr)
3570 {
3571 _engineStatisticsPtr->SetLastError(
3572 VE_INVALID_OPERATION, kTraceError,
3573 "RegisterRTCPObserver() observer already enabled");
3574 return -1;
3575 }
3576
3577 _rtcpObserverPtr = &observer;
3578 _rtcpObserver = true;
3579
3580 return 0;
3581}
3582
3583int
3584Channel::DeRegisterRTCPObserver()
3585{
3586 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3587 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003588 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003589
3590 if (!_rtcpObserverPtr)
3591 {
3592 _engineStatisticsPtr->SetLastError(
3593 VE_INVALID_OPERATION, kTraceWarning,
3594 "DeRegisterRTCPObserver() observer already disabled");
3595 return 0;
3596 }
3597
3598 _rtcpObserver = false;
3599 _rtcpObserverPtr = NULL;
3600
3601 return 0;
3602}
3603
3604int
3605Channel::SetLocalSSRC(unsigned int ssrc)
3606{
3607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3608 "Channel::SetLocalSSRC()");
3609 if (_sending)
3610 {
3611 _engineStatisticsPtr->SetLastError(
3612 VE_ALREADY_SENDING, kTraceError,
3613 "SetLocalSSRC() already sending");
3614 return -1;
3615 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003616 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003617 {
3618 _engineStatisticsPtr->SetLastError(
3619 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3620 "SetLocalSSRC() failed to set SSRC");
3621 return -1;
3622 }
3623 return 0;
3624}
3625
3626int
3627Channel::GetLocalSSRC(unsigned int& ssrc)
3628{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003629 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003630 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3631 VoEId(_instanceId,_channelId),
3632 "GetLocalSSRC() => ssrc=%lu", ssrc);
3633 return 0;
3634}
3635
3636int
3637Channel::GetRemoteSSRC(unsigned int& ssrc)
3638{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003639 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003640 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3641 VoEId(_instanceId,_channelId),
3642 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3643 return 0;
3644}
3645
3646int
3647Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3648{
3649 if (arrCSRC == NULL)
3650 {
3651 _engineStatisticsPtr->SetLastError(
3652 VE_INVALID_ARGUMENT, kTraceError,
3653 "GetRemoteCSRCs() invalid array argument");
3654 return -1;
3655 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003656 uint32_t arrOfCSRC[kRtpCsrcSize];
3657 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003658 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003659 if (CSRCs > 0)
3660 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003661 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003662 for (int i = 0; i < (int) CSRCs; i++)
3663 {
3664 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3665 VoEId(_instanceId, _channelId),
3666 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3667 }
3668 } else
3669 {
3670 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3671 VoEId(_instanceId, _channelId),
3672 "GetRemoteCSRCs() => list is empty!");
3673 }
3674 return CSRCs;
3675}
3676
3677int
3678Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3679{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003680 if (rtp_audioproc_.get() == NULL) {
3681 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3682 _channelId)));
3683 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003684
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003685 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3686 AudioProcessing::kNoError) {
3687 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3688 "Failed to enable AudioProcessing::level_estimator()");
3689 return -1;
3690 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003691
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003692 _includeAudioLevelIndication = enable;
3693 if (enable) {
3694 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3695 ID);
3696 } else {
3697 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3698 }
3699 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003700}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003701
niklase@google.com470e71d2011-07-07 08:21:25 +00003702int
3703Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3704{
3705 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3706 VoEId(_instanceId,_channelId),
3707 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3708 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003709 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003710}
3711
3712int
3713Channel::SetRTCPStatus(bool enable)
3714{
3715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3716 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003717 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003718 kRtcpCompound : kRtcpOff) != 0)
3719 {
3720 _engineStatisticsPtr->SetLastError(
3721 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3722 "SetRTCPStatus() failed to set RTCP status");
3723 return -1;
3724 }
3725 return 0;
3726}
3727
3728int
3729Channel::GetRTCPStatus(bool& enabled)
3730{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003731 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003732 enabled = (method != kRtcpOff);
3733 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3734 VoEId(_instanceId,_channelId),
3735 "GetRTCPStatus() => enabled=%d", enabled);
3736 return 0;
3737}
3738
3739int
3740Channel::SetRTCP_CNAME(const char cName[256])
3741{
3742 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3743 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003744 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 {
3746 _engineStatisticsPtr->SetLastError(
3747 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3748 "SetRTCP_CNAME() failed to set RTCP CNAME");
3749 return -1;
3750 }
3751 return 0;
3752}
3753
3754int
3755Channel::GetRTCP_CNAME(char cName[256])
3756{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003757 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003758 {
3759 _engineStatisticsPtr->SetLastError(
3760 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3761 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3762 return -1;
3763 }
3764 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3765 VoEId(_instanceId, _channelId),
3766 "GetRTCP_CNAME() => cName=%s", cName);
3767 return 0;
3768}
3769
3770int
3771Channel::GetRemoteRTCP_CNAME(char cName[256])
3772{
3773 if (cName == NULL)
3774 {
3775 _engineStatisticsPtr->SetLastError(
3776 VE_INVALID_ARGUMENT, kTraceError,
3777 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3778 return -1;
3779 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003780 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003781 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003782 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003783 {
3784 _engineStatisticsPtr->SetLastError(
3785 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3786 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3787 return -1;
3788 }
3789 strcpy(cName, cname);
3790 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3791 VoEId(_instanceId, _channelId),
3792 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3793 return 0;
3794}
3795
3796int
3797Channel::GetRemoteRTCPData(
3798 unsigned int& NTPHigh,
3799 unsigned int& NTPLow,
3800 unsigned int& timestamp,
3801 unsigned int& playoutTimestamp,
3802 unsigned int* jitter,
3803 unsigned short* fractionLost)
3804{
3805 // --- Information from sender info in received Sender Reports
3806
3807 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003808 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003809 {
3810 _engineStatisticsPtr->SetLastError(
3811 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003812 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003813 "side");
3814 return -1;
3815 }
3816
3817 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3818 // and octet count)
3819 NTPHigh = senderInfo.NTPseconds;
3820 NTPLow = senderInfo.NTPfraction;
3821 timestamp = senderInfo.RTPtimeStamp;
3822
3823 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3824 VoEId(_instanceId, _channelId),
3825 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3826 "timestamp=%lu",
3827 NTPHigh, NTPLow, timestamp);
3828
3829 // --- Locally derived information
3830
3831 // This value is updated on each incoming RTCP packet (0 when no packet
3832 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003833 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003834
3835 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3836 VoEId(_instanceId, _channelId),
3837 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003838 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003839
3840 if (NULL != jitter || NULL != fractionLost)
3841 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003842 // Get all RTCP receiver report blocks that have been received on this
3843 // channel. If we receive RTP packets from a remote source we know the
3844 // remote SSRC and use the report block from him.
3845 // Otherwise use the first report block.
3846 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003847 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003848 remote_stats.empty()) {
3849 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3850 VoEId(_instanceId, _channelId),
3851 "GetRemoteRTCPData() failed to measure statistics due"
3852 " to lack of received RTP and/or RTCP packets");
3853 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003854 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003855
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003856 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003857 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3858 for (; it != remote_stats.end(); ++it) {
3859 if (it->remoteSSRC == remoteSSRC)
3860 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003861 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003862
3863 if (it == remote_stats.end()) {
3864 // If we have not received any RTCP packets from this SSRC it probably
3865 // means that we have not received any RTP packets.
3866 // Use the first received report block instead.
3867 it = remote_stats.begin();
3868 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003869 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003870
xians@webrtc.org79af7342012-01-31 12:22:14 +00003871 if (jitter) {
3872 *jitter = it->jitter;
3873 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3874 VoEId(_instanceId, _channelId),
3875 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3876 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003877
xians@webrtc.org79af7342012-01-31 12:22:14 +00003878 if (fractionLost) {
3879 *fractionLost = it->fractionLost;
3880 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3881 VoEId(_instanceId, _channelId),
3882 "GetRemoteRTCPData() => fractionLost = %lu",
3883 *fractionLost);
3884 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003885 }
3886 return 0;
3887}
3888
3889int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003890Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003891 unsigned int name,
3892 const char* data,
3893 unsigned short dataLengthInBytes)
3894{
3895 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3896 "Channel::SendApplicationDefinedRTCPPacket()");
3897 if (!_sending)
3898 {
3899 _engineStatisticsPtr->SetLastError(
3900 VE_NOT_SENDING, kTraceError,
3901 "SendApplicationDefinedRTCPPacket() not sending");
3902 return -1;
3903 }
3904 if (NULL == data)
3905 {
3906 _engineStatisticsPtr->SetLastError(
3907 VE_INVALID_ARGUMENT, kTraceError,
3908 "SendApplicationDefinedRTCPPacket() invalid data value");
3909 return -1;
3910 }
3911 if (dataLengthInBytes % 4 != 0)
3912 {
3913 _engineStatisticsPtr->SetLastError(
3914 VE_INVALID_ARGUMENT, kTraceError,
3915 "SendApplicationDefinedRTCPPacket() invalid length value");
3916 return -1;
3917 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003918 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003919 if (status == kRtcpOff)
3920 {
3921 _engineStatisticsPtr->SetLastError(
3922 VE_RTCP_ERROR, kTraceError,
3923 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3924 return -1;
3925 }
3926
3927 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003928 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003929 subType,
3930 name,
3931 (const unsigned char*) data,
3932 dataLengthInBytes) != 0)
3933 {
3934 _engineStatisticsPtr->SetLastError(
3935 VE_SEND_ERROR, kTraceError,
3936 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3937 return -1;
3938 }
3939 return 0;
3940}
3941
3942int
3943Channel::GetRTPStatistics(
3944 unsigned int& averageJitterMs,
3945 unsigned int& maxJitterMs,
3946 unsigned int& discardedPackets)
3947{
niklase@google.com470e71d2011-07-07 08:21:25 +00003948 // The jitter statistics is updated for each received RTP packet and is
3949 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003950 StreamStatistician::Statistics statistics;
3951 StreamStatistician* statistician =
3952 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3953 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003954 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3955 _engineStatisticsPtr->SetLastError(
3956 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3957 "GetRTPStatistics() failed to read RTP statistics from the "
3958 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003959 }
3960
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003961 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003962 if (playoutFrequency > 0)
3963 {
3964 // Scale RTP statistics given the current playout frequency
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003965 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3966 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003967 }
3968
3969 discardedPackets = _numberOfDiscardedPackets;
3970
3971 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3972 VoEId(_instanceId, _channelId),
3973 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003974 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003975 averageJitterMs, maxJitterMs, discardedPackets);
3976 return 0;
3977}
3978
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003979int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3980 if (sender_info == NULL) {
3981 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3982 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3983 return -1;
3984 }
3985
3986 // Get the sender info from the latest received RTCP Sender Report.
3987 RTCPSenderInfo rtcp_sender_info;
3988 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3989 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3990 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3991 return -1;
3992 }
3993
3994 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3995 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3996 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3997 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3998 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3999 return 0;
4000}
4001
4002int Channel::GetRemoteRTCPReportBlocks(
4003 std::vector<ReportBlock>* report_blocks) {
4004 if (report_blocks == NULL) {
4005 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4006 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4007 return -1;
4008 }
4009
4010 // Get the report blocks from the latest received RTCP Sender or Receiver
4011 // Report. Each element in the vector contains the sender's SSRC and a
4012 // report block according to RFC 3550.
4013 std::vector<RTCPReportBlock> rtcp_report_blocks;
4014 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4015 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4016 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4017 return -1;
4018 }
4019
4020 if (rtcp_report_blocks.empty())
4021 return 0;
4022
4023 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4024 for (; it != rtcp_report_blocks.end(); ++it) {
4025 ReportBlock report_block;
4026 report_block.sender_SSRC = it->remoteSSRC;
4027 report_block.source_SSRC = it->sourceSSRC;
4028 report_block.fraction_lost = it->fractionLost;
4029 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4030 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4031 report_block.interarrival_jitter = it->jitter;
4032 report_block.last_SR_timestamp = it->lastSR;
4033 report_block.delay_since_last_SR = it->delaySinceLastSR;
4034 report_blocks->push_back(report_block);
4035 }
4036 return 0;
4037}
4038
niklase@google.com470e71d2011-07-07 08:21:25 +00004039int
4040Channel::GetRTPStatistics(CallStatistics& stats)
4041{
niklase@google.com470e71d2011-07-07 08:21:25 +00004042 // --- Part one of the final structure (four values)
4043
4044 // The jitter statistics is updated for each received RTP packet and is
4045 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004046 StreamStatistician::Statistics statistics;
4047 StreamStatistician* statistician =
4048 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
4049 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004050 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4051 _engineStatisticsPtr->SetLastError(
4052 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4053 "GetRTPStatistics() failed to read RTP statistics from the "
4054 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004055 }
4056
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004057 stats.fractionLost = statistics.fraction_lost;
4058 stats.cumulativeLost = statistics.cumulative_lost;
4059 stats.extendedMax = statistics.extended_max_sequence_number;
4060 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004061
4062 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4063 VoEId(_instanceId, _channelId),
4064 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004065 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004066 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4067 stats.jitterSamples);
4068
4069 // --- Part two of the final structure (one value)
4070
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004071 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004072 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004073 if (method == kRtcpOff)
4074 {
4075 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4076 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004077 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004078 "measurements cannot be retrieved");
4079 } else
4080 {
4081 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004082 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004083 if (remoteSSRC > 0)
4084 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004085 uint16_t avgRTT(0);
4086 uint16_t maxRTT(0);
4087 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004088
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004089 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004090 != 0)
4091 {
4092 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4093 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004094 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004095 "the RTP/RTCP module");
4096 }
4097 } else
4098 {
4099 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4100 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004101 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004102 "RTP packets have been received yet");
4103 }
4104 }
4105
4106 stats.rttMs = static_cast<int> (RTT);
4107
4108 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4109 VoEId(_instanceId, _channelId),
4110 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4111
4112 // --- Part three of the final structure (four values)
4113
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004114 uint32_t bytesSent(0);
4115 uint32_t packetsSent(0);
4116 uint32_t bytesReceived(0);
4117 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004118
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004119 if (statistician) {
4120 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4121 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004122
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004123 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004124 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004125 {
4126 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4127 VoEId(_instanceId, _channelId),
4128 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004129 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004130 }
4131
4132 stats.bytesSent = bytesSent;
4133 stats.packetsSent = packetsSent;
4134 stats.bytesReceived = bytesReceived;
4135 stats.packetsReceived = packetsReceived;
4136
4137 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4138 VoEId(_instanceId, _channelId),
4139 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004140 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004141 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4142 stats.packetsReceived);
4143
4144 return 0;
4145}
4146
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004147int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4148 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4149 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004150
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004151 if (enable) {
4152 if (redPayloadtype < 0 || redPayloadtype > 127) {
4153 _engineStatisticsPtr->SetLastError(
4154 VE_PLTYPE_ERROR, kTraceError,
4155 "SetFECStatus() invalid RED payload type");
4156 return -1;
4157 }
4158
4159 if (SetRedPayloadType(redPayloadtype) < 0) {
4160 _engineStatisticsPtr->SetLastError(
4161 VE_CODEC_ERROR, kTraceError,
4162 "SetSecondarySendCodec() Failed to register RED ACM");
4163 return -1;
4164 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004165 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004166
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004167 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004168 _engineStatisticsPtr->SetLastError(
4169 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4170 "SetFECStatus() failed to set FEC state in the ACM");
4171 return -1;
4172 }
4173 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004174}
4175
4176int
4177Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4178{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004179 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004180 if (enabled)
4181 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004182 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004183 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004184 {
4185 _engineStatisticsPtr->SetLastError(
4186 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4187 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4188 "module");
4189 return -1;
4190 }
4191 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4192 VoEId(_instanceId, _channelId),
4193 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4194 enabled, redPayloadtype);
4195 return 0;
4196 }
4197 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4198 VoEId(_instanceId, _channelId),
4199 "GetFECStatus() => enabled=%d", enabled);
4200 return 0;
4201}
4202
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004203void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4204 // None of these functions can fail.
4205 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004206 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4207 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004208 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004209 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004210 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004211 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004212}
4213
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004214// Called when we are missing one or more packets.
4215int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004216 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4217}
4218
niklase@google.com470e71d2011-07-07 08:21:25 +00004219int
niklase@google.com470e71d2011-07-07 08:21:25 +00004220Channel::StartRTPDump(const char fileNameUTF8[1024],
4221 RTPDirections direction)
4222{
4223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4224 "Channel::StartRTPDump()");
4225 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4226 {
4227 _engineStatisticsPtr->SetLastError(
4228 VE_INVALID_ARGUMENT, kTraceError,
4229 "StartRTPDump() invalid RTP direction");
4230 return -1;
4231 }
4232 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4233 &_rtpDumpIn : &_rtpDumpOut;
4234 if (rtpDumpPtr == NULL)
4235 {
4236 assert(false);
4237 return -1;
4238 }
4239 if (rtpDumpPtr->IsActive())
4240 {
4241 rtpDumpPtr->Stop();
4242 }
4243 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4244 {
4245 _engineStatisticsPtr->SetLastError(
4246 VE_BAD_FILE, kTraceError,
4247 "StartRTPDump() failed to create file");
4248 return -1;
4249 }
4250 return 0;
4251}
4252
4253int
4254Channel::StopRTPDump(RTPDirections direction)
4255{
4256 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4257 "Channel::StopRTPDump()");
4258 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4259 {
4260 _engineStatisticsPtr->SetLastError(
4261 VE_INVALID_ARGUMENT, kTraceError,
4262 "StopRTPDump() invalid RTP direction");
4263 return -1;
4264 }
4265 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4266 &_rtpDumpIn : &_rtpDumpOut;
4267 if (rtpDumpPtr == NULL)
4268 {
4269 assert(false);
4270 return -1;
4271 }
4272 if (!rtpDumpPtr->IsActive())
4273 {
4274 return 0;
4275 }
4276 return rtpDumpPtr->Stop();
4277}
4278
4279bool
4280Channel::RTPDumpIsActive(RTPDirections direction)
4281{
4282 if ((direction != kRtpIncoming) &&
4283 (direction != kRtpOutgoing))
4284 {
4285 _engineStatisticsPtr->SetLastError(
4286 VE_INVALID_ARGUMENT, kTraceError,
4287 "RTPDumpIsActive() invalid RTP direction");
4288 return false;
4289 }
4290 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4291 &_rtpDumpIn : &_rtpDumpOut;
4292 return rtpDumpPtr->IsActive();
4293}
4294
4295int
4296Channel::InsertExtraRTPPacket(unsigned char payloadType,
4297 bool markerBit,
4298 const char* payloadData,
4299 unsigned short payloadSize)
4300{
4301 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4302 "Channel::InsertExtraRTPPacket()");
4303 if (payloadType > 127)
4304 {
4305 _engineStatisticsPtr->SetLastError(
4306 VE_INVALID_PLTYPE, kTraceError,
4307 "InsertExtraRTPPacket() invalid payload type");
4308 return -1;
4309 }
4310 if (payloadData == NULL)
4311 {
4312 _engineStatisticsPtr->SetLastError(
4313 VE_INVALID_ARGUMENT, kTraceError,
4314 "InsertExtraRTPPacket() invalid payload data");
4315 return -1;
4316 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004317 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004318 {
4319 _engineStatisticsPtr->SetLastError(
4320 VE_INVALID_ARGUMENT, kTraceError,
4321 "InsertExtraRTPPacket() invalid payload size");
4322 return -1;
4323 }
4324 if (!_sending)
4325 {
4326 _engineStatisticsPtr->SetLastError(
4327 VE_NOT_SENDING, kTraceError,
4328 "InsertExtraRTPPacket() not sending");
4329 return -1;
4330 }
4331
4332 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4333 // Transport::SendPacket() will be called by the module when the RTP packet
4334 // is created.
4335 // The call to SendOutgoingData() does *not* modify the timestamp and
4336 // payloadtype to ensure that the RTP module generates a valid RTP packet
4337 // (user might utilize a non-registered payload type).
4338 // The marker bit and payload type will be replaced just before the actual
4339 // transmission, i.e., the actual modification is done *after* the RTP
4340 // module has delivered its RTP packet back to the VoE.
4341 // We will use the stored values above when the packet is modified
4342 // (see Channel::SendPacket()).
4343
4344 _extraPayloadType = payloadType;
4345 _extraMarkerBit = markerBit;
4346 _insertExtraRTPPacket = true;
4347
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004348 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004349 _lastPayloadType,
4350 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004351 // Leaving the time when this frame was
4352 // received from the capture device as
4353 // undefined for voice for now.
4354 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004355 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004356 payloadSize) != 0)
4357 {
4358 _engineStatisticsPtr->SetLastError(
4359 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4360 "InsertExtraRTPPacket() failed to send extra RTP packet");
4361 return -1;
4362 }
4363
4364 return 0;
4365}
4366
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004367uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004368Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004369{
4370 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004371 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004372 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004373 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004374 return 0;
4375}
4376
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004377// TODO(xians): This method borrows quite some code from
4378// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4379// code duplication.
4380void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004381 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004382 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004383 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004384 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4385 static const int kMaxNumberOfFrames = 960;
4386 assert(number_of_frames <= kMaxNumberOfFrames);
4387
4388 // Get the send codec information for doing resampling or downmixing later on.
4389 CodecInst codec;
4390 GetSendCodec(codec);
4391 assert(codec.channels == 1 || codec.channels == 2);
4392 int support_sample_rate = std::min(32000,
4393 std::min(sample_rate, codec.plfreq));
4394
4395 // Downmix the data to mono if needed.
4396 const int16_t* audio_ptr = audio_data;
4397 if (number_of_channels == 2 && codec.channels == 1) {
4398 if (!mono_recording_audio_.get())
4399 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4400
4401 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4402 mono_recording_audio_.get());
4403 audio_ptr = mono_recording_audio_.get();
4404 }
4405
4406 // Resample the data to the sample rate that the codec is using.
4407 if (input_resampler_.InitializeIfNeeded(sample_rate,
4408 support_sample_rate,
4409 codec.channels)) {
4410 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4411 "Channel::Demultiplex() unable to resample");
4412 return;
4413 }
4414
4415 int out_length = input_resampler_.Resample(audio_ptr,
4416 number_of_frames * codec.channels,
4417 _audioFrame.data_,
4418 AudioFrame::kMaxDataSizeSamples);
4419 if (out_length == -1) {
4420 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4421 "Channel::Demultiplex() resampling failed");
4422 return;
4423 }
4424
4425 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4426 _audioFrame.timestamp_ = -1;
4427 _audioFrame.sample_rate_hz_ = support_sample_rate;
4428 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4429 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4430 _audioFrame.num_channels_ = codec.channels;
4431 _audioFrame.id_ = _channelId;
4432}
4433
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004434uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004435Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004436{
4437 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4438 "Channel::PrepareEncodeAndSend()");
4439
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004440 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004441 {
4442 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4443 "Channel::PrepareEncodeAndSend() invalid audio frame");
4444 return -1;
4445 }
4446
4447 if (_inputFilePlaying)
4448 {
4449 MixOrReplaceAudioWithFile(mixingFrequency);
4450 }
4451
4452 if (_mute)
4453 {
4454 AudioFrameOperations::Mute(_audioFrame);
4455 }
4456
4457 if (_inputExternalMedia)
4458 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004459 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004460 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004461 if (_inputExternalMediaCallbackPtr)
4462 {
4463 _inputExternalMediaCallbackPtr->Process(
4464 _channelId,
4465 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004466 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004467 _audioFrame.samples_per_channel_,
4468 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004469 isStereo);
4470 }
4471 }
4472
4473 InsertInbandDtmfTone();
4474
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004475 if (_includeAudioLevelIndication)
4476 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004477 if (rtp_audioproc_->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4478 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004479 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004480 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4481 VoEId(_instanceId, _channelId),
4482 "Error setting AudioProcessing sample rate");
4483 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004484 }
4485
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004486 if (rtp_audioproc_->set_num_channels(_audioFrame.num_channels_,
4487 _audioFrame.num_channels_) !=
4488 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004489 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004490 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4491 VoEId(_instanceId, _channelId),
4492 "Error setting AudioProcessing channels");
4493 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004494 }
4495
4496 // Performs level analysis only; does not affect the signal.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004497 rtp_audioproc_->ProcessStream(&_audioFrame);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004498 }
4499
niklase@google.com470e71d2011-07-07 08:21:25 +00004500 return 0;
4501}
4502
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004503uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004504Channel::EncodeAndSend()
4505{
4506 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4507 "Channel::EncodeAndSend()");
4508
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004509 assert(_audioFrame.num_channels_ <= 2);
4510 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004511 {
4512 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4513 "Channel::EncodeAndSend() invalid audio frame");
4514 return -1;
4515 }
4516
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004517 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004518
4519 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4520
4521 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004522 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004523 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004524 {
4525 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4526 "Channel::EncodeAndSend() ACM encoding failed");
4527 return -1;
4528 }
4529
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004530 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004531
4532 // --- Encode if complete frame is ready
4533
4534 // This call will trigger AudioPacketizationCallback::SendData if encoding
4535 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004536 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004537}
4538
4539int Channel::RegisterExternalMediaProcessing(
4540 ProcessingTypes type,
4541 VoEMediaProcess& processObject)
4542{
4543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4544 "Channel::RegisterExternalMediaProcessing()");
4545
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004546 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004547
4548 if (kPlaybackPerChannel == type)
4549 {
4550 if (_outputExternalMediaCallbackPtr)
4551 {
4552 _engineStatisticsPtr->SetLastError(
4553 VE_INVALID_OPERATION, kTraceError,
4554 "Channel::RegisterExternalMediaProcessing() "
4555 "output external media already enabled");
4556 return -1;
4557 }
4558 _outputExternalMediaCallbackPtr = &processObject;
4559 _outputExternalMedia = true;
4560 }
4561 else if (kRecordingPerChannel == type)
4562 {
4563 if (_inputExternalMediaCallbackPtr)
4564 {
4565 _engineStatisticsPtr->SetLastError(
4566 VE_INVALID_OPERATION, kTraceError,
4567 "Channel::RegisterExternalMediaProcessing() "
4568 "output external media already enabled");
4569 return -1;
4570 }
4571 _inputExternalMediaCallbackPtr = &processObject;
4572 _inputExternalMedia = true;
4573 }
4574 return 0;
4575}
4576
4577int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4578{
4579 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4580 "Channel::DeRegisterExternalMediaProcessing()");
4581
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004582 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004583
4584 if (kPlaybackPerChannel == type)
4585 {
4586 if (!_outputExternalMediaCallbackPtr)
4587 {
4588 _engineStatisticsPtr->SetLastError(
4589 VE_INVALID_OPERATION, kTraceWarning,
4590 "Channel::DeRegisterExternalMediaProcessing() "
4591 "output external media already disabled");
4592 return 0;
4593 }
4594 _outputExternalMedia = false;
4595 _outputExternalMediaCallbackPtr = NULL;
4596 }
4597 else if (kRecordingPerChannel == type)
4598 {
4599 if (!_inputExternalMediaCallbackPtr)
4600 {
4601 _engineStatisticsPtr->SetLastError(
4602 VE_INVALID_OPERATION, kTraceWarning,
4603 "Channel::DeRegisterExternalMediaProcessing() "
4604 "input external media already disabled");
4605 return 0;
4606 }
4607 _inputExternalMedia = false;
4608 _inputExternalMediaCallbackPtr = NULL;
4609 }
4610
4611 return 0;
4612}
4613
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004614int Channel::SetExternalMixing(bool enabled) {
4615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4616 "Channel::SetExternalMixing(enabled=%d)", enabled);
4617
4618 if (_playing)
4619 {
4620 _engineStatisticsPtr->SetLastError(
4621 VE_INVALID_OPERATION, kTraceError,
4622 "Channel::SetExternalMixing() "
4623 "external mixing cannot be changed while playing.");
4624 return -1;
4625 }
4626
4627 _externalMixing = enabled;
4628
4629 return 0;
4630}
4631
niklase@google.com470e71d2011-07-07 08:21:25 +00004632int
4633Channel::ResetRTCPStatistics()
4634{
4635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4636 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004637 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004638 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004639 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004640}
4641
4642int
4643Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4644{
4645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4646 "Channel::GetRoundTripTimeSummary()");
4647 // Override default module outputs for the case when RTCP is disabled.
4648 // This is done to ensure that we are backward compatible with the
4649 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004650 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004651 {
4652 delaysMs.min = -1;
4653 delaysMs.max = -1;
4654 delaysMs.average = -1;
4655 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4656 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4657 " valid RTT measurements cannot be retrieved");
4658 return 0;
4659 }
4660
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004661 uint32_t remoteSSRC;
4662 uint16_t RTT;
4663 uint16_t avgRTT;
4664 uint16_t maxRTT;
4665 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004666 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004667 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004668 if (remoteSSRC == 0)
4669 {
4670 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4671 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4672 " since no RTP packet has been received yet");
4673 }
4674
4675 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4676 // channel and SSRC. The SSRC is required to parse out the correct source
4677 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004678 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004679 {
4680 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4681 "GetRoundTripTimeSummary unable to retrieve RTT values"
4682 " from the RTCP layer");
4683 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4684 }
4685 else
4686 {
4687 delaysMs.min = minRTT;
4688 delaysMs.max = maxRTT;
4689 delaysMs.average = avgRTT;
4690 }
4691 return 0;
4692}
4693
4694int
4695Channel::GetNetworkStatistics(NetworkStatistics& stats)
4696{
4697 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4698 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004699 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004700 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004701 if (return_value >= 0) {
4702 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4703 }
4704 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004705}
4706
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004707bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4708 int* playout_buffer_delay_ms) const {
4709 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004710 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004711 "Channel::GetDelayEstimate() no valid estimate.");
4712 return false;
4713 }
4714 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4715 _recPacketDelayMs;
4716 *playout_buffer_delay_ms = playout_delay_ms_;
4717 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4718 "Channel::GetDelayEstimate()");
4719 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004720}
4721
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004722int Channel::SetInitialPlayoutDelay(int delay_ms)
4723{
4724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4725 "Channel::SetInitialPlayoutDelay()");
4726 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4727 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4728 {
4729 _engineStatisticsPtr->SetLastError(
4730 VE_INVALID_ARGUMENT, kTraceError,
4731 "SetInitialPlayoutDelay() invalid min delay");
4732 return -1;
4733 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004734 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004735 {
4736 _engineStatisticsPtr->SetLastError(
4737 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4738 "SetInitialPlayoutDelay() failed to set min playout delay");
4739 return -1;
4740 }
4741 return 0;
4742}
4743
4744
niklase@google.com470e71d2011-07-07 08:21:25 +00004745int
4746Channel::SetMinimumPlayoutDelay(int delayMs)
4747{
4748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4749 "Channel::SetMinimumPlayoutDelay()");
4750 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4751 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4752 {
4753 _engineStatisticsPtr->SetLastError(
4754 VE_INVALID_ARGUMENT, kTraceError,
4755 "SetMinimumPlayoutDelay() invalid min delay");
4756 return -1;
4757 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004758 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004759 {
4760 _engineStatisticsPtr->SetLastError(
4761 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4762 "SetMinimumPlayoutDelay() failed to set min playout delay");
4763 return -1;
4764 }
4765 return 0;
4766}
4767
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004768void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4769 uint32_t playout_timestamp = 0;
4770
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004771 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004772 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4773 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4774 " timestamp from the ACM");
4775 _engineStatisticsPtr->SetLastError(
4776 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4777 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4778 return;
4779 }
4780
4781 uint16_t delay_ms = 0;
4782 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4783 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4784 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4785 " delay from the ADM");
4786 _engineStatisticsPtr->SetLastError(
4787 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4788 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4789 return;
4790 }
4791
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004792 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004793 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004794 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004795 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4796 playout_frequency = 8000;
4797 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4798 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004799 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004800 }
4801
4802 // Remove the playout delay.
4803 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4804
4805 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4806 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4807 playout_timestamp);
4808
4809 if (rtcp) {
4810 playout_timestamp_rtcp_ = playout_timestamp;
4811 } else {
4812 playout_timestamp_rtp_ = playout_timestamp;
4813 }
4814 playout_delay_ms_ = delay_ms;
4815}
4816
4817int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4818 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4819 "Channel::GetPlayoutTimestamp()");
4820 if (playout_timestamp_rtp_ == 0) {
4821 _engineStatisticsPtr->SetLastError(
4822 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4823 "GetPlayoutTimestamp() failed to retrieve timestamp");
4824 return -1;
4825 }
4826 timestamp = playout_timestamp_rtp_;
4827 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4828 VoEId(_instanceId,_channelId),
4829 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4830 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004831}
4832
4833int
4834Channel::SetInitTimestamp(unsigned int timestamp)
4835{
4836 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4837 "Channel::SetInitTimestamp()");
4838 if (_sending)
4839 {
4840 _engineStatisticsPtr->SetLastError(
4841 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4842 return -1;
4843 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004844 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004845 {
4846 _engineStatisticsPtr->SetLastError(
4847 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4848 "SetInitTimestamp() failed to set timestamp");
4849 return -1;
4850 }
4851 return 0;
4852}
4853
4854int
4855Channel::SetInitSequenceNumber(short sequenceNumber)
4856{
4857 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4858 "Channel::SetInitSequenceNumber()");
4859 if (_sending)
4860 {
4861 _engineStatisticsPtr->SetLastError(
4862 VE_SENDING, kTraceError,
4863 "SetInitSequenceNumber() already sending");
4864 return -1;
4865 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004866 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004867 {
4868 _engineStatisticsPtr->SetLastError(
4869 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4870 "SetInitSequenceNumber() failed to set sequence number");
4871 return -1;
4872 }
4873 return 0;
4874}
4875
4876int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004877Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004878{
4879 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4880 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004881 *rtpRtcpModule = _rtpRtcpModule.get();
4882 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004883 return 0;
4884}
4885
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004886// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4887// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004888int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004889Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004890{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004891 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004892 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004893
4894 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004895 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004896
4897 if (_inputFilePlayerPtr == NULL)
4898 {
4899 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4900 VoEId(_instanceId, _channelId),
4901 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4902 " doesnt exist");
4903 return -1;
4904 }
4905
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004906 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004907 fileSamples,
4908 mixingFrequency) == -1)
4909 {
4910 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4911 VoEId(_instanceId, _channelId),
4912 "Channel::MixOrReplaceAudioWithFile() file mixing "
4913 "failed");
4914 return -1;
4915 }
4916 if (fileSamples == 0)
4917 {
4918 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4919 VoEId(_instanceId, _channelId),
4920 "Channel::MixOrReplaceAudioWithFile() file is ended");
4921 return 0;
4922 }
4923 }
4924
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004925 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004926
4927 if (_mixFileWithMicrophone)
4928 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004929 // Currently file stream is always mono.
4930 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004931 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004932 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004933 fileBuffer.get(),
4934 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004935 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004936 }
4937 else
4938 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004939 // Replace ACM audio with file.
4940 // Currently file stream is always mono.
4941 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004942 _audioFrame.UpdateFrame(_channelId,
4943 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004944 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004945 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004946 mixingFrequency,
4947 AudioFrame::kNormalSpeech,
4948 AudioFrame::kVadUnknown,
4949 1);
4950
4951 }
4952 return 0;
4953}
4954
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004955int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004956Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004957 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004958{
4959 assert(mixingFrequency <= 32000);
4960
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004961 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004962 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004963
4964 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004965 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004966
4967 if (_outputFilePlayerPtr == NULL)
4968 {
4969 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4970 VoEId(_instanceId, _channelId),
4971 "Channel::MixAudioWithFile() file mixing failed");
4972 return -1;
4973 }
4974
4975 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004976 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004977 fileSamples,
4978 mixingFrequency) == -1)
4979 {
4980 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4981 VoEId(_instanceId, _channelId),
4982 "Channel::MixAudioWithFile() file mixing failed");
4983 return -1;
4984 }
4985 }
4986
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004987 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004988 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004989 // Currently file stream is always mono.
4990 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004991 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004992 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004993 fileBuffer.get(),
4994 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004995 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004996 }
4997 else
4998 {
4999 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005000 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00005001 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005002 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005003 return -1;
5004 }
5005
5006 return 0;
5007}
5008
5009int
5010Channel::InsertInbandDtmfTone()
5011{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005012 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00005013 if (_inbandDtmfQueue.PendingDtmf() &&
5014 !_inbandDtmfGenerator.IsAddingTone() &&
5015 _inbandDtmfGenerator.DelaySinceLastTone() >
5016 kMinTelephoneEventSeparationMs)
5017 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005018 int8_t eventCode(0);
5019 uint16_t lengthMs(0);
5020 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005021
5022 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
5023 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
5024 if (_playInbandDtmfEvent)
5025 {
5026 // Add tone to output mixer using a reduced length to minimize
5027 // risk of echo.
5028 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
5029 attenuationDb);
5030 }
5031 }
5032
5033 if (_inbandDtmfGenerator.IsAddingTone())
5034 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005035 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005036 _inbandDtmfGenerator.GetSampleRate(frequency);
5037
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005038 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005039 {
5040 // Update sample rate of Dtmf tone since the mixing frequency
5041 // has changed.
5042 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005043 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005044 // Reset the tone to be added taking the new sample rate into
5045 // account.
5046 _inbandDtmfGenerator.ResetTone();
5047 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005048
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005049 int16_t toneBuffer[320];
5050 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005051 // Get 10ms tone segment and set time since last tone to zero
5052 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5053 {
5054 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5055 VoEId(_instanceId, _channelId),
5056 "Channel::EncodeAndSend() inserting Dtmf failed");
5057 return -1;
5058 }
5059
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005060 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005061 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005062 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005063 sample++)
5064 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005065 for (int channel = 0;
5066 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005067 channel++)
5068 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005069 const int index = sample * _audioFrame.num_channels_ + channel;
5070 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005071 }
5072 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005073
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005074 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005075 } else
5076 {
5077 // Add 10ms to "delay-since-last-tone" counter
5078 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5079 }
5080 return 0;
5081}
5082
niklase@google.com470e71d2011-07-07 08:21:25 +00005083void
5084Channel::ResetDeadOrAliveCounters()
5085{
5086 _countDeadDetections = 0;
5087 _countAliveDetections = 0;
5088}
5089
5090void
5091Channel::UpdateDeadOrAliveCounters(bool alive)
5092{
5093 if (alive)
5094 _countAliveDetections++;
5095 else
5096 _countDeadDetections++;
5097}
5098
5099int
5100Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5101{
niklase@google.com470e71d2011-07-07 08:21:25 +00005102 return 0;
5103}
5104
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005105int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005106Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5107{
5108 if (_transportPtr == NULL)
5109 {
5110 return -1;
5111 }
5112 if (!RTCP)
5113 {
5114 return _transportPtr->SendPacket(_channelId, data, len);
5115 }
5116 else
5117 {
5118 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5119 }
5120}
5121
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005122// Called for incoming RTP packets after successful RTP header parsing.
5123void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5124 uint16_t sequence_number) {
5125 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5126 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5127 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005128
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005129 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005130 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005131
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005132 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005133 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005134 return;
5135 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005136
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005137 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005138 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005139
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005140 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5141 // Even though the actual sampling rate for G.722 audio is
5142 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5143 // 8,000 Hz because that value was erroneously assigned in
5144 // RFC 1890 and must remain unchanged for backward compatibility.
5145 rtp_receive_frequency = 8000;
5146 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5147 // We are resampling Opus internally to 32,000 Hz until all our
5148 // DSP routines can operate at 48,000 Hz, but the RTP clock
5149 // rate for the Opus payload format is standardized to 48,000 Hz,
5150 // because that is the maximum supported decoding sampling rate.
5151 rtp_receive_frequency = 48000;
5152 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005153
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005154 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5155 // packet.
5156 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5157 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005158
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005159 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5160 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005161
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005162 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005163
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005164 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5165 timestamp_diff_ms = 0;
5166 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005167
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005168 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005169
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005170 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5171 _recPacketDelayMs = packet_delay_ms;
5172 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005173
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005174 if (_average_jitter_buffer_delay_us == 0) {
5175 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5176 return;
5177 }
5178
5179 // Filter average delay value using exponential filter (alpha is
5180 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5181 // risk of rounding error) and compensate for it in GetDelayEstimate()
5182 // later.
5183 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5184 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005185}
5186
5187void
5188Channel::RegisterReceiveCodecsToRTPModule()
5189{
5190 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5191 "Channel::RegisterReceiveCodecsToRTPModule()");
5192
5193
5194 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005195 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005196
5197 for (int idx = 0; idx < nSupportedCodecs; idx++)
5198 {
5199 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005200 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005201 (rtp_receiver_->RegisterReceivePayload(
5202 codec.plname,
5203 codec.pltype,
5204 codec.plfreq,
5205 codec.channels,
5206 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005207 {
5208 WEBRTC_TRACE(
5209 kTraceWarning,
5210 kTraceVoice,
5211 VoEId(_instanceId, _channelId),
5212 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5213 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5214 codec.plname, codec.pltype, codec.plfreq,
5215 codec.channels, codec.rate);
5216 }
5217 else
5218 {
5219 WEBRTC_TRACE(
5220 kTraceInfo,
5221 kTraceVoice,
5222 VoEId(_instanceId, _channelId),
5223 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005224 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005225 "receiver",
5226 codec.plname, codec.pltype, codec.plfreq,
5227 codec.channels, codec.rate);
5228 }
5229 }
5230}
5231
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005232int Channel::ApmProcessRx(AudioFrame& frame) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005233 // Register the (possibly new) frame parameters.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005234 if (rx_audioproc_->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005235 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005236 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005237 if (rx_audioproc_->set_num_channels(frame.num_channels_,
5238 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005239 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005240 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005241 if (rx_audioproc_->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005242 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005243 }
5244 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005245}
5246
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005247int Channel::SetSecondarySendCodec(const CodecInst& codec,
5248 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005249 // Sanity check for payload type.
5250 if (red_payload_type < 0 || red_payload_type > 127) {
5251 _engineStatisticsPtr->SetLastError(
5252 VE_PLTYPE_ERROR, kTraceError,
5253 "SetRedPayloadType() invalid RED payload type");
5254 return -1;
5255 }
5256
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005257 if (SetRedPayloadType(red_payload_type) < 0) {
5258 _engineStatisticsPtr->SetLastError(
5259 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5260 "SetSecondarySendCodec() Failed to register RED ACM");
5261 return -1;
5262 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005263 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005264 _engineStatisticsPtr->SetLastError(
5265 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5266 "SetSecondarySendCodec() Failed to register secondary send codec in "
5267 "ACM");
5268 return -1;
5269 }
5270
5271 return 0;
5272}
5273
5274void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005275 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005276}
5277
5278int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005279 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005280 _engineStatisticsPtr->SetLastError(
5281 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5282 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5283 return -1;
5284 }
5285 return 0;
5286}
5287
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005288// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005289int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005290 CodecInst codec;
5291 bool found_red = false;
5292
5293 // Get default RED settings from the ACM database
5294 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5295 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005296 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005297 if (!STR_CASE_CMP(codec.plname, "RED")) {
5298 found_red = true;
5299 break;
5300 }
5301 }
5302
5303 if (!found_red) {
5304 _engineStatisticsPtr->SetLastError(
5305 VE_CODEC_ERROR, kTraceError,
5306 "SetRedPayloadType() RED is not supported");
5307 return -1;
5308 }
5309
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005310 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005311 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005312 _engineStatisticsPtr->SetLastError(
5313 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5314 "SetRedPayloadType() RED registration in ACM module failed");
5315 return -1;
5316 }
5317
5318 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5319 _engineStatisticsPtr->SetLastError(
5320 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5321 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5322 return -1;
5323 }
5324 return 0;
5325}
5326
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005327} // namespace voe
5328} // namespace webrtc