blob: 4ef3ed82cc1bcca8517d341d1e3e577f9ef21469 [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
wu@webrtc.org63420662013-10-17 18:28:55 +0000706 float output_gain = 1.0f;
707 float left_pan = 1.0f;
708 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000710 CriticalSectionScoped cs(&volume_settings_critsect_);
711 output_gain = _outputGain;
712 left_pan = _panLeft;
713 right_pan= _panRight;
714 }
715
716 // Output volume scaling
717 if (output_gain < 0.99f || output_gain > 1.01f)
718 {
719 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
721
722 // Scale left and/or right channel(s) if stereo and master balance is
723 // active
724
wu@webrtc.org63420662013-10-17 18:28:55 +0000725 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000727 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 {
729 // Emulate stereo mode since panning is active.
730 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000731 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 }
733 // For true stereo mode (when we are receiving a stereo signal), no
734 // action is needed.
735
736 // Do the panning operation (the audio frame contains stereo at this
737 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000738 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 }
740
741 // Mix decoded PCM output with file if file mixing is enabled
742 if (_outputFilePlaying)
743 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000744 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 }
746
747 // Place channel in on-hold state (~muted) if on-hold is activated
748 if (_outputIsOnHold)
749 {
750 AudioFrameOperations::Mute(audioFrame);
751 }
752
753 // External media
754 if (_outputExternalMedia)
755 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000756 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000757 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000758 if (_outputExternalMediaCallbackPtr)
759 {
760 _outputExternalMediaCallbackPtr->Process(
761 _channelId,
762 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000763 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000764 audioFrame.samples_per_channel_,
765 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 isStereo);
767 }
768 }
769
770 // Record playout if enabled
771 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000772 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000773
774 if (_outputFileRecording && _outputFileRecorderPtr)
775 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000776 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000777 }
778 }
779
780 // Measure audio level (0-9)
781 _outputAudioLevel.ComputeLevel(audioFrame);
782
783 return 0;
784}
785
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000786int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000787Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000788{
789 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
790 "Channel::NeededFrequency(id=%d)", id);
791
792 int highestNeeded = 0;
793
794 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000795 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000796
797 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000798 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000800 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000801 }
802 else
803 {
804 highestNeeded = receiveFrequency;
805 }
806
807 // Special case, if we're playing a file on the playout side
808 // we take that frequency into consideration as well
809 // This is not needed on sending side, since the codec will
810 // limit the spectrum anyway.
811 if (_outputFilePlaying)
812 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000813 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000814 if (_outputFilePlayerPtr && _outputFilePlaying)
815 {
816 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
817 {
818 highestNeeded=_outputFilePlayerPtr->Frequency();
819 }
820 }
821 }
822
823 return(highestNeeded);
824}
825
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000826int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000827Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000828 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000829 uint32_t instanceId,
830 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000831{
832 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
833 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
834 channelId, instanceId);
835
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000836 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 if (channel == NULL)
838 {
839 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
840 VoEId(instanceId,channelId),
841 "Channel::CreateChannel() unable to allocate memory for"
842 " channel");
843 return -1;
844 }
845 return 0;
846}
847
848void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000849Channel::PlayNotification(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::PlayNotification(id=%d, durationMs=%d)",
853 id, durationMs);
854
855 // Not implement yet
856}
857
858void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000859Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860{
861 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
862 "Channel::RecordNotification(id=%d, durationMs=%d)",
863 id, durationMs);
864
865 // Not implement yet
866}
867
868void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000869Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000870{
871 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
872 "Channel::PlayFileEnded(id=%d)", id);
873
874 if (id == _inputFilePlayerId)
875 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000876 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 _inputFilePlaying = false;
879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_instanceId,_channelId),
881 "Channel::PlayFileEnded() => input file player module is"
882 " shutdown");
883 }
884 else if (id == _outputFilePlayerId)
885 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000886 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000887
888 _outputFilePlaying = false;
889 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
890 VoEId(_instanceId,_channelId),
891 "Channel::PlayFileEnded() => output file player module is"
892 " shutdown");
893 }
894}
895
896void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000897Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000898{
899 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
900 "Channel::RecordFileEnded(id=%d)", id);
901
902 assert(id == _outputFileRecorderId);
903
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000904 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000905
906 _outputFileRecording = false;
907 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
908 VoEId(_instanceId,_channelId),
909 "Channel::RecordFileEnded() => output file recorder module is"
910 " shutdown");
911}
912
pbos@webrtc.org92135212013-05-14 08:31:39 +0000913Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000914 uint32_t instanceId,
915 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
917 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000918 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000920 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000921 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000922 rtp_payload_registry_(
923 new RTPPayloadRegistry(channelId,
924 RTPPayloadStrategy::CreateStrategy(true))),
925 rtp_receive_statistics_(ReceiveStatistics::Create(
926 Clock::GetRealTimeClock())),
927 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
928 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
929 this, this, rtp_payload_registry_.get())),
930 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000931 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000932 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 _rtpDumpIn(*RtpDump::CreateRtpDump()),
934 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000937 _inputFilePlayerPtr(NULL),
938 _outputFilePlayerPtr(NULL),
939 _outputFileRecorderPtr(NULL),
940 // Avoid conflict with other channels by adding 1024 - 1026,
941 // won't use as much as 1024 channels.
942 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
943 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
944 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
945 _inputFilePlaying(false),
946 _outputFilePlaying(false),
947 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000948 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
949 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000951 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 _inputExternalMediaCallbackPtr(NULL),
953 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000954 _encryptionRTPBufferPtr(NULL),
955 _decryptionRTPBufferPtr(NULL),
956 _encryptionRTCPBufferPtr(NULL),
957 _decryptionRTCPBufferPtr(NULL),
958 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
959 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000960 playout_timestamp_rtp_(0),
961 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000962 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000963 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000964 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000965 _outputMixerPtr(NULL),
966 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000967 _moduleProcessThreadPtr(NULL),
968 _audioDeviceModulePtr(NULL),
969 _voiceEngineObserverPtr(NULL),
970 _callbackCritSectPtr(NULL),
971 _transportPtr(NULL),
972 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000973 rtp_audioproc_(NULL),
974 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000975 _rxVadObserverPtr(NULL),
976 _oldVadDecision(-1),
977 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 _rtpObserverPtr(NULL),
979 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000980 _outputIsOnHold(false),
981 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000982 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000983 _inputIsOnHold(false),
984 _playing(false),
985 _sending(false),
986 _receiving(false),
987 _mixFileWithMicrophone(false),
988 _rtpObserver(false),
989 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 _mute(false),
991 _panLeft(1.0f),
992 _panRight(1.0f),
993 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000994 _encrypting(false),
995 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 _playOutbandDtmfEvent(false),
997 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 _extraPayloadType(0),
999 _insertExtraRTPPacket(false),
1000 _extraMarkerBit(false),
1001 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +00001002 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +00001004 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 _rtpPacketTimedOut(false),
1006 _rtpPacketTimeOutIsEnabled(false),
1007 _rtpTimeOutSeconds(0),
1008 _connectionObserver(false),
1009 _connectionObserverPtr(NULL),
1010 _countAliveDetections(0),
1011 _countDeadDetections(0),
1012 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001013 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00001014 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 _previousTimestamp(0),
1016 _recPacketDelayMs(20),
1017 _RxVadDetection(false),
1018 _rxApmIsEnabled(false),
1019 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001020 _rxNsIsEnabled(false),
1021 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001022{
1023 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1024 "Channel::Channel() - ctor");
1025 _inbandDtmfQueue.ResetDtmf();
1026 _inbandDtmfGenerator.Init();
1027 _outputAudioLevel.Clear();
1028
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001029 RtpRtcp::Configuration configuration;
1030 configuration.id = VoEModuleId(instanceId, channelId);
1031 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001032 configuration.outgoing_transport = this;
1033 configuration.rtcp_feedback = this;
1034 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001035 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001036
1037 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
niklase@google.com470e71d2011-07-07 08:21:25 +00001038}
1039
1040Channel::~Channel()
1041{
1042 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1043 "Channel::~Channel() - dtor");
1044
1045 if (_outputExternalMedia)
1046 {
1047 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1048 }
1049 if (_inputExternalMedia)
1050 {
1051 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1052 }
1053 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 StopPlayout();
1055
1056 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001057 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 if (_inputFilePlayerPtr)
1059 {
1060 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1061 _inputFilePlayerPtr->StopPlayingFile();
1062 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1063 _inputFilePlayerPtr = NULL;
1064 }
1065 if (_outputFilePlayerPtr)
1066 {
1067 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1068 _outputFilePlayerPtr->StopPlayingFile();
1069 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1070 _outputFilePlayerPtr = NULL;
1071 }
1072 if (_outputFileRecorderPtr)
1073 {
1074 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1075 _outputFileRecorderPtr->StopRecording();
1076 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1077 _outputFileRecorderPtr = NULL;
1078 }
1079 }
1080
1081 // The order to safely shutdown modules in a channel is:
1082 // 1. De-register callbacks in modules
1083 // 2. De-register modules in process thread
1084 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001085 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 {
1087 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1088 VoEId(_instanceId,_channelId),
1089 "~Channel() failed to de-register transport callback"
1090 " (Audio coding module)");
1091 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001092 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 {
1094 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1095 VoEId(_instanceId,_channelId),
1096 "~Channel() failed to de-register VAD callback"
1097 " (Audio coding module)");
1098 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001100 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001101 {
1102 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1103 VoEId(_instanceId,_channelId),
1104 "~Channel() failed to deregister RTP/RTCP module");
1105 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 // End of modules shutdown
1107
1108 // Delete other objects
1109 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1110 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1111 delete [] _encryptionRTPBufferPtr;
1112 delete [] _decryptionRTPBufferPtr;
1113 delete [] _encryptionRTCPBufferPtr;
1114 delete [] _decryptionRTCPBufferPtr;
1115 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001117 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001118}
1119
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001120int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001121Channel::Init()
1122{
1123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1124 "Channel::Init()");
1125
1126 // --- Initial sanity
1127
1128 if ((_engineStatisticsPtr == NULL) ||
1129 (_moduleProcessThreadPtr == NULL))
1130 {
1131 WEBRTC_TRACE(kTraceError, kTraceVoice,
1132 VoEId(_instanceId,_channelId),
1133 "Channel::Init() must call SetEngineInformation() first");
1134 return -1;
1135 }
1136
1137 // --- Add modules to process thread (for periodic schedulation)
1138
1139 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001140 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 if (processThreadFail)
1143 {
1144 _engineStatisticsPtr->SetLastError(
1145 VE_CANNOT_INIT_CHANNEL, kTraceError,
1146 "Channel::Init() modules not registered");
1147 return -1;
1148 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001149 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001150
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001151 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001152#ifdef WEBRTC_CODEC_AVT
1153 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001154 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001155#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001156 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 {
1158 _engineStatisticsPtr->SetLastError(
1159 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1160 "Channel::Init() unable to initialize the ACM - 1");
1161 return -1;
1162 }
1163
1164 // --- RTP/RTCP module initialization
1165
1166 // Ensure that RTCP is enabled by default for the created channel.
1167 // Note that, the module will keep generating RTCP until it is explicitly
1168 // disabled by the user.
1169 // After StopListen (when no sockets exists), RTCP packets will no longer
1170 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001171 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1172 // RTCP is enabled by default.
1173 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 {
1175 _engineStatisticsPtr->SetLastError(
1176 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1177 "Channel::Init() RTP/RTCP module not initialized");
1178 return -1;
1179 }
1180
1181 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001183 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1184 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001185
1186 if (fail)
1187 {
1188 _engineStatisticsPtr->SetLastError(
1189 VE_CANNOT_INIT_CHANNEL, kTraceError,
1190 "Channel::Init() callbacks not registered");
1191 return -1;
1192 }
1193
1194 // --- Register all supported codecs to the receiving side of the
1195 // RTP/RTCP module
1196
1197 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001198 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001199
1200 for (int idx = 0; idx < nSupportedCodecs; idx++)
1201 {
1202 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001203 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001204 (rtp_receiver_->RegisterReceivePayload(
1205 codec.plname,
1206 codec.pltype,
1207 codec.plfreq,
1208 codec.channels,
1209 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001210 {
1211 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1212 VoEId(_instanceId,_channelId),
1213 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1214 "to RTP/RTCP receiver",
1215 codec.plname, codec.pltype, codec.plfreq,
1216 codec.channels, codec.rate);
1217 }
1218 else
1219 {
1220 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1221 VoEId(_instanceId,_channelId),
1222 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1223 "the RTP/RTCP receiver",
1224 codec.plname, codec.pltype, codec.plfreq,
1225 codec.channels, codec.rate);
1226 }
1227
1228 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001229 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 {
1231 SetSendCodec(codec);
1232 }
1233
1234 // Register default PT for outband 'telephone-event'
1235 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1236 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001237 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001238 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001239 {
1240 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1241 VoEId(_instanceId,_channelId),
1242 "Channel::Init() failed to register outband "
1243 "'telephone-event' (%d/%d) correctly",
1244 codec.pltype, codec.plfreq);
1245 }
1246 }
1247
1248 if (!STR_CASE_CMP(codec.plname, "CN"))
1249 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001250 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1251 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001252 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 {
1254 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1255 VoEId(_instanceId,_channelId),
1256 "Channel::Init() failed to register CN (%d/%d) "
1257 "correctly - 1",
1258 codec.pltype, codec.plfreq);
1259 }
1260 }
1261#ifdef WEBRTC_CODEC_RED
1262 // Register RED to the receiving side of the ACM.
1263 // We will not receive an OnInitializeDecoder() callback for RED.
1264 if (!STR_CASE_CMP(codec.plname, "RED"))
1265 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001266 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001267 {
1268 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1269 VoEId(_instanceId,_channelId),
1270 "Channel::Init() failed to register RED (%d/%d) "
1271 "correctly",
1272 codec.pltype, codec.plfreq);
1273 }
1274 }
1275#endif
1276 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001277
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001278 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1279 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1280 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001282 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1283 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1284 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001285 }
1286
1287 return 0;
1288}
1289
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001290int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001291Channel::SetEngineInformation(Statistics& engineStatistics,
1292 OutputMixer& outputMixer,
1293 voe::TransmitMixer& transmitMixer,
1294 ProcessThread& moduleProcessThread,
1295 AudioDeviceModule& audioDeviceModule,
1296 VoiceEngineObserver* voiceEngineObserver,
1297 CriticalSectionWrapper* callbackCritSect)
1298{
1299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1300 "Channel::SetEngineInformation()");
1301 _engineStatisticsPtr = &engineStatistics;
1302 _outputMixerPtr = &outputMixer;
1303 _transmitMixerPtr = &transmitMixer,
1304 _moduleProcessThreadPtr = &moduleProcessThread;
1305 _audioDeviceModulePtr = &audioDeviceModule;
1306 _voiceEngineObserverPtr = voiceEngineObserver;
1307 _callbackCritSectPtr = callbackCritSect;
1308 return 0;
1309}
1310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001312Channel::UpdateLocalTimeStamp()
1313{
1314
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001315 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001316 return 0;
1317}
1318
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001319int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001320Channel::StartPlayout()
1321{
1322 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1323 "Channel::StartPlayout()");
1324 if (_playing)
1325 {
1326 return 0;
1327 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001328
1329 if (!_externalMixing) {
1330 // Add participant as candidates for mixing.
1331 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1332 {
1333 _engineStatisticsPtr->SetLastError(
1334 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1335 "StartPlayout() failed to add participant to mixer");
1336 return -1;
1337 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001338 }
1339
1340 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001341
1342 if (RegisterFilePlayingToMixer() != 0)
1343 return -1;
1344
niklase@google.com470e71d2011-07-07 08:21:25 +00001345 return 0;
1346}
1347
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001348int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001349Channel::StopPlayout()
1350{
1351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1352 "Channel::StopPlayout()");
1353 if (!_playing)
1354 {
1355 return 0;
1356 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001357
1358 if (!_externalMixing) {
1359 // Remove participant as candidates for mixing
1360 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1361 {
1362 _engineStatisticsPtr->SetLastError(
1363 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1364 "StopPlayout() failed to remove participant from mixer");
1365 return -1;
1366 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 }
1368
1369 _playing = false;
1370 _outputAudioLevel.Clear();
1371
1372 return 0;
1373}
1374
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001375int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001376Channel::StartSend()
1377{
1378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1379 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001380 // Resume the previous sequence number which was reset by StopSend().
1381 // This needs to be done before |_sending| is set to true.
1382 if (send_sequence_number_)
1383 SetInitSequenceNumber(send_sequence_number_);
1384
niklase@google.com470e71d2011-07-07 08:21:25 +00001385 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001386 // A lock is needed because |_sending| can be accessed or modified by
1387 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001388 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001389
1390 if (_sending)
1391 {
1392 return 0;
1393 }
1394 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001396
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001397 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001398 {
1399 _engineStatisticsPtr->SetLastError(
1400 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1401 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001402 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001403 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001404 return -1;
1405 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001406
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 return 0;
1408}
1409
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001410int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001411Channel::StopSend()
1412{
1413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1414 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001415 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001416 // A lock is needed because |_sending| can be accessed or modified by
1417 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001418 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001419
1420 if (!_sending)
1421 {
1422 return 0;
1423 }
1424 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001425 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001426
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001427 // Store the sequence number to be able to pick up the same sequence for
1428 // the next StartSend(). This is needed for restarting device, otherwise
1429 // it might cause libSRTP to complain about packets being replayed.
1430 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1431 // CL is landed. See issue
1432 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1433 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1434
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 // Reset sending SSRC and sequence number and triggers direct transmission
1436 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001437 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1438 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 {
1440 _engineStatisticsPtr->SetLastError(
1441 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1442 "StartSend() RTP/RTCP failed to stop sending");
1443 }
1444
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 return 0;
1446}
1447
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001448int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001449Channel::StartReceiving()
1450{
1451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1452 "Channel::StartReceiving()");
1453 if (_receiving)
1454 {
1455 return 0;
1456 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001457 _receiving = true;
1458 _numberOfDiscardedPackets = 0;
1459 return 0;
1460}
1461
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001462int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001463Channel::StopReceiving()
1464{
1465 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1466 "Channel::StopReceiving()");
1467 if (!_receiving)
1468 {
1469 return 0;
1470 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001471
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001472 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001473 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001474 RegisterReceiveCodecsToRTPModule();
1475 _receiving = false;
1476 return 0;
1477}
1478
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001479int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001480Channel::SetNetEQPlayoutMode(NetEqModes mode)
1481{
1482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1483 "Channel::SetNetEQPlayoutMode()");
1484 AudioPlayoutMode playoutMode(voice);
1485 switch (mode)
1486 {
1487 case kNetEqDefault:
1488 playoutMode = voice;
1489 break;
1490 case kNetEqStreaming:
1491 playoutMode = streaming;
1492 break;
1493 case kNetEqFax:
1494 playoutMode = fax;
1495 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001496 case kNetEqOff:
1497 playoutMode = off;
1498 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001500 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 {
1502 _engineStatisticsPtr->SetLastError(
1503 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1504 "SetNetEQPlayoutMode() failed to set playout mode");
1505 return -1;
1506 }
1507 return 0;
1508}
1509
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001510int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001511Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1512{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001513 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001514 switch (playoutMode)
1515 {
1516 case voice:
1517 mode = kNetEqDefault;
1518 break;
1519 case streaming:
1520 mode = kNetEqStreaming;
1521 break;
1522 case fax:
1523 mode = kNetEqFax;
1524 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001525 case off:
1526 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 }
1528 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1529 VoEId(_instanceId,_channelId),
1530 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1531 return 0;
1532}
1533
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001534int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001535Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1536{
1537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1538 "Channel::SetOnHoldStatus()");
1539 if (mode == kHoldSendAndPlay)
1540 {
1541 _outputIsOnHold = enable;
1542 _inputIsOnHold = enable;
1543 }
1544 else if (mode == kHoldPlayOnly)
1545 {
1546 _outputIsOnHold = enable;
1547 }
1548 if (mode == kHoldSendOnly)
1549 {
1550 _inputIsOnHold = enable;
1551 }
1552 return 0;
1553}
1554
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001555int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001556Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1557{
1558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1559 "Channel::GetOnHoldStatus()");
1560 enabled = (_outputIsOnHold || _inputIsOnHold);
1561 if (_outputIsOnHold && _inputIsOnHold)
1562 {
1563 mode = kHoldSendAndPlay;
1564 }
1565 else if (_outputIsOnHold && !_inputIsOnHold)
1566 {
1567 mode = kHoldPlayOnly;
1568 }
1569 else if (!_outputIsOnHold && _inputIsOnHold)
1570 {
1571 mode = kHoldSendOnly;
1572 }
1573 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1575 enabled, mode);
1576 return 0;
1577}
1578
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001579int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001580Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1581{
1582 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1583 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001584 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001585
1586 if (_voiceEngineObserverPtr)
1587 {
1588 _engineStatisticsPtr->SetLastError(
1589 VE_INVALID_OPERATION, kTraceError,
1590 "RegisterVoiceEngineObserver() observer already enabled");
1591 return -1;
1592 }
1593 _voiceEngineObserverPtr = &observer;
1594 return 0;
1595}
1596
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001597int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001598Channel::DeRegisterVoiceEngineObserver()
1599{
1600 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1601 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001602 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001603
1604 if (!_voiceEngineObserverPtr)
1605 {
1606 _engineStatisticsPtr->SetLastError(
1607 VE_INVALID_OPERATION, kTraceWarning,
1608 "DeRegisterVoiceEngineObserver() observer already disabled");
1609 return 0;
1610 }
1611 _voiceEngineObserverPtr = NULL;
1612 return 0;
1613}
1614
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001615int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001616Channel::GetSendCodec(CodecInst& codec)
1617{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001618 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001619}
1620
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001621int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001622Channel::GetRecCodec(CodecInst& codec)
1623{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001624 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001625}
1626
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001627int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001628Channel::SetSendCodec(const CodecInst& codec)
1629{
1630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1631 "Channel::SetSendCodec()");
1632
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001633 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001634 {
1635 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1636 "SetSendCodec() failed to register codec to ACM");
1637 return -1;
1638 }
1639
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001640 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001641 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001642 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1643 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001644 {
1645 WEBRTC_TRACE(
1646 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1647 "SetSendCodec() failed to register codec to"
1648 " RTP/RTCP module");
1649 return -1;
1650 }
1651 }
1652
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001653 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001654 {
1655 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1656 "SetSendCodec() failed to set audio packet size");
1657 return -1;
1658 }
1659
1660 return 0;
1661}
1662
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001663int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001664Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1665{
1666 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1667 "Channel::SetVADStatus(mode=%d)", mode);
1668 // To disable VAD, DTX must be disabled too
1669 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001670 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674 "SetVADStatus() failed to set VAD");
1675 return -1;
1676 }
1677 return 0;
1678}
1679
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001680int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001681Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1682{
1683 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1684 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001685 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001686 {
1687 _engineStatisticsPtr->SetLastError(
1688 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1689 "GetVADStatus() failed to get VAD status");
1690 return -1;
1691 }
1692 disabledDTX = !disabledDTX;
1693 return 0;
1694}
1695
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001696int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001697Channel::SetRecPayloadType(const CodecInst& codec)
1698{
1699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1700 "Channel::SetRecPayloadType()");
1701
1702 if (_playing)
1703 {
1704 _engineStatisticsPtr->SetLastError(
1705 VE_ALREADY_PLAYING, kTraceError,
1706 "SetRecPayloadType() unable to set PT while playing");
1707 return -1;
1708 }
1709 if (_receiving)
1710 {
1711 _engineStatisticsPtr->SetLastError(
1712 VE_ALREADY_LISTENING, kTraceError,
1713 "SetRecPayloadType() unable to set PT while listening");
1714 return -1;
1715 }
1716
1717 if (codec.pltype == -1)
1718 {
1719 // De-register the selected codec (RTP/RTCP module and ACM)
1720
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001721 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001722 CodecInst rxCodec = codec;
1723
1724 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001725 rtp_payload_registry_->ReceivePayloadType(
1726 rxCodec.plname,
1727 rxCodec.plfreq,
1728 rxCodec.channels,
1729 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1730 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001731 rxCodec.pltype = pltype;
1732
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001733 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001734 {
1735 _engineStatisticsPtr->SetLastError(
1736 VE_RTP_RTCP_MODULE_ERROR,
1737 kTraceError,
1738 "SetRecPayloadType() RTP/RTCP-module deregistration "
1739 "failed");
1740 return -1;
1741 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001742 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001743 {
1744 _engineStatisticsPtr->SetLastError(
1745 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1746 "SetRecPayloadType() ACM deregistration failed - 1");
1747 return -1;
1748 }
1749 return 0;
1750 }
1751
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001752 if (rtp_receiver_->RegisterReceivePayload(
1753 codec.plname,
1754 codec.pltype,
1755 codec.plfreq,
1756 codec.channels,
1757 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001758 {
1759 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001760 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1761 if (rtp_receiver_->RegisterReceivePayload(
1762 codec.plname,
1763 codec.pltype,
1764 codec.plfreq,
1765 codec.channels,
1766 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001767 {
1768 _engineStatisticsPtr->SetLastError(
1769 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1770 "SetRecPayloadType() RTP/RTCP-module registration failed");
1771 return -1;
1772 }
1773 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001774 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001775 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001776 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1777 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001778 {
1779 _engineStatisticsPtr->SetLastError(
1780 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1781 "SetRecPayloadType() ACM registration failed - 1");
1782 return -1;
1783 }
1784 }
1785 return 0;
1786}
1787
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001788int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001789Channel::GetRecPayloadType(CodecInst& codec)
1790{
1791 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1792 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001793 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001794 if (rtp_payload_registry_->ReceivePayloadType(
1795 codec.plname,
1796 codec.plfreq,
1797 codec.channels,
1798 (codec.rate < 0) ? 0 : codec.rate,
1799 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001800 {
1801 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001802 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001803 "GetRecPayloadType() failed to retrieve RX payload type");
1804 return -1;
1805 }
1806 codec.pltype = payloadType;
1807 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1808 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1809 return 0;
1810}
1811
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001812int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001813Channel::SetAMREncFormat(AmrMode mode)
1814{
1815 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1816 "Channel::SetAMREncFormat()");
1817
1818 // ACM doesn't support AMR
1819 return -1;
1820}
1821
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001822int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001823Channel::SetAMRDecFormat(AmrMode mode)
1824{
1825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1826 "Channel::SetAMRDecFormat()");
1827
1828 // ACM doesn't support AMR
1829 return -1;
1830}
1831
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001832int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001833Channel::SetAMRWbEncFormat(AmrMode mode)
1834{
1835 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1836 "Channel::SetAMRWbEncFormat()");
1837
1838 // ACM doesn't support AMR
1839 return -1;
1840
1841}
1842
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001843int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001844Channel::SetAMRWbDecFormat(AmrMode mode)
1845{
1846 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1847 "Channel::SetAMRWbDecFormat()");
1848
1849 // ACM doesn't support AMR
1850 return -1;
1851}
1852
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001853int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001854Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1855{
1856 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1857 "Channel::SetSendCNPayloadType()");
1858
1859 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001860 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001861 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001862 if (frequency == kFreq32000Hz)
1863 samplingFreqHz = 32000;
1864 else if (frequency == kFreq16000Hz)
1865 samplingFreqHz = 16000;
1866
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001867 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1871 "SetSendCNPayloadType() failed to retrieve default CN codec "
1872 "settings");
1873 return -1;
1874 }
1875
1876 // Modify the payload type (must be set to dynamic range)
1877 codec.pltype = type;
1878
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001879 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001880 {
1881 _engineStatisticsPtr->SetLastError(
1882 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1883 "SetSendCNPayloadType() failed to register CN to ACM");
1884 return -1;
1885 }
1886
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001887 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001888 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001889 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1890 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001891 {
1892 _engineStatisticsPtr->SetLastError(
1893 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1894 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1895 "module");
1896 return -1;
1897 }
1898 }
1899 return 0;
1900}
1901
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001902int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001903Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1904{
1905 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1906 "Channel::SetISACInitTargetRate()");
1907
1908 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001909 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001910 {
1911 _engineStatisticsPtr->SetLastError(
1912 VE_CODEC_ERROR, kTraceError,
1913 "SetISACInitTargetRate() failed to retrieve send codec");
1914 return -1;
1915 }
1916 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1917 {
1918 // This API is only valid if iSAC is setup to run in channel-adaptive
1919 // mode.
1920 // We do not validate the adaptive mode here. It is done later in the
1921 // ConfigISACBandwidthEstimator() API.
1922 _engineStatisticsPtr->SetLastError(
1923 VE_CODEC_ERROR, kTraceError,
1924 "SetISACInitTargetRate() send codec is not iSAC");
1925 return -1;
1926 }
1927
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001928 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001929 if (16000 == sendCodec.plfreq)
1930 {
1931 // Note that 0 is a valid and corresponds to "use default
1932 if ((rateBps != 0 &&
1933 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1934 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1935 {
1936 _engineStatisticsPtr->SetLastError(
1937 VE_INVALID_ARGUMENT, kTraceError,
1938 "SetISACInitTargetRate() invalid target rate - 1");
1939 return -1;
1940 }
1941 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001942 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001943 }
1944 else if (32000 == sendCodec.plfreq)
1945 {
1946 if ((rateBps != 0 &&
1947 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1948 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1949 {
1950 _engineStatisticsPtr->SetLastError(
1951 VE_INVALID_ARGUMENT, kTraceError,
1952 "SetISACInitTargetRate() invalid target rate - 2");
1953 return -1;
1954 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001955 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001956 }
1957
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001958 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001959 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1960 {
1961 _engineStatisticsPtr->SetLastError(
1962 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1963 "SetISACInitTargetRate() iSAC BWE config failed");
1964 return -1;
1965 }
1966
1967 return 0;
1968}
1969
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001970int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001971Channel::SetISACMaxRate(int rateBps)
1972{
1973 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1974 "Channel::SetISACMaxRate()");
1975
1976 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001977 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001978 {
1979 _engineStatisticsPtr->SetLastError(
1980 VE_CODEC_ERROR, kTraceError,
1981 "SetISACMaxRate() failed to retrieve send codec");
1982 return -1;
1983 }
1984 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1985 {
1986 // This API is only valid if iSAC is selected as sending codec.
1987 _engineStatisticsPtr->SetLastError(
1988 VE_CODEC_ERROR, kTraceError,
1989 "SetISACMaxRate() send codec is not iSAC");
1990 return -1;
1991 }
1992 if (16000 == sendCodec.plfreq)
1993 {
1994 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1995 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1996 {
1997 _engineStatisticsPtr->SetLastError(
1998 VE_INVALID_ARGUMENT, kTraceError,
1999 "SetISACMaxRate() invalid max rate - 1");
2000 return -1;
2001 }
2002 }
2003 else if (32000 == sendCodec.plfreq)
2004 {
2005 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2006 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2007 {
2008 _engineStatisticsPtr->SetLastError(
2009 VE_INVALID_ARGUMENT, kTraceError,
2010 "SetISACMaxRate() invalid max rate - 2");
2011 return -1;
2012 }
2013 }
2014 if (_sending)
2015 {
2016 _engineStatisticsPtr->SetLastError(
2017 VE_SENDING, kTraceError,
2018 "SetISACMaxRate() unable to set max rate while sending");
2019 return -1;
2020 }
2021
2022 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2023 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002024 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002025 {
2026 _engineStatisticsPtr->SetLastError(
2027 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2028 "SetISACMaxRate() failed to set max rate");
2029 return -1;
2030 }
2031
2032 return 0;
2033}
2034
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002035int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002036Channel::SetISACMaxPayloadSize(int sizeBytes)
2037{
2038 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2039 "Channel::SetISACMaxPayloadSize()");
2040 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002041 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002042 {
2043 _engineStatisticsPtr->SetLastError(
2044 VE_CODEC_ERROR, kTraceError,
2045 "SetISACMaxPayloadSize() failed to retrieve send codec");
2046 return -1;
2047 }
2048 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2049 {
2050 _engineStatisticsPtr->SetLastError(
2051 VE_CODEC_ERROR, kTraceError,
2052 "SetISACMaxPayloadSize() send codec is not iSAC");
2053 return -1;
2054 }
2055 if (16000 == sendCodec.plfreq)
2056 {
2057 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2058 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2059 {
2060 _engineStatisticsPtr->SetLastError(
2061 VE_INVALID_ARGUMENT, kTraceError,
2062 "SetISACMaxPayloadSize() invalid max payload - 1");
2063 return -1;
2064 }
2065 }
2066 else if (32000 == sendCodec.plfreq)
2067 {
2068 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2069 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2070 {
2071 _engineStatisticsPtr->SetLastError(
2072 VE_INVALID_ARGUMENT, kTraceError,
2073 "SetISACMaxPayloadSize() invalid max payload - 2");
2074 return -1;
2075 }
2076 }
2077 if (_sending)
2078 {
2079 _engineStatisticsPtr->SetLastError(
2080 VE_SENDING, kTraceError,
2081 "SetISACMaxPayloadSize() unable to set max rate while sending");
2082 return -1;
2083 }
2084
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002085 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002086 {
2087 _engineStatisticsPtr->SetLastError(
2088 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2089 "SetISACMaxPayloadSize() failed to set max payload size");
2090 return -1;
2091 }
2092 return 0;
2093}
2094
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002095int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002096{
2097 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2098 "Channel::RegisterExternalTransport()");
2099
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002100 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002101
niklase@google.com470e71d2011-07-07 08:21:25 +00002102 if (_externalTransport)
2103 {
2104 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2105 kTraceError,
2106 "RegisterExternalTransport() external transport already enabled");
2107 return -1;
2108 }
2109 _externalTransport = true;
2110 _transportPtr = &transport;
2111 return 0;
2112}
2113
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002114int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002115Channel::DeRegisterExternalTransport()
2116{
2117 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2118 "Channel::DeRegisterExternalTransport()");
2119
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002120 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002121
niklase@google.com470e71d2011-07-07 08:21:25 +00002122 if (!_transportPtr)
2123 {
2124 _engineStatisticsPtr->SetLastError(
2125 VE_INVALID_OPERATION, kTraceWarning,
2126 "DeRegisterExternalTransport() external transport already "
2127 "disabled");
2128 return 0;
2129 }
2130 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002131 _transportPtr = NULL;
2132 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2133 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002134 return 0;
2135}
2136
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002137int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002138 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2139 "Channel::ReceivedRTPPacket()");
2140
2141 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002142 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002143
2144 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002145 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2146 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002147 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2148 VoEId(_instanceId,_channelId),
2149 "Channel::SendPacket() RTP dump to input file failed");
2150 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002151 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002152 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002153 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2154 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2155 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002156 return -1;
2157 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002158 header.payload_type_frequency =
2159 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002160 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002161 return -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002162 rtp_receive_statistics_->IncomingPacket(header, length,
2163 IsPacketRetransmitted(header));
2164 rtp_payload_registry_->SetIncomingPayloadType(header);
2165 return ReceivePacket(received_packet, length, header,
2166 IsPacketInOrder(header)) ? 0 : -1;
2167}
2168
2169bool Channel::ReceivePacket(const uint8_t* packet,
2170 int packet_length,
2171 const RTPHeader& header,
2172 bool in_order) {
2173 if (rtp_payload_registry_->IsEncapsulated(header)) {
2174 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002175 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002176 const uint8_t* payload = packet + header.headerLength;
2177 int payload_length = packet_length - header.headerLength;
2178 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002179 PayloadUnion payload_specific;
2180 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002181 &payload_specific)) {
2182 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002183 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002184 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2185 payload_specific, in_order);
2186}
2187
2188bool Channel::HandleEncapsulation(const uint8_t* packet,
2189 int packet_length,
2190 const RTPHeader& header) {
2191 if (!rtp_payload_registry_->IsRtx(header))
2192 return false;
2193
2194 // Remove the RTX header and parse the original RTP header.
2195 if (packet_length < header.headerLength)
2196 return false;
2197 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2198 return false;
2199 if (restored_packet_in_use_) {
2200 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2201 "Multiple RTX headers detected, dropping packet");
2202 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002203 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002204 uint8_t* restored_packet_ptr = restored_packet_;
2205 if (!rtp_payload_registry_->RestoreOriginalPacket(
2206 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2207 header)) {
2208 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2209 "Incoming RTX packet: invalid RTP header");
2210 return false;
2211 }
2212 restored_packet_in_use_ = true;
2213 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2214 restored_packet_in_use_ = false;
2215 return ret;
2216}
2217
2218bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2219 StreamStatistician* statistician =
2220 rtp_receive_statistics_->GetStatistician(header.ssrc);
2221 if (!statistician)
2222 return false;
2223 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002224}
2225
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002226bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002227 // Retransmissions are handled separately if RTX is enabled.
2228 if (rtp_payload_registry_->RtxEnabled())
2229 return false;
2230 StreamStatistician* statistician =
2231 rtp_receive_statistics_->GetStatistician(header.ssrc);
2232 if (!statistician)
2233 return false;
2234 // Check if this is a retransmission.
2235 uint16_t min_rtt = 0;
2236 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
2237 return !IsPacketInOrder(header) &&
2238 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002239}
2240
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002241int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002242 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2243 "Channel::ReceivedRTCPPacket()");
2244 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002245 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002246
2247 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002248 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2249 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002250 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2251 VoEId(_instanceId,_channelId),
2252 "Channel::SendPacket() RTCP dump to input file failed");
2253 }
2254
2255 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002256 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2257 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002258 _engineStatisticsPtr->SetLastError(
2259 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2260 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2261 }
2262 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002263}
2264
niklase@google.com470e71d2011-07-07 08:21:25 +00002265int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002266 bool loop,
2267 FileFormats format,
2268 int startPosition,
2269 float volumeScaling,
2270 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002271 const CodecInst* codecInst)
2272{
2273 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2274 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2275 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2276 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2277 startPosition, stopPosition);
2278
2279 if (_outputFilePlaying)
2280 {
2281 _engineStatisticsPtr->SetLastError(
2282 VE_ALREADY_PLAYING, kTraceError,
2283 "StartPlayingFileLocally() is already playing");
2284 return -1;
2285 }
2286
niklase@google.com470e71d2011-07-07 08:21:25 +00002287 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002288 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002289
2290 if (_outputFilePlayerPtr)
2291 {
2292 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2293 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2294 _outputFilePlayerPtr = NULL;
2295 }
2296
2297 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2298 _outputFilePlayerId, (const FileFormats)format);
2299
2300 if (_outputFilePlayerPtr == NULL)
2301 {
2302 _engineStatisticsPtr->SetLastError(
2303 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002304 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002305 return -1;
2306 }
2307
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002308 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002309
2310 if (_outputFilePlayerPtr->StartPlayingFile(
2311 fileName,
2312 loop,
2313 startPosition,
2314 volumeScaling,
2315 notificationTime,
2316 stopPosition,
2317 (const CodecInst*)codecInst) != 0)
2318 {
2319 _engineStatisticsPtr->SetLastError(
2320 VE_BAD_FILE, kTraceError,
2321 "StartPlayingFile() failed to start file playout");
2322 _outputFilePlayerPtr->StopPlayingFile();
2323 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2324 _outputFilePlayerPtr = NULL;
2325 return -1;
2326 }
2327 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2328 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002329 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002330
2331 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002332 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002333
2334 return 0;
2335}
2336
2337int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002338 FileFormats format,
2339 int startPosition,
2340 float volumeScaling,
2341 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 const CodecInst* codecInst)
2343{
2344 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2345 "Channel::StartPlayingFileLocally(format=%d,"
2346 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2347 format, volumeScaling, startPosition, stopPosition);
2348
2349 if(stream == NULL)
2350 {
2351 _engineStatisticsPtr->SetLastError(
2352 VE_BAD_FILE, kTraceError,
2353 "StartPlayingFileLocally() NULL as input stream");
2354 return -1;
2355 }
2356
2357
2358 if (_outputFilePlaying)
2359 {
2360 _engineStatisticsPtr->SetLastError(
2361 VE_ALREADY_PLAYING, kTraceError,
2362 "StartPlayingFileLocally() is already playing");
2363 return -1;
2364 }
2365
niklase@google.com470e71d2011-07-07 08:21:25 +00002366 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002367 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002368
2369 // Destroy the old instance
2370 if (_outputFilePlayerPtr)
2371 {
2372 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2373 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2374 _outputFilePlayerPtr = NULL;
2375 }
2376
2377 // Create the instance
2378 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2379 _outputFilePlayerId,
2380 (const FileFormats)format);
2381
2382 if (_outputFilePlayerPtr == NULL)
2383 {
2384 _engineStatisticsPtr->SetLastError(
2385 VE_INVALID_ARGUMENT, kTraceError,
2386 "StartPlayingFileLocally() filePlayer format isnot correct");
2387 return -1;
2388 }
2389
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002390 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002391
2392 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2393 volumeScaling,
2394 notificationTime,
2395 stopPosition, codecInst) != 0)
2396 {
2397 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2398 "StartPlayingFile() failed to "
2399 "start file playout");
2400 _outputFilePlayerPtr->StopPlayingFile();
2401 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2402 _outputFilePlayerPtr = NULL;
2403 return -1;
2404 }
2405 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2406 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002407 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002408
2409 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002410 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002411
niklase@google.com470e71d2011-07-07 08:21:25 +00002412 return 0;
2413}
2414
2415int Channel::StopPlayingFileLocally()
2416{
2417 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2418 "Channel::StopPlayingFileLocally()");
2419
2420 if (!_outputFilePlaying)
2421 {
2422 _engineStatisticsPtr->SetLastError(
2423 VE_INVALID_OPERATION, kTraceWarning,
2424 "StopPlayingFileLocally() isnot playing");
2425 return 0;
2426 }
2427
niklase@google.com470e71d2011-07-07 08:21:25 +00002428 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002429 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002430
2431 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2432 {
2433 _engineStatisticsPtr->SetLastError(
2434 VE_STOP_RECORDING_FAILED, kTraceError,
2435 "StopPlayingFile() could not stop playing");
2436 return -1;
2437 }
2438 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2439 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2440 _outputFilePlayerPtr = NULL;
2441 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002442 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002443 // _fileCritSect cannot be taken while calling
2444 // SetAnonymousMixibilityStatus. Refer to comments in
2445 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002446 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2447 {
2448 _engineStatisticsPtr->SetLastError(
2449 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002450 "StopPlayingFile() failed to stop participant from playing as"
2451 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002452 return -1;
2453 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002454
2455 return 0;
2456}
2457
2458int Channel::IsPlayingFileLocally() const
2459{
2460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2461 "Channel::IsPlayingFileLocally()");
2462
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002463 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002464}
2465
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002466int Channel::RegisterFilePlayingToMixer()
2467{
2468 // Return success for not registering for file playing to mixer if:
2469 // 1. playing file before playout is started on that channel.
2470 // 2. starting playout without file playing on that channel.
2471 if (!_playing || !_outputFilePlaying)
2472 {
2473 return 0;
2474 }
2475
2476 // |_fileCritSect| cannot be taken while calling
2477 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2478 // frames can be pulled by the mixer. Since the frames are generated from
2479 // the file, _fileCritSect will be taken. This would result in a deadlock.
2480 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2481 {
2482 CriticalSectionScoped cs(&_fileCritSect);
2483 _outputFilePlaying = false;
2484 _engineStatisticsPtr->SetLastError(
2485 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2486 "StartPlayingFile() failed to add participant as file to mixer");
2487 _outputFilePlayerPtr->StopPlayingFile();
2488 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2489 _outputFilePlayerPtr = NULL;
2490 return -1;
2491 }
2492
2493 return 0;
2494}
2495
pbos@webrtc.org92135212013-05-14 08:31:39 +00002496int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002497{
2498 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2499 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2500
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002501 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002502
2503 if (!_outputFilePlaying)
2504 {
2505 _engineStatisticsPtr->SetLastError(
2506 VE_INVALID_OPERATION, kTraceError,
2507 "ScaleLocalFilePlayout() isnot playing");
2508 return -1;
2509 }
2510 if ((_outputFilePlayerPtr == NULL) ||
2511 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2512 {
2513 _engineStatisticsPtr->SetLastError(
2514 VE_BAD_ARGUMENT, kTraceError,
2515 "SetAudioScaling() failed to scale the playout");
2516 return -1;
2517 }
2518
2519 return 0;
2520}
2521
2522int Channel::GetLocalPlayoutPosition(int& positionMs)
2523{
2524 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2525 "Channel::GetLocalPlayoutPosition(position=?)");
2526
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002527 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002528
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002529 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002530
2531 if (_outputFilePlayerPtr == NULL)
2532 {
2533 _engineStatisticsPtr->SetLastError(
2534 VE_INVALID_OPERATION, kTraceError,
2535 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2536 return -1;
2537 }
2538
2539 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2540 {
2541 _engineStatisticsPtr->SetLastError(
2542 VE_BAD_FILE, kTraceError,
2543 "GetLocalPlayoutPosition() failed");
2544 return -1;
2545 }
2546 positionMs = position;
2547
2548 return 0;
2549}
2550
2551int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002552 bool loop,
2553 FileFormats format,
2554 int startPosition,
2555 float volumeScaling,
2556 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002557 const CodecInst* codecInst)
2558{
2559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2560 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2561 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2562 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2563 startPosition, stopPosition);
2564
2565 if (_inputFilePlaying)
2566 {
2567 _engineStatisticsPtr->SetLastError(
2568 VE_ALREADY_PLAYING, kTraceWarning,
2569 "StartPlayingFileAsMicrophone() filePlayer is playing");
2570 return 0;
2571 }
2572
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002573 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002574
2575 // Destroy the old instance
2576 if (_inputFilePlayerPtr)
2577 {
2578 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2579 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2580 _inputFilePlayerPtr = NULL;
2581 }
2582
2583 // Create the instance
2584 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2585 _inputFilePlayerId, (const FileFormats)format);
2586
2587 if (_inputFilePlayerPtr == NULL)
2588 {
2589 _engineStatisticsPtr->SetLastError(
2590 VE_INVALID_ARGUMENT, kTraceError,
2591 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2592 return -1;
2593 }
2594
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002595 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002596
2597 if (_inputFilePlayerPtr->StartPlayingFile(
2598 fileName,
2599 loop,
2600 startPosition,
2601 volumeScaling,
2602 notificationTime,
2603 stopPosition,
2604 (const CodecInst*)codecInst) != 0)
2605 {
2606 _engineStatisticsPtr->SetLastError(
2607 VE_BAD_FILE, kTraceError,
2608 "StartPlayingFile() failed to start file playout");
2609 _inputFilePlayerPtr->StopPlayingFile();
2610 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2611 _inputFilePlayerPtr = NULL;
2612 return -1;
2613 }
2614 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2615 _inputFilePlaying = true;
2616
2617 return 0;
2618}
2619
2620int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002621 FileFormats format,
2622 int startPosition,
2623 float volumeScaling,
2624 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002625 const CodecInst* codecInst)
2626{
2627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2628 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2629 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2630 format, volumeScaling, startPosition, stopPosition);
2631
2632 if(stream == NULL)
2633 {
2634 _engineStatisticsPtr->SetLastError(
2635 VE_BAD_FILE, kTraceError,
2636 "StartPlayingFileAsMicrophone NULL as input stream");
2637 return -1;
2638 }
2639
2640 if (_inputFilePlaying)
2641 {
2642 _engineStatisticsPtr->SetLastError(
2643 VE_ALREADY_PLAYING, kTraceWarning,
2644 "StartPlayingFileAsMicrophone() is playing");
2645 return 0;
2646 }
2647
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002648 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002649
2650 // Destroy the old instance
2651 if (_inputFilePlayerPtr)
2652 {
2653 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2654 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2655 _inputFilePlayerPtr = NULL;
2656 }
2657
2658 // Create the instance
2659 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2660 _inputFilePlayerId, (const FileFormats)format);
2661
2662 if (_inputFilePlayerPtr == NULL)
2663 {
2664 _engineStatisticsPtr->SetLastError(
2665 VE_INVALID_ARGUMENT, kTraceError,
2666 "StartPlayingInputFile() filePlayer format isnot correct");
2667 return -1;
2668 }
2669
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002670 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002671
2672 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2673 volumeScaling, notificationTime,
2674 stopPosition, codecInst) != 0)
2675 {
2676 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2677 "StartPlayingFile() failed to start "
2678 "file playout");
2679 _inputFilePlayerPtr->StopPlayingFile();
2680 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2681 _inputFilePlayerPtr = NULL;
2682 return -1;
2683 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002684
niklase@google.com470e71d2011-07-07 08:21:25 +00002685 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2686 _inputFilePlaying = true;
2687
2688 return 0;
2689}
2690
2691int Channel::StopPlayingFileAsMicrophone()
2692{
2693 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2694 "Channel::StopPlayingFileAsMicrophone()");
2695
2696 if (!_inputFilePlaying)
2697 {
2698 _engineStatisticsPtr->SetLastError(
2699 VE_INVALID_OPERATION, kTraceWarning,
2700 "StopPlayingFileAsMicrophone() isnot playing");
2701 return 0;
2702 }
2703
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002704 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002705 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2706 {
2707 _engineStatisticsPtr->SetLastError(
2708 VE_STOP_RECORDING_FAILED, kTraceError,
2709 "StopPlayingFile() could not stop playing");
2710 return -1;
2711 }
2712 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2713 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2714 _inputFilePlayerPtr = NULL;
2715 _inputFilePlaying = false;
2716
2717 return 0;
2718}
2719
2720int Channel::IsPlayingFileAsMicrophone() const
2721{
2722 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2723 "Channel::IsPlayingFileAsMicrophone()");
2724
2725 return _inputFilePlaying;
2726}
2727
pbos@webrtc.org92135212013-05-14 08:31:39 +00002728int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002729{
2730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2731 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2732
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002733 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002734
2735 if (!_inputFilePlaying)
2736 {
2737 _engineStatisticsPtr->SetLastError(
2738 VE_INVALID_OPERATION, kTraceError,
2739 "ScaleFileAsMicrophonePlayout() isnot playing");
2740 return -1;
2741 }
2742
2743 if ((_inputFilePlayerPtr == NULL) ||
2744 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2745 {
2746 _engineStatisticsPtr->SetLastError(
2747 VE_BAD_ARGUMENT, kTraceError,
2748 "SetAudioScaling() failed to scale playout");
2749 return -1;
2750 }
2751
2752 return 0;
2753}
2754
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002755int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002756 const CodecInst* codecInst)
2757{
2758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2759 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2760
2761 if (_outputFileRecording)
2762 {
2763 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2764 "StartRecordingPlayout() is already recording");
2765 return 0;
2766 }
2767
2768 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002769 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002770 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2771
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002772 if ((codecInst != NULL) &&
2773 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002774 {
2775 _engineStatisticsPtr->SetLastError(
2776 VE_BAD_ARGUMENT, kTraceError,
2777 "StartRecordingPlayout() invalid compression");
2778 return(-1);
2779 }
2780 if(codecInst == NULL)
2781 {
2782 format = kFileFormatPcm16kHzFile;
2783 codecInst=&dummyCodec;
2784 }
2785 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2786 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2787 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2788 {
2789 format = kFileFormatWavFile;
2790 }
2791 else
2792 {
2793 format = kFileFormatCompressedFile;
2794 }
2795
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002796 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002797
2798 // Destroy the old instance
2799 if (_outputFileRecorderPtr)
2800 {
2801 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2802 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2803 _outputFileRecorderPtr = NULL;
2804 }
2805
2806 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2807 _outputFileRecorderId, (const FileFormats)format);
2808 if (_outputFileRecorderPtr == NULL)
2809 {
2810 _engineStatisticsPtr->SetLastError(
2811 VE_INVALID_ARGUMENT, kTraceError,
2812 "StartRecordingPlayout() fileRecorder format isnot correct");
2813 return -1;
2814 }
2815
2816 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2817 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2818 {
2819 _engineStatisticsPtr->SetLastError(
2820 VE_BAD_FILE, kTraceError,
2821 "StartRecordingAudioFile() failed to start file recording");
2822 _outputFileRecorderPtr->StopRecording();
2823 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2824 _outputFileRecorderPtr = NULL;
2825 return -1;
2826 }
2827 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2828 _outputFileRecording = true;
2829
2830 return 0;
2831}
2832
2833int Channel::StartRecordingPlayout(OutStream* stream,
2834 const CodecInst* codecInst)
2835{
2836 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2837 "Channel::StartRecordingPlayout()");
2838
2839 if (_outputFileRecording)
2840 {
2841 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2842 "StartRecordingPlayout() is already recording");
2843 return 0;
2844 }
2845
2846 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002847 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002848 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2849
2850 if (codecInst != NULL && codecInst->channels != 1)
2851 {
2852 _engineStatisticsPtr->SetLastError(
2853 VE_BAD_ARGUMENT, kTraceError,
2854 "StartRecordingPlayout() invalid compression");
2855 return(-1);
2856 }
2857 if(codecInst == NULL)
2858 {
2859 format = kFileFormatPcm16kHzFile;
2860 codecInst=&dummyCodec;
2861 }
2862 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2863 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2864 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2865 {
2866 format = kFileFormatWavFile;
2867 }
2868 else
2869 {
2870 format = kFileFormatCompressedFile;
2871 }
2872
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002873 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002874
2875 // Destroy the old instance
2876 if (_outputFileRecorderPtr)
2877 {
2878 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2879 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2880 _outputFileRecorderPtr = NULL;
2881 }
2882
2883 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2884 _outputFileRecorderId, (const FileFormats)format);
2885 if (_outputFileRecorderPtr == NULL)
2886 {
2887 _engineStatisticsPtr->SetLastError(
2888 VE_INVALID_ARGUMENT, kTraceError,
2889 "StartRecordingPlayout() fileRecorder format isnot correct");
2890 return -1;
2891 }
2892
2893 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2894 notificationTime) != 0)
2895 {
2896 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2897 "StartRecordingPlayout() failed to "
2898 "start file recording");
2899 _outputFileRecorderPtr->StopRecording();
2900 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2901 _outputFileRecorderPtr = NULL;
2902 return -1;
2903 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002904
niklase@google.com470e71d2011-07-07 08:21:25 +00002905 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2906 _outputFileRecording = true;
2907
2908 return 0;
2909}
2910
2911int Channel::StopRecordingPlayout()
2912{
2913 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2914 "Channel::StopRecordingPlayout()");
2915
2916 if (!_outputFileRecording)
2917 {
2918 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2919 "StopRecordingPlayout() isnot recording");
2920 return -1;
2921 }
2922
2923
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002924 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002925
2926 if (_outputFileRecorderPtr->StopRecording() != 0)
2927 {
2928 _engineStatisticsPtr->SetLastError(
2929 VE_STOP_RECORDING_FAILED, kTraceError,
2930 "StopRecording() could not stop recording");
2931 return(-1);
2932 }
2933 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2934 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2935 _outputFileRecorderPtr = NULL;
2936 _outputFileRecording = false;
2937
2938 return 0;
2939}
2940
2941void
2942Channel::SetMixWithMicStatus(bool mix)
2943{
2944 _mixFileWithMicrophone=mix;
2945}
2946
2947int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002948Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002949{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002950 int8_t currentLevel = _outputAudioLevel.Level();
2951 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002952 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2953 VoEId(_instanceId,_channelId),
2954 "GetSpeechOutputLevel() => level=%u", level);
2955 return 0;
2956}
2957
2958int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002959Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002960{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002961 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2962 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002963 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2964 VoEId(_instanceId,_channelId),
2965 "GetSpeechOutputLevelFullRange() => level=%u", level);
2966 return 0;
2967}
2968
2969int
2970Channel::SetMute(bool enable)
2971{
wu@webrtc.org63420662013-10-17 18:28:55 +00002972 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002973 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2974 "Channel::SetMute(enable=%d)", enable);
2975 _mute = enable;
2976 return 0;
2977}
2978
2979bool
2980Channel::Mute() const
2981{
wu@webrtc.org63420662013-10-17 18:28:55 +00002982 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002983 return _mute;
2984}
2985
2986int
2987Channel::SetOutputVolumePan(float left, float right)
2988{
wu@webrtc.org63420662013-10-17 18:28:55 +00002989 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2991 "Channel::SetOutputVolumePan()");
2992 _panLeft = left;
2993 _panRight = right;
2994 return 0;
2995}
2996
2997int
2998Channel::GetOutputVolumePan(float& left, float& right) const
2999{
wu@webrtc.org63420662013-10-17 18:28:55 +00003000 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003001 left = _panLeft;
3002 right = _panRight;
3003 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3004 VoEId(_instanceId,_channelId),
3005 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3006 return 0;
3007}
3008
3009int
3010Channel::SetChannelOutputVolumeScaling(float scaling)
3011{
wu@webrtc.org63420662013-10-17 18:28:55 +00003012 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003013 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3014 "Channel::SetChannelOutputVolumeScaling()");
3015 _outputGain = scaling;
3016 return 0;
3017}
3018
3019int
3020Channel::GetChannelOutputVolumeScaling(float& scaling) const
3021{
wu@webrtc.org63420662013-10-17 18:28:55 +00003022 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003023 scaling = _outputGain;
3024 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3025 VoEId(_instanceId,_channelId),
3026 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3027 return 0;
3028}
3029
niklase@google.com470e71d2011-07-07 08:21:25 +00003030int
3031Channel::RegisterExternalEncryption(Encryption& encryption)
3032{
3033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3034 "Channel::RegisterExternalEncryption()");
3035
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003036 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003037
3038 if (_encryptionPtr)
3039 {
3040 _engineStatisticsPtr->SetLastError(
3041 VE_INVALID_OPERATION, kTraceError,
3042 "RegisterExternalEncryption() encryption already enabled");
3043 return -1;
3044 }
3045
3046 _encryptionPtr = &encryption;
3047
3048 _decrypting = true;
3049 _encrypting = true;
3050
3051 return 0;
3052}
3053
3054int
3055Channel::DeRegisterExternalEncryption()
3056{
3057 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3058 "Channel::DeRegisterExternalEncryption()");
3059
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003060 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003061
3062 if (!_encryptionPtr)
3063 {
3064 _engineStatisticsPtr->SetLastError(
3065 VE_INVALID_OPERATION, kTraceWarning,
3066 "DeRegisterExternalEncryption() encryption already disabled");
3067 return 0;
3068 }
3069
3070 _decrypting = false;
3071 _encrypting = false;
3072
3073 _encryptionPtr = NULL;
3074
3075 return 0;
3076}
3077
3078int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003079 int lengthMs, int attenuationDb,
3080 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003081{
3082 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3083 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3084 playDtmfEvent);
3085
3086 _playOutbandDtmfEvent = playDtmfEvent;
3087
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003088 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003089 attenuationDb) != 0)
3090 {
3091 _engineStatisticsPtr->SetLastError(
3092 VE_SEND_DTMF_FAILED,
3093 kTraceWarning,
3094 "SendTelephoneEventOutband() failed to send event");
3095 return -1;
3096 }
3097 return 0;
3098}
3099
3100int Channel::SendTelephoneEventInband(unsigned char eventCode,
3101 int lengthMs,
3102 int attenuationDb,
3103 bool playDtmfEvent)
3104{
3105 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3106 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3107 playDtmfEvent);
3108
3109 _playInbandDtmfEvent = playDtmfEvent;
3110 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3111
3112 return 0;
3113}
3114
3115int
3116Channel::SetDtmfPlayoutStatus(bool enable)
3117{
3118 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3119 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003120 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003121 {
3122 _engineStatisticsPtr->SetLastError(
3123 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3124 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3125 return -1;
3126 }
3127 return 0;
3128}
3129
3130bool
3131Channel::DtmfPlayoutStatus() const
3132{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003133 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003134}
3135
3136int
3137Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3138{
3139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3140 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003141 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003142 {
3143 _engineStatisticsPtr->SetLastError(
3144 VE_INVALID_ARGUMENT, kTraceError,
3145 "SetSendTelephoneEventPayloadType() invalid type");
3146 return -1;
3147 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003148 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003149 codec.plfreq = 8000;
3150 codec.pltype = type;
3151 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003152 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003153 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003154 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3155 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3156 _engineStatisticsPtr->SetLastError(
3157 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3158 "SetSendTelephoneEventPayloadType() failed to register send"
3159 "payload type");
3160 return -1;
3161 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003162 }
3163 _sendTelephoneEventPayloadType = type;
3164 return 0;
3165}
3166
3167int
3168Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3169{
3170 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3171 "Channel::GetSendTelephoneEventPayloadType()");
3172 type = _sendTelephoneEventPayloadType;
3173 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3174 VoEId(_instanceId,_channelId),
3175 "GetSendTelephoneEventPayloadType() => type=%u", type);
3176 return 0;
3177}
3178
niklase@google.com470e71d2011-07-07 08:21:25 +00003179int
3180Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3181{
3182 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3183 "Channel::UpdateRxVadDetection()");
3184
3185 int vadDecision = 1;
3186
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003187 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003188
3189 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3190 {
3191 OnRxVadDetected(vadDecision);
3192 _oldVadDecision = vadDecision;
3193 }
3194
3195 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3196 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3197 vadDecision);
3198 return 0;
3199}
3200
3201int
3202Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3203{
3204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3205 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003206 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003207
3208 if (_rxVadObserverPtr)
3209 {
3210 _engineStatisticsPtr->SetLastError(
3211 VE_INVALID_OPERATION, kTraceError,
3212 "RegisterRxVadObserver() observer already enabled");
3213 return -1;
3214 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003215 _rxVadObserverPtr = &observer;
3216 _RxVadDetection = true;
3217 return 0;
3218}
3219
3220int
3221Channel::DeRegisterRxVadObserver()
3222{
3223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3224 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003225 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003226
3227 if (!_rxVadObserverPtr)
3228 {
3229 _engineStatisticsPtr->SetLastError(
3230 VE_INVALID_OPERATION, kTraceWarning,
3231 "DeRegisterRxVadObserver() observer already disabled");
3232 return 0;
3233 }
3234 _rxVadObserverPtr = NULL;
3235 _RxVadDetection = false;
3236 return 0;
3237}
3238
3239int
3240Channel::VoiceActivityIndicator(int &activity)
3241{
3242 activity = _sendFrameType;
3243
3244 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003245 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003246 return 0;
3247}
3248
3249#ifdef WEBRTC_VOICE_ENGINE_AGC
3250
3251int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003252Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003253{
3254 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3255 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3256 (int)enable, (int)mode);
3257
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003258 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003259 switch (mode)
3260 {
3261 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003262 break;
3263 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003264 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 break;
3266 case kAgcFixedDigital:
3267 agcMode = GainControl::kFixedDigital;
3268 break;
3269 case kAgcAdaptiveDigital:
3270 agcMode =GainControl::kAdaptiveDigital;
3271 break;
3272 default:
3273 _engineStatisticsPtr->SetLastError(
3274 VE_INVALID_ARGUMENT, kTraceError,
3275 "SetRxAgcStatus() invalid Agc mode");
3276 return -1;
3277 }
3278
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003279 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003280 {
3281 _engineStatisticsPtr->SetLastError(
3282 VE_APM_ERROR, kTraceError,
3283 "SetRxAgcStatus() failed to set Agc mode");
3284 return -1;
3285 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003286 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003287 {
3288 _engineStatisticsPtr->SetLastError(
3289 VE_APM_ERROR, kTraceError,
3290 "SetRxAgcStatus() failed to set Agc state");
3291 return -1;
3292 }
3293
3294 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003295 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3296
3297 return 0;
3298}
3299
3300int
3301Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3302{
3303 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3304 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3305
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003306 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003307 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003308 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003309
3310 enabled = enable;
3311
3312 switch (agcMode)
3313 {
3314 case GainControl::kFixedDigital:
3315 mode = kAgcFixedDigital;
3316 break;
3317 case GainControl::kAdaptiveDigital:
3318 mode = kAgcAdaptiveDigital;
3319 break;
3320 default:
3321 _engineStatisticsPtr->SetLastError(
3322 VE_APM_ERROR, kTraceError,
3323 "GetRxAgcStatus() invalid Agc mode");
3324 return -1;
3325 }
3326
3327 return 0;
3328}
3329
3330int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003331Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003332{
3333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3334 "Channel::SetRxAgcConfig()");
3335
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003336 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003337 config.targetLeveldBOv) != 0)
3338 {
3339 _engineStatisticsPtr->SetLastError(
3340 VE_APM_ERROR, kTraceError,
3341 "SetRxAgcConfig() failed to set target peak |level|"
3342 "(or envelope) of the Agc");
3343 return -1;
3344 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003345 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003346 config.digitalCompressionGaindB) != 0)
3347 {
3348 _engineStatisticsPtr->SetLastError(
3349 VE_APM_ERROR, kTraceError,
3350 "SetRxAgcConfig() failed to set the range in |gain| the"
3351 " digital compression stage may apply");
3352 return -1;
3353 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003354 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003355 config.limiterEnable) != 0)
3356 {
3357 _engineStatisticsPtr->SetLastError(
3358 VE_APM_ERROR, kTraceError,
3359 "SetRxAgcConfig() failed to set hard limiter to the signal");
3360 return -1;
3361 }
3362
3363 return 0;
3364}
3365
3366int
3367Channel::GetRxAgcConfig(AgcConfig& config)
3368{
3369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3370 "Channel::GetRxAgcConfig(config=%?)");
3371
3372 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003373 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003374 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003375 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003376 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003377 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003378
3379 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3380 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3381 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3382 " limiterEnable=%d",
3383 config.targetLeveldBOv,
3384 config.digitalCompressionGaindB,
3385 config.limiterEnable);
3386
3387 return 0;
3388}
3389
3390#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3391
3392#ifdef WEBRTC_VOICE_ENGINE_NR
3393
3394int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003395Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003396{
3397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3398 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3399 (int)enable, (int)mode);
3400
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003401 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003402 switch (mode)
3403 {
3404
3405 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003406 break;
3407 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003408 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003409 break;
3410 case kNsConference:
3411 nsLevel = NoiseSuppression::kHigh;
3412 break;
3413 case kNsLowSuppression:
3414 nsLevel = NoiseSuppression::kLow;
3415 break;
3416 case kNsModerateSuppression:
3417 nsLevel = NoiseSuppression::kModerate;
3418 break;
3419 case kNsHighSuppression:
3420 nsLevel = NoiseSuppression::kHigh;
3421 break;
3422 case kNsVeryHighSuppression:
3423 nsLevel = NoiseSuppression::kVeryHigh;
3424 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003425 }
3426
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003427 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003428 != 0)
3429 {
3430 _engineStatisticsPtr->SetLastError(
3431 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003432 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003433 return -1;
3434 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003435 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003436 {
3437 _engineStatisticsPtr->SetLastError(
3438 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003439 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003440 return -1;
3441 }
3442
3443 _rxNsIsEnabled = enable;
3444 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3445
3446 return 0;
3447}
3448
3449int
3450Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3451{
3452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3453 "Channel::GetRxNsStatus(enable=?, mode=?)");
3454
3455 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003456 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003457 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003458 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003459
3460 enabled = enable;
3461
3462 switch (ncLevel)
3463 {
3464 case NoiseSuppression::kLow:
3465 mode = kNsLowSuppression;
3466 break;
3467 case NoiseSuppression::kModerate:
3468 mode = kNsModerateSuppression;
3469 break;
3470 case NoiseSuppression::kHigh:
3471 mode = kNsHighSuppression;
3472 break;
3473 case NoiseSuppression::kVeryHigh:
3474 mode = kNsVeryHighSuppression;
3475 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003476 }
3477
3478 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3479 VoEId(_instanceId,_channelId),
3480 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3481 return 0;
3482}
3483
3484#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3485
3486int
3487Channel::RegisterRTPObserver(VoERTPObserver& observer)
3488{
3489 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3490 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003491 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003492
3493 if (_rtpObserverPtr)
3494 {
3495 _engineStatisticsPtr->SetLastError(
3496 VE_INVALID_OPERATION, kTraceError,
3497 "RegisterRTPObserver() observer already enabled");
3498 return -1;
3499 }
3500
3501 _rtpObserverPtr = &observer;
3502 _rtpObserver = true;
3503
3504 return 0;
3505}
3506
3507int
3508Channel::DeRegisterRTPObserver()
3509{
3510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3511 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003512 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003513
3514 if (!_rtpObserverPtr)
3515 {
3516 _engineStatisticsPtr->SetLastError(
3517 VE_INVALID_OPERATION, kTraceWarning,
3518 "DeRegisterRTPObserver() observer already disabled");
3519 return 0;
3520 }
3521
3522 _rtpObserver = false;
3523 _rtpObserverPtr = NULL;
3524
3525 return 0;
3526}
3527
3528int
3529Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3530{
3531 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3532 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003533 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003534
3535 if (_rtcpObserverPtr)
3536 {
3537 _engineStatisticsPtr->SetLastError(
3538 VE_INVALID_OPERATION, kTraceError,
3539 "RegisterRTCPObserver() observer already enabled");
3540 return -1;
3541 }
3542
3543 _rtcpObserverPtr = &observer;
3544 _rtcpObserver = true;
3545
3546 return 0;
3547}
3548
3549int
3550Channel::DeRegisterRTCPObserver()
3551{
3552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3553 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003554 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003555
3556 if (!_rtcpObserverPtr)
3557 {
3558 _engineStatisticsPtr->SetLastError(
3559 VE_INVALID_OPERATION, kTraceWarning,
3560 "DeRegisterRTCPObserver() observer already disabled");
3561 return 0;
3562 }
3563
3564 _rtcpObserver = false;
3565 _rtcpObserverPtr = NULL;
3566
3567 return 0;
3568}
3569
3570int
3571Channel::SetLocalSSRC(unsigned int ssrc)
3572{
3573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3574 "Channel::SetLocalSSRC()");
3575 if (_sending)
3576 {
3577 _engineStatisticsPtr->SetLastError(
3578 VE_ALREADY_SENDING, kTraceError,
3579 "SetLocalSSRC() already sending");
3580 return -1;
3581 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003582 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003583 {
3584 _engineStatisticsPtr->SetLastError(
3585 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3586 "SetLocalSSRC() failed to set SSRC");
3587 return -1;
3588 }
3589 return 0;
3590}
3591
3592int
3593Channel::GetLocalSSRC(unsigned int& ssrc)
3594{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003595 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003596 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3597 VoEId(_instanceId,_channelId),
3598 "GetLocalSSRC() => ssrc=%lu", ssrc);
3599 return 0;
3600}
3601
3602int
3603Channel::GetRemoteSSRC(unsigned int& ssrc)
3604{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003605 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003606 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3607 VoEId(_instanceId,_channelId),
3608 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3609 return 0;
3610}
3611
3612int
3613Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3614{
3615 if (arrCSRC == NULL)
3616 {
3617 _engineStatisticsPtr->SetLastError(
3618 VE_INVALID_ARGUMENT, kTraceError,
3619 "GetRemoteCSRCs() invalid array argument");
3620 return -1;
3621 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003622 uint32_t arrOfCSRC[kRtpCsrcSize];
3623 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003624 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003625 if (CSRCs > 0)
3626 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003627 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003628 for (int i = 0; i < (int) CSRCs; i++)
3629 {
3630 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3631 VoEId(_instanceId, _channelId),
3632 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3633 }
3634 } else
3635 {
3636 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3637 VoEId(_instanceId, _channelId),
3638 "GetRemoteCSRCs() => list is empty!");
3639 }
3640 return CSRCs;
3641}
3642
3643int
3644Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3645{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003646 if (rtp_audioproc_.get() == NULL) {
3647 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3648 _channelId)));
3649 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003650
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003651 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3652 AudioProcessing::kNoError) {
3653 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3654 "Failed to enable AudioProcessing::level_estimator()");
3655 return -1;
3656 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003657
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003658 _includeAudioLevelIndication = enable;
3659 if (enable) {
3660 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3661 ID);
3662 } else {
3663 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3664 }
3665 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003666}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003667
niklase@google.com470e71d2011-07-07 08:21:25 +00003668int
3669Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3670{
3671 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3672 VoEId(_instanceId,_channelId),
3673 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3674 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003675 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003676}
3677
3678int
3679Channel::SetRTCPStatus(bool enable)
3680{
3681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3682 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003683 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003684 kRtcpCompound : kRtcpOff) != 0)
3685 {
3686 _engineStatisticsPtr->SetLastError(
3687 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3688 "SetRTCPStatus() failed to set RTCP status");
3689 return -1;
3690 }
3691 return 0;
3692}
3693
3694int
3695Channel::GetRTCPStatus(bool& enabled)
3696{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003697 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003698 enabled = (method != kRtcpOff);
3699 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3700 VoEId(_instanceId,_channelId),
3701 "GetRTCPStatus() => enabled=%d", enabled);
3702 return 0;
3703}
3704
3705int
3706Channel::SetRTCP_CNAME(const char cName[256])
3707{
3708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3709 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003710 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003711 {
3712 _engineStatisticsPtr->SetLastError(
3713 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3714 "SetRTCP_CNAME() failed to set RTCP CNAME");
3715 return -1;
3716 }
3717 return 0;
3718}
3719
3720int
3721Channel::GetRTCP_CNAME(char cName[256])
3722{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003723 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3727 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3728 return -1;
3729 }
3730 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3731 VoEId(_instanceId, _channelId),
3732 "GetRTCP_CNAME() => cName=%s", cName);
3733 return 0;
3734}
3735
3736int
3737Channel::GetRemoteRTCP_CNAME(char cName[256])
3738{
3739 if (cName == NULL)
3740 {
3741 _engineStatisticsPtr->SetLastError(
3742 VE_INVALID_ARGUMENT, kTraceError,
3743 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3744 return -1;
3745 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003746 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003747 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003748 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003749 {
3750 _engineStatisticsPtr->SetLastError(
3751 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3752 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3753 return -1;
3754 }
3755 strcpy(cName, cname);
3756 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3757 VoEId(_instanceId, _channelId),
3758 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3759 return 0;
3760}
3761
3762int
3763Channel::GetRemoteRTCPData(
3764 unsigned int& NTPHigh,
3765 unsigned int& NTPLow,
3766 unsigned int& timestamp,
3767 unsigned int& playoutTimestamp,
3768 unsigned int* jitter,
3769 unsigned short* fractionLost)
3770{
3771 // --- Information from sender info in received Sender Reports
3772
3773 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003774 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003775 {
3776 _engineStatisticsPtr->SetLastError(
3777 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003778 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003779 "side");
3780 return -1;
3781 }
3782
3783 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3784 // and octet count)
3785 NTPHigh = senderInfo.NTPseconds;
3786 NTPLow = senderInfo.NTPfraction;
3787 timestamp = senderInfo.RTPtimeStamp;
3788
3789 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3790 VoEId(_instanceId, _channelId),
3791 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3792 "timestamp=%lu",
3793 NTPHigh, NTPLow, timestamp);
3794
3795 // --- Locally derived information
3796
3797 // This value is updated on each incoming RTCP packet (0 when no packet
3798 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003799 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003800
3801 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3802 VoEId(_instanceId, _channelId),
3803 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003804 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003805
3806 if (NULL != jitter || NULL != fractionLost)
3807 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003808 // Get all RTCP receiver report blocks that have been received on this
3809 // channel. If we receive RTP packets from a remote source we know the
3810 // remote SSRC and use the report block from him.
3811 // Otherwise use the first report block.
3812 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003813 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003814 remote_stats.empty()) {
3815 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3816 VoEId(_instanceId, _channelId),
3817 "GetRemoteRTCPData() failed to measure statistics due"
3818 " to lack of received RTP and/or RTCP packets");
3819 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003820 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003821
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003822 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003823 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3824 for (; it != remote_stats.end(); ++it) {
3825 if (it->remoteSSRC == remoteSSRC)
3826 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003827 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003828
3829 if (it == remote_stats.end()) {
3830 // If we have not received any RTCP packets from this SSRC it probably
3831 // means that we have not received any RTP packets.
3832 // Use the first received report block instead.
3833 it = remote_stats.begin();
3834 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003835 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003836
xians@webrtc.org79af7342012-01-31 12:22:14 +00003837 if (jitter) {
3838 *jitter = it->jitter;
3839 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3840 VoEId(_instanceId, _channelId),
3841 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3842 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003843
xians@webrtc.org79af7342012-01-31 12:22:14 +00003844 if (fractionLost) {
3845 *fractionLost = it->fractionLost;
3846 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3847 VoEId(_instanceId, _channelId),
3848 "GetRemoteRTCPData() => fractionLost = %lu",
3849 *fractionLost);
3850 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003851 }
3852 return 0;
3853}
3854
3855int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003856Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003857 unsigned int name,
3858 const char* data,
3859 unsigned short dataLengthInBytes)
3860{
3861 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3862 "Channel::SendApplicationDefinedRTCPPacket()");
3863 if (!_sending)
3864 {
3865 _engineStatisticsPtr->SetLastError(
3866 VE_NOT_SENDING, kTraceError,
3867 "SendApplicationDefinedRTCPPacket() not sending");
3868 return -1;
3869 }
3870 if (NULL == data)
3871 {
3872 _engineStatisticsPtr->SetLastError(
3873 VE_INVALID_ARGUMENT, kTraceError,
3874 "SendApplicationDefinedRTCPPacket() invalid data value");
3875 return -1;
3876 }
3877 if (dataLengthInBytes % 4 != 0)
3878 {
3879 _engineStatisticsPtr->SetLastError(
3880 VE_INVALID_ARGUMENT, kTraceError,
3881 "SendApplicationDefinedRTCPPacket() invalid length value");
3882 return -1;
3883 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003884 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003885 if (status == kRtcpOff)
3886 {
3887 _engineStatisticsPtr->SetLastError(
3888 VE_RTCP_ERROR, kTraceError,
3889 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3890 return -1;
3891 }
3892
3893 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003894 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003895 subType,
3896 name,
3897 (const unsigned char*) data,
3898 dataLengthInBytes) != 0)
3899 {
3900 _engineStatisticsPtr->SetLastError(
3901 VE_SEND_ERROR, kTraceError,
3902 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3903 return -1;
3904 }
3905 return 0;
3906}
3907
3908int
3909Channel::GetRTPStatistics(
3910 unsigned int& averageJitterMs,
3911 unsigned int& maxJitterMs,
3912 unsigned int& discardedPackets)
3913{
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 // The jitter statistics is updated for each received RTP packet and is
3915 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003916 StreamStatistician::Statistics statistics;
3917 StreamStatistician* statistician =
3918 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3919 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003920 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3921 _engineStatisticsPtr->SetLastError(
3922 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3923 "GetRTPStatistics() failed to read RTP statistics from the "
3924 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003925 }
3926
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003927 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003928 if (playoutFrequency > 0)
3929 {
3930 // Scale RTP statistics given the current playout frequency
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003931 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3932 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003933 }
3934
3935 discardedPackets = _numberOfDiscardedPackets;
3936
3937 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3938 VoEId(_instanceId, _channelId),
3939 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003940 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003941 averageJitterMs, maxJitterMs, discardedPackets);
3942 return 0;
3943}
3944
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003945int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3946 if (sender_info == NULL) {
3947 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3948 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3949 return -1;
3950 }
3951
3952 // Get the sender info from the latest received RTCP Sender Report.
3953 RTCPSenderInfo rtcp_sender_info;
3954 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3955 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3956 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3957 return -1;
3958 }
3959
3960 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3961 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3962 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3963 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3964 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3965 return 0;
3966}
3967
3968int Channel::GetRemoteRTCPReportBlocks(
3969 std::vector<ReportBlock>* report_blocks) {
3970 if (report_blocks == NULL) {
3971 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3972 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3973 return -1;
3974 }
3975
3976 // Get the report blocks from the latest received RTCP Sender or Receiver
3977 // Report. Each element in the vector contains the sender's SSRC and a
3978 // report block according to RFC 3550.
3979 std::vector<RTCPReportBlock> rtcp_report_blocks;
3980 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3981 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3982 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3983 return -1;
3984 }
3985
3986 if (rtcp_report_blocks.empty())
3987 return 0;
3988
3989 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3990 for (; it != rtcp_report_blocks.end(); ++it) {
3991 ReportBlock report_block;
3992 report_block.sender_SSRC = it->remoteSSRC;
3993 report_block.source_SSRC = it->sourceSSRC;
3994 report_block.fraction_lost = it->fractionLost;
3995 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3996 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3997 report_block.interarrival_jitter = it->jitter;
3998 report_block.last_SR_timestamp = it->lastSR;
3999 report_block.delay_since_last_SR = it->delaySinceLastSR;
4000 report_blocks->push_back(report_block);
4001 }
4002 return 0;
4003}
4004
niklase@google.com470e71d2011-07-07 08:21:25 +00004005int
4006Channel::GetRTPStatistics(CallStatistics& stats)
4007{
niklase@google.com470e71d2011-07-07 08:21:25 +00004008 // --- Part one of the final structure (four values)
4009
4010 // The jitter statistics is updated for each received RTP packet and is
4011 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004012 StreamStatistician::Statistics statistics;
4013 StreamStatistician* statistician =
4014 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
4015 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004016 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4017 _engineStatisticsPtr->SetLastError(
4018 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4019 "GetRTPStatistics() failed to read RTP statistics from the "
4020 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004021 }
4022
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004023 stats.fractionLost = statistics.fraction_lost;
4024 stats.cumulativeLost = statistics.cumulative_lost;
4025 stats.extendedMax = statistics.extended_max_sequence_number;
4026 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004027
4028 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4029 VoEId(_instanceId, _channelId),
4030 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004031 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004032 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4033 stats.jitterSamples);
4034
4035 // --- Part two of the final structure (one value)
4036
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004037 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004038 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004039 if (method == kRtcpOff)
4040 {
4041 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4042 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004043 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004044 "measurements cannot be retrieved");
4045 } else
4046 {
4047 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004048 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004049 if (remoteSSRC > 0)
4050 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004051 uint16_t avgRTT(0);
4052 uint16_t maxRTT(0);
4053 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004054
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004055 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004056 != 0)
4057 {
4058 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4059 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004060 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004061 "the RTP/RTCP module");
4062 }
4063 } else
4064 {
4065 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4066 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004067 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004068 "RTP packets have been received yet");
4069 }
4070 }
4071
4072 stats.rttMs = static_cast<int> (RTT);
4073
4074 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4075 VoEId(_instanceId, _channelId),
4076 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4077
4078 // --- Part three of the final structure (four values)
4079
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004080 uint32_t bytesSent(0);
4081 uint32_t packetsSent(0);
4082 uint32_t bytesReceived(0);
4083 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004084
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004085 if (statistician) {
4086 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4087 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004088
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004089 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004090 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004091 {
4092 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4093 VoEId(_instanceId, _channelId),
4094 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004095 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004096 }
4097
4098 stats.bytesSent = bytesSent;
4099 stats.packetsSent = packetsSent;
4100 stats.bytesReceived = bytesReceived;
4101 stats.packetsReceived = packetsReceived;
4102
4103 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4104 VoEId(_instanceId, _channelId),
4105 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004106 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004107 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4108 stats.packetsReceived);
4109
4110 return 0;
4111}
4112
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004113int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4114 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4115 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004116
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004117 if (enable) {
4118 if (redPayloadtype < 0 || redPayloadtype > 127) {
4119 _engineStatisticsPtr->SetLastError(
4120 VE_PLTYPE_ERROR, kTraceError,
4121 "SetFECStatus() invalid RED payload type");
4122 return -1;
4123 }
4124
4125 if (SetRedPayloadType(redPayloadtype) < 0) {
4126 _engineStatisticsPtr->SetLastError(
4127 VE_CODEC_ERROR, kTraceError,
4128 "SetSecondarySendCodec() Failed to register RED ACM");
4129 return -1;
4130 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004131 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004132
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004133 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004134 _engineStatisticsPtr->SetLastError(
4135 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4136 "SetFECStatus() failed to set FEC state in the ACM");
4137 return -1;
4138 }
4139 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004140}
4141
4142int
4143Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4144{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004145 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004146 if (enabled)
4147 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004148 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004149 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004150 {
4151 _engineStatisticsPtr->SetLastError(
4152 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4153 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4154 "module");
4155 return -1;
4156 }
4157 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4158 VoEId(_instanceId, _channelId),
4159 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4160 enabled, redPayloadtype);
4161 return 0;
4162 }
4163 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4164 VoEId(_instanceId, _channelId),
4165 "GetFECStatus() => enabled=%d", enabled);
4166 return 0;
4167}
4168
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004169void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4170 // None of these functions can fail.
4171 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004172 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4173 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004174 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004175 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004176 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004177 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004178}
4179
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004180// Called when we are missing one or more packets.
4181int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004182 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4183}
4184
niklase@google.com470e71d2011-07-07 08:21:25 +00004185int
niklase@google.com470e71d2011-07-07 08:21:25 +00004186Channel::StartRTPDump(const char fileNameUTF8[1024],
4187 RTPDirections direction)
4188{
4189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4190 "Channel::StartRTPDump()");
4191 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4192 {
4193 _engineStatisticsPtr->SetLastError(
4194 VE_INVALID_ARGUMENT, kTraceError,
4195 "StartRTPDump() invalid RTP direction");
4196 return -1;
4197 }
4198 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4199 &_rtpDumpIn : &_rtpDumpOut;
4200 if (rtpDumpPtr == NULL)
4201 {
4202 assert(false);
4203 return -1;
4204 }
4205 if (rtpDumpPtr->IsActive())
4206 {
4207 rtpDumpPtr->Stop();
4208 }
4209 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4210 {
4211 _engineStatisticsPtr->SetLastError(
4212 VE_BAD_FILE, kTraceError,
4213 "StartRTPDump() failed to create file");
4214 return -1;
4215 }
4216 return 0;
4217}
4218
4219int
4220Channel::StopRTPDump(RTPDirections direction)
4221{
4222 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4223 "Channel::StopRTPDump()");
4224 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4225 {
4226 _engineStatisticsPtr->SetLastError(
4227 VE_INVALID_ARGUMENT, kTraceError,
4228 "StopRTPDump() invalid RTP direction");
4229 return -1;
4230 }
4231 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4232 &_rtpDumpIn : &_rtpDumpOut;
4233 if (rtpDumpPtr == NULL)
4234 {
4235 assert(false);
4236 return -1;
4237 }
4238 if (!rtpDumpPtr->IsActive())
4239 {
4240 return 0;
4241 }
4242 return rtpDumpPtr->Stop();
4243}
4244
4245bool
4246Channel::RTPDumpIsActive(RTPDirections direction)
4247{
4248 if ((direction != kRtpIncoming) &&
4249 (direction != kRtpOutgoing))
4250 {
4251 _engineStatisticsPtr->SetLastError(
4252 VE_INVALID_ARGUMENT, kTraceError,
4253 "RTPDumpIsActive() invalid RTP direction");
4254 return false;
4255 }
4256 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4257 &_rtpDumpIn : &_rtpDumpOut;
4258 return rtpDumpPtr->IsActive();
4259}
4260
4261int
4262Channel::InsertExtraRTPPacket(unsigned char payloadType,
4263 bool markerBit,
4264 const char* payloadData,
4265 unsigned short payloadSize)
4266{
4267 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4268 "Channel::InsertExtraRTPPacket()");
4269 if (payloadType > 127)
4270 {
4271 _engineStatisticsPtr->SetLastError(
4272 VE_INVALID_PLTYPE, kTraceError,
4273 "InsertExtraRTPPacket() invalid payload type");
4274 return -1;
4275 }
4276 if (payloadData == NULL)
4277 {
4278 _engineStatisticsPtr->SetLastError(
4279 VE_INVALID_ARGUMENT, kTraceError,
4280 "InsertExtraRTPPacket() invalid payload data");
4281 return -1;
4282 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004283 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004284 {
4285 _engineStatisticsPtr->SetLastError(
4286 VE_INVALID_ARGUMENT, kTraceError,
4287 "InsertExtraRTPPacket() invalid payload size");
4288 return -1;
4289 }
4290 if (!_sending)
4291 {
4292 _engineStatisticsPtr->SetLastError(
4293 VE_NOT_SENDING, kTraceError,
4294 "InsertExtraRTPPacket() not sending");
4295 return -1;
4296 }
4297
4298 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4299 // Transport::SendPacket() will be called by the module when the RTP packet
4300 // is created.
4301 // The call to SendOutgoingData() does *not* modify the timestamp and
4302 // payloadtype to ensure that the RTP module generates a valid RTP packet
4303 // (user might utilize a non-registered payload type).
4304 // The marker bit and payload type will be replaced just before the actual
4305 // transmission, i.e., the actual modification is done *after* the RTP
4306 // module has delivered its RTP packet back to the VoE.
4307 // We will use the stored values above when the packet is modified
4308 // (see Channel::SendPacket()).
4309
4310 _extraPayloadType = payloadType;
4311 _extraMarkerBit = markerBit;
4312 _insertExtraRTPPacket = true;
4313
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004314 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004315 _lastPayloadType,
4316 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004317 // Leaving the time when this frame was
4318 // received from the capture device as
4319 // undefined for voice for now.
4320 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004321 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004322 payloadSize) != 0)
4323 {
4324 _engineStatisticsPtr->SetLastError(
4325 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4326 "InsertExtraRTPPacket() failed to send extra RTP packet");
4327 return -1;
4328 }
4329
4330 return 0;
4331}
4332
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004333uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004334Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004335{
4336 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004337 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004338 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004339 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004340 return 0;
4341}
4342
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004343// TODO(xians): This method borrows quite some code from
4344// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4345// code duplication.
4346void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004347 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004348 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004349 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004350 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4351 static const int kMaxNumberOfFrames = 960;
4352 assert(number_of_frames <= kMaxNumberOfFrames);
4353
4354 // Get the send codec information for doing resampling or downmixing later on.
4355 CodecInst codec;
4356 GetSendCodec(codec);
4357 assert(codec.channels == 1 || codec.channels == 2);
4358 int support_sample_rate = std::min(32000,
4359 std::min(sample_rate, codec.plfreq));
4360
4361 // Downmix the data to mono if needed.
4362 const int16_t* audio_ptr = audio_data;
4363 if (number_of_channels == 2 && codec.channels == 1) {
4364 if (!mono_recording_audio_.get())
4365 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4366
4367 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4368 mono_recording_audio_.get());
4369 audio_ptr = mono_recording_audio_.get();
4370 }
4371
4372 // Resample the data to the sample rate that the codec is using.
4373 if (input_resampler_.InitializeIfNeeded(sample_rate,
4374 support_sample_rate,
4375 codec.channels)) {
4376 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4377 "Channel::Demultiplex() unable to resample");
4378 return;
4379 }
4380
4381 int out_length = input_resampler_.Resample(audio_ptr,
4382 number_of_frames * codec.channels,
4383 _audioFrame.data_,
4384 AudioFrame::kMaxDataSizeSamples);
4385 if (out_length == -1) {
4386 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4387 "Channel::Demultiplex() resampling failed");
4388 return;
4389 }
4390
4391 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4392 _audioFrame.timestamp_ = -1;
4393 _audioFrame.sample_rate_hz_ = support_sample_rate;
4394 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4395 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4396 _audioFrame.num_channels_ = codec.channels;
4397 _audioFrame.id_ = _channelId;
4398}
4399
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004400uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004401Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004402{
4403 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4404 "Channel::PrepareEncodeAndSend()");
4405
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004406 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004407 {
4408 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4409 "Channel::PrepareEncodeAndSend() invalid audio frame");
4410 return -1;
4411 }
4412
4413 if (_inputFilePlaying)
4414 {
4415 MixOrReplaceAudioWithFile(mixingFrequency);
4416 }
4417
wu@webrtc.org63420662013-10-17 18:28:55 +00004418 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004419 {
4420 AudioFrameOperations::Mute(_audioFrame);
4421 }
4422
4423 if (_inputExternalMedia)
4424 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004425 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004426 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004427 if (_inputExternalMediaCallbackPtr)
4428 {
4429 _inputExternalMediaCallbackPtr->Process(
4430 _channelId,
4431 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004432 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004433 _audioFrame.samples_per_channel_,
4434 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004435 isStereo);
4436 }
4437 }
4438
4439 InsertInbandDtmfTone();
4440
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004441 if (_includeAudioLevelIndication)
4442 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004443 if (rtp_audioproc_->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4444 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004445 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004446 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4447 VoEId(_instanceId, _channelId),
4448 "Error setting AudioProcessing sample rate");
4449 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004450 }
4451
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004452 if (rtp_audioproc_->set_num_channels(_audioFrame.num_channels_,
4453 _audioFrame.num_channels_) !=
4454 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004455 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004456 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4457 VoEId(_instanceId, _channelId),
4458 "Error setting AudioProcessing channels");
4459 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004460 }
4461
4462 // Performs level analysis only; does not affect the signal.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004463 rtp_audioproc_->ProcessStream(&_audioFrame);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004464 }
4465
niklase@google.com470e71d2011-07-07 08:21:25 +00004466 return 0;
4467}
4468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004469uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004470Channel::EncodeAndSend()
4471{
4472 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4473 "Channel::EncodeAndSend()");
4474
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004475 assert(_audioFrame.num_channels_ <= 2);
4476 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004477 {
4478 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4479 "Channel::EncodeAndSend() invalid audio frame");
4480 return -1;
4481 }
4482
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004483 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004484
4485 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4486
4487 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004488 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004489 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004490 {
4491 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4492 "Channel::EncodeAndSend() ACM encoding failed");
4493 return -1;
4494 }
4495
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004496 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004497
4498 // --- Encode if complete frame is ready
4499
4500 // This call will trigger AudioPacketizationCallback::SendData if encoding
4501 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004502 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004503}
4504
4505int Channel::RegisterExternalMediaProcessing(
4506 ProcessingTypes type,
4507 VoEMediaProcess& processObject)
4508{
4509 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4510 "Channel::RegisterExternalMediaProcessing()");
4511
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004512 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004513
4514 if (kPlaybackPerChannel == type)
4515 {
4516 if (_outputExternalMediaCallbackPtr)
4517 {
4518 _engineStatisticsPtr->SetLastError(
4519 VE_INVALID_OPERATION, kTraceError,
4520 "Channel::RegisterExternalMediaProcessing() "
4521 "output external media already enabled");
4522 return -1;
4523 }
4524 _outputExternalMediaCallbackPtr = &processObject;
4525 _outputExternalMedia = true;
4526 }
4527 else if (kRecordingPerChannel == type)
4528 {
4529 if (_inputExternalMediaCallbackPtr)
4530 {
4531 _engineStatisticsPtr->SetLastError(
4532 VE_INVALID_OPERATION, kTraceError,
4533 "Channel::RegisterExternalMediaProcessing() "
4534 "output external media already enabled");
4535 return -1;
4536 }
4537 _inputExternalMediaCallbackPtr = &processObject;
4538 _inputExternalMedia = true;
4539 }
4540 return 0;
4541}
4542
4543int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4544{
4545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4546 "Channel::DeRegisterExternalMediaProcessing()");
4547
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004548 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004549
4550 if (kPlaybackPerChannel == type)
4551 {
4552 if (!_outputExternalMediaCallbackPtr)
4553 {
4554 _engineStatisticsPtr->SetLastError(
4555 VE_INVALID_OPERATION, kTraceWarning,
4556 "Channel::DeRegisterExternalMediaProcessing() "
4557 "output external media already disabled");
4558 return 0;
4559 }
4560 _outputExternalMedia = false;
4561 _outputExternalMediaCallbackPtr = NULL;
4562 }
4563 else if (kRecordingPerChannel == type)
4564 {
4565 if (!_inputExternalMediaCallbackPtr)
4566 {
4567 _engineStatisticsPtr->SetLastError(
4568 VE_INVALID_OPERATION, kTraceWarning,
4569 "Channel::DeRegisterExternalMediaProcessing() "
4570 "input external media already disabled");
4571 return 0;
4572 }
4573 _inputExternalMedia = false;
4574 _inputExternalMediaCallbackPtr = NULL;
4575 }
4576
4577 return 0;
4578}
4579
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004580int Channel::SetExternalMixing(bool enabled) {
4581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4582 "Channel::SetExternalMixing(enabled=%d)", enabled);
4583
4584 if (_playing)
4585 {
4586 _engineStatisticsPtr->SetLastError(
4587 VE_INVALID_OPERATION, kTraceError,
4588 "Channel::SetExternalMixing() "
4589 "external mixing cannot be changed while playing.");
4590 return -1;
4591 }
4592
4593 _externalMixing = enabled;
4594
4595 return 0;
4596}
4597
niklase@google.com470e71d2011-07-07 08:21:25 +00004598int
4599Channel::ResetRTCPStatistics()
4600{
4601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4602 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004603 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004604 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004605 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004606}
4607
4608int
4609Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4610{
4611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4612 "Channel::GetRoundTripTimeSummary()");
4613 // Override default module outputs for the case when RTCP is disabled.
4614 // This is done to ensure that we are backward compatible with the
4615 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004616 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004617 {
4618 delaysMs.min = -1;
4619 delaysMs.max = -1;
4620 delaysMs.average = -1;
4621 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4622 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4623 " valid RTT measurements cannot be retrieved");
4624 return 0;
4625 }
4626
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004627 uint32_t remoteSSRC;
4628 uint16_t RTT;
4629 uint16_t avgRTT;
4630 uint16_t maxRTT;
4631 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004632 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004633 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004634 if (remoteSSRC == 0)
4635 {
4636 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4637 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4638 " since no RTP packet has been received yet");
4639 }
4640
4641 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4642 // channel and SSRC. The SSRC is required to parse out the correct source
4643 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004644 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004645 {
4646 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4647 "GetRoundTripTimeSummary unable to retrieve RTT values"
4648 " from the RTCP layer");
4649 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4650 }
4651 else
4652 {
4653 delaysMs.min = minRTT;
4654 delaysMs.max = maxRTT;
4655 delaysMs.average = avgRTT;
4656 }
4657 return 0;
4658}
4659
4660int
4661Channel::GetNetworkStatistics(NetworkStatistics& stats)
4662{
4663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4664 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004665 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004666 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004667 if (return_value >= 0) {
4668 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4669 }
4670 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004671}
4672
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004673bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4674 int* playout_buffer_delay_ms) const {
4675 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004676 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004677 "Channel::GetDelayEstimate() no valid estimate.");
4678 return false;
4679 }
4680 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4681 _recPacketDelayMs;
4682 *playout_buffer_delay_ms = playout_delay_ms_;
4683 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4684 "Channel::GetDelayEstimate()");
4685 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004686}
4687
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004688int Channel::SetInitialPlayoutDelay(int delay_ms)
4689{
4690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4691 "Channel::SetInitialPlayoutDelay()");
4692 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4693 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4694 {
4695 _engineStatisticsPtr->SetLastError(
4696 VE_INVALID_ARGUMENT, kTraceError,
4697 "SetInitialPlayoutDelay() invalid min delay");
4698 return -1;
4699 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004700 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004701 {
4702 _engineStatisticsPtr->SetLastError(
4703 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4704 "SetInitialPlayoutDelay() failed to set min playout delay");
4705 return -1;
4706 }
4707 return 0;
4708}
4709
4710
niklase@google.com470e71d2011-07-07 08:21:25 +00004711int
4712Channel::SetMinimumPlayoutDelay(int delayMs)
4713{
4714 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4715 "Channel::SetMinimumPlayoutDelay()");
4716 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4717 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4718 {
4719 _engineStatisticsPtr->SetLastError(
4720 VE_INVALID_ARGUMENT, kTraceError,
4721 "SetMinimumPlayoutDelay() invalid min delay");
4722 return -1;
4723 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004724 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004725 {
4726 _engineStatisticsPtr->SetLastError(
4727 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4728 "SetMinimumPlayoutDelay() failed to set min playout delay");
4729 return -1;
4730 }
4731 return 0;
4732}
4733
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004734void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4735 uint32_t playout_timestamp = 0;
4736
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004737 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004738 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4739 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4740 " timestamp from the ACM");
4741 _engineStatisticsPtr->SetLastError(
4742 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4743 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4744 return;
4745 }
4746
4747 uint16_t delay_ms = 0;
4748 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4749 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4750 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4751 " delay from the ADM");
4752 _engineStatisticsPtr->SetLastError(
4753 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4754 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4755 return;
4756 }
4757
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004758 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004759 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004760 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004761 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4762 playout_frequency = 8000;
4763 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4764 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004765 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004766 }
4767
4768 // Remove the playout delay.
4769 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4770
4771 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4772 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4773 playout_timestamp);
4774
4775 if (rtcp) {
4776 playout_timestamp_rtcp_ = playout_timestamp;
4777 } else {
4778 playout_timestamp_rtp_ = playout_timestamp;
4779 }
4780 playout_delay_ms_ = delay_ms;
4781}
4782
4783int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4784 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4785 "Channel::GetPlayoutTimestamp()");
4786 if (playout_timestamp_rtp_ == 0) {
4787 _engineStatisticsPtr->SetLastError(
4788 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4789 "GetPlayoutTimestamp() failed to retrieve timestamp");
4790 return -1;
4791 }
4792 timestamp = playout_timestamp_rtp_;
4793 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4794 VoEId(_instanceId,_channelId),
4795 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4796 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004797}
4798
4799int
4800Channel::SetInitTimestamp(unsigned int timestamp)
4801{
4802 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4803 "Channel::SetInitTimestamp()");
4804 if (_sending)
4805 {
4806 _engineStatisticsPtr->SetLastError(
4807 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4808 return -1;
4809 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004810 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004811 {
4812 _engineStatisticsPtr->SetLastError(
4813 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4814 "SetInitTimestamp() failed to set timestamp");
4815 return -1;
4816 }
4817 return 0;
4818}
4819
4820int
4821Channel::SetInitSequenceNumber(short sequenceNumber)
4822{
4823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4824 "Channel::SetInitSequenceNumber()");
4825 if (_sending)
4826 {
4827 _engineStatisticsPtr->SetLastError(
4828 VE_SENDING, kTraceError,
4829 "SetInitSequenceNumber() already sending");
4830 return -1;
4831 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004832 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004833 {
4834 _engineStatisticsPtr->SetLastError(
4835 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4836 "SetInitSequenceNumber() failed to set sequence number");
4837 return -1;
4838 }
4839 return 0;
4840}
4841
4842int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004843Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004844{
4845 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4846 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004847 *rtpRtcpModule = _rtpRtcpModule.get();
4848 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004849 return 0;
4850}
4851
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004852// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4853// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004854int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004855Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004856{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004857 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004858 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004859
4860 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004861 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004862
4863 if (_inputFilePlayerPtr == NULL)
4864 {
4865 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4866 VoEId(_instanceId, _channelId),
4867 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4868 " doesnt exist");
4869 return -1;
4870 }
4871
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004872 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004873 fileSamples,
4874 mixingFrequency) == -1)
4875 {
4876 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4877 VoEId(_instanceId, _channelId),
4878 "Channel::MixOrReplaceAudioWithFile() file mixing "
4879 "failed");
4880 return -1;
4881 }
4882 if (fileSamples == 0)
4883 {
4884 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4885 VoEId(_instanceId, _channelId),
4886 "Channel::MixOrReplaceAudioWithFile() file is ended");
4887 return 0;
4888 }
4889 }
4890
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004891 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004892
4893 if (_mixFileWithMicrophone)
4894 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004895 // Currently file stream is always mono.
4896 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004897 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004898 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004899 fileBuffer.get(),
4900 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004901 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004902 }
4903 else
4904 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004905 // Replace ACM audio with file.
4906 // Currently file stream is always mono.
4907 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004908 _audioFrame.UpdateFrame(_channelId,
4909 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004910 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004911 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004912 mixingFrequency,
4913 AudioFrame::kNormalSpeech,
4914 AudioFrame::kVadUnknown,
4915 1);
4916
4917 }
4918 return 0;
4919}
4920
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004921int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004922Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004923 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004924{
4925 assert(mixingFrequency <= 32000);
4926
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004927 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004928 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004929
4930 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004931 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004932
4933 if (_outputFilePlayerPtr == NULL)
4934 {
4935 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4936 VoEId(_instanceId, _channelId),
4937 "Channel::MixAudioWithFile() file mixing failed");
4938 return -1;
4939 }
4940
4941 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004942 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004943 fileSamples,
4944 mixingFrequency) == -1)
4945 {
4946 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4947 VoEId(_instanceId, _channelId),
4948 "Channel::MixAudioWithFile() file mixing failed");
4949 return -1;
4950 }
4951 }
4952
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004953 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004954 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004955 // Currently file stream is always mono.
4956 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004957 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004958 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004959 fileBuffer.get(),
4960 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004961 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004962 }
4963 else
4964 {
4965 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004966 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004967 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004968 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004969 return -1;
4970 }
4971
4972 return 0;
4973}
4974
4975int
4976Channel::InsertInbandDtmfTone()
4977{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004978 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004979 if (_inbandDtmfQueue.PendingDtmf() &&
4980 !_inbandDtmfGenerator.IsAddingTone() &&
4981 _inbandDtmfGenerator.DelaySinceLastTone() >
4982 kMinTelephoneEventSeparationMs)
4983 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004984 int8_t eventCode(0);
4985 uint16_t lengthMs(0);
4986 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004987
4988 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4989 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4990 if (_playInbandDtmfEvent)
4991 {
4992 // Add tone to output mixer using a reduced length to minimize
4993 // risk of echo.
4994 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4995 attenuationDb);
4996 }
4997 }
4998
4999 if (_inbandDtmfGenerator.IsAddingTone())
5000 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005001 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005002 _inbandDtmfGenerator.GetSampleRate(frequency);
5003
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005004 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005005 {
5006 // Update sample rate of Dtmf tone since the mixing frequency
5007 // has changed.
5008 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005009 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005010 // Reset the tone to be added taking the new sample rate into
5011 // account.
5012 _inbandDtmfGenerator.ResetTone();
5013 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005014
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005015 int16_t toneBuffer[320];
5016 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005017 // Get 10ms tone segment and set time since last tone to zero
5018 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5019 {
5020 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5021 VoEId(_instanceId, _channelId),
5022 "Channel::EncodeAndSend() inserting Dtmf failed");
5023 return -1;
5024 }
5025
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005026 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005027 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005028 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005029 sample++)
5030 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005031 for (int channel = 0;
5032 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005033 channel++)
5034 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005035 const int index = sample * _audioFrame.num_channels_ + channel;
5036 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005037 }
5038 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005039
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005040 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005041 } else
5042 {
5043 // Add 10ms to "delay-since-last-tone" counter
5044 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5045 }
5046 return 0;
5047}
5048
niklase@google.com470e71d2011-07-07 08:21:25 +00005049void
5050Channel::ResetDeadOrAliveCounters()
5051{
5052 _countDeadDetections = 0;
5053 _countAliveDetections = 0;
5054}
5055
5056void
5057Channel::UpdateDeadOrAliveCounters(bool alive)
5058{
5059 if (alive)
5060 _countAliveDetections++;
5061 else
5062 _countDeadDetections++;
5063}
5064
5065int
5066Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5067{
niklase@google.com470e71d2011-07-07 08:21:25 +00005068 return 0;
5069}
5070
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005071int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005072Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5073{
5074 if (_transportPtr == NULL)
5075 {
5076 return -1;
5077 }
5078 if (!RTCP)
5079 {
5080 return _transportPtr->SendPacket(_channelId, data, len);
5081 }
5082 else
5083 {
5084 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5085 }
5086}
5087
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005088// Called for incoming RTP packets after successful RTP header parsing.
5089void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5090 uint16_t sequence_number) {
5091 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5092 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5093 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005094
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005095 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005096 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005097
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005098 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005099 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005100 return;
5101 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005102
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005103 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005104 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005105
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005106 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5107 // Even though the actual sampling rate for G.722 audio is
5108 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5109 // 8,000 Hz because that value was erroneously assigned in
5110 // RFC 1890 and must remain unchanged for backward compatibility.
5111 rtp_receive_frequency = 8000;
5112 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5113 // We are resampling Opus internally to 32,000 Hz until all our
5114 // DSP routines can operate at 48,000 Hz, but the RTP clock
5115 // rate for the Opus payload format is standardized to 48,000 Hz,
5116 // because that is the maximum supported decoding sampling rate.
5117 rtp_receive_frequency = 48000;
5118 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005119
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005120 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5121 // packet.
5122 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5123 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005124
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005125 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5126 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005127
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005128 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005129
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005130 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5131 timestamp_diff_ms = 0;
5132 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005133
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005134 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005135
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005136 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5137 _recPacketDelayMs = packet_delay_ms;
5138 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005139
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005140 if (_average_jitter_buffer_delay_us == 0) {
5141 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5142 return;
5143 }
5144
5145 // Filter average delay value using exponential filter (alpha is
5146 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5147 // risk of rounding error) and compensate for it in GetDelayEstimate()
5148 // later.
5149 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5150 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005151}
5152
5153void
5154Channel::RegisterReceiveCodecsToRTPModule()
5155{
5156 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5157 "Channel::RegisterReceiveCodecsToRTPModule()");
5158
5159
5160 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005161 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005162
5163 for (int idx = 0; idx < nSupportedCodecs; idx++)
5164 {
5165 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005166 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005167 (rtp_receiver_->RegisterReceivePayload(
5168 codec.plname,
5169 codec.pltype,
5170 codec.plfreq,
5171 codec.channels,
5172 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005173 {
5174 WEBRTC_TRACE(
5175 kTraceWarning,
5176 kTraceVoice,
5177 VoEId(_instanceId, _channelId),
5178 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5179 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5180 codec.plname, codec.pltype, codec.plfreq,
5181 codec.channels, codec.rate);
5182 }
5183 else
5184 {
5185 WEBRTC_TRACE(
5186 kTraceInfo,
5187 kTraceVoice,
5188 VoEId(_instanceId, _channelId),
5189 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005190 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005191 "receiver",
5192 codec.plname, codec.pltype, codec.plfreq,
5193 codec.channels, codec.rate);
5194 }
5195 }
5196}
5197
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005198int Channel::ApmProcessRx(AudioFrame& frame) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005199 // Register the (possibly new) frame parameters.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005200 if (rx_audioproc_->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005201 assert(false);
5202 LOG_FERR1(LS_ERROR, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005203 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005204 if (rx_audioproc_->set_num_channels(frame.num_channels_,
5205 frame.num_channels_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005206 assert(false);
5207 LOG_FERR2(LS_ERROR, set_num_channels, frame.num_channels_,
5208 frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005209 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005210 if (rx_audioproc_->ProcessStream(&frame) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005211 assert(false);
5212 LOG_FERR0(LS_ERROR, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005213 }
5214 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005215}
5216
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005217int Channel::SetSecondarySendCodec(const CodecInst& codec,
5218 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005219 // Sanity check for payload type.
5220 if (red_payload_type < 0 || red_payload_type > 127) {
5221 _engineStatisticsPtr->SetLastError(
5222 VE_PLTYPE_ERROR, kTraceError,
5223 "SetRedPayloadType() invalid RED payload type");
5224 return -1;
5225 }
5226
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005227 if (SetRedPayloadType(red_payload_type) < 0) {
5228 _engineStatisticsPtr->SetLastError(
5229 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5230 "SetSecondarySendCodec() Failed to register RED ACM");
5231 return -1;
5232 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005233 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005234 _engineStatisticsPtr->SetLastError(
5235 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5236 "SetSecondarySendCodec() Failed to register secondary send codec in "
5237 "ACM");
5238 return -1;
5239 }
5240
5241 return 0;
5242}
5243
5244void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005245 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005246}
5247
5248int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005249 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005250 _engineStatisticsPtr->SetLastError(
5251 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5252 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5253 return -1;
5254 }
5255 return 0;
5256}
5257
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005258// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005259int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005260 CodecInst codec;
5261 bool found_red = false;
5262
5263 // Get default RED settings from the ACM database
5264 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5265 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005266 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005267 if (!STR_CASE_CMP(codec.plname, "RED")) {
5268 found_red = true;
5269 break;
5270 }
5271 }
5272
5273 if (!found_red) {
5274 _engineStatisticsPtr->SetLastError(
5275 VE_CODEC_ERROR, kTraceError,
5276 "SetRedPayloadType() RED is not supported");
5277 return -1;
5278 }
5279
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005280 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005281 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005282 _engineStatisticsPtr->SetLastError(
5283 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5284 "SetRedPayloadType() RED registration in ACM module failed");
5285 return -1;
5286 }
5287
5288 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5289 _engineStatisticsPtr->SetLastError(
5290 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5291 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5292 return -1;
5293 }
5294 return 0;
5295}
5296
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005297} // namespace voe
5298} // namespace webrtc