blob: 49a7442ae19da33a88caaa41f7fbb65c390a8d01 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000016#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/utility/interface/audio_frame_operations.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/utility/interface/rtp_dump.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/voice_engine/include/voe_base.h"
27#include "webrtc/voice_engine/include/voe_external_media.h"
28#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
29#include "webrtc/voice_engine/output_mixer.h"
30#include "webrtc/voice_engine/statistics.h"
31#include "webrtc/voice_engine/transmit_mixer.h"
32#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34#if defined(_WIN32)
35#include <Qos.h>
36#endif
37
andrew@webrtc.org50419b02012-11-14 19:07:54 +000038namespace webrtc {
39namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000040
pbos@webrtc.org6141e132013-04-09 10:09:10 +000041int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000042Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000043 uint8_t payloadType,
44 uint32_t timeStamp,
45 const uint8_t* payloadData,
46 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000047 const RTPFragmentationHeader* fragmentation)
48{
49 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
50 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
51 " payloadSize=%u, fragmentation=0x%x)",
52 frameType, payloadType, timeStamp, payloadSize, fragmentation);
53
54 if (_includeAudioLevelIndication)
55 {
56 // Store current audio level in the RTP/RTCP module.
57 // The level will be used in combination with voice-activity state
58 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000059 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000060 }
61
62 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
63 // packetization.
64 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000065 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000066 payloadType,
67 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000068 // Leaving the time when this frame was
69 // received from the capture device as
70 // undefined for voice for now.
71 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000072 payloadData,
73 payloadSize,
74 fragmentation) == -1)
75 {
76 _engineStatisticsPtr->SetLastError(
77 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
78 "Channel::SendData() failed to send data to RTP/RTCP module");
79 return -1;
80 }
81
82 _lastLocalTimeStamp = timeStamp;
83 _lastPayloadType = payloadType;
84
85 return 0;
86}
87
pbos@webrtc.org6141e132013-04-09 10:09:10 +000088int32_t
89Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +000090{
91 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
92 "Channel::InFrameType(frameType=%d)", frameType);
93
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000094 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000095 // 1 indicates speech
96 _sendFrameType = (frameType == 1) ? 1 : 0;
97 return 0;
98}
99
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000100int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000101Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000102{
103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
104 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
105
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000106 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 if (_rxVadObserverPtr)
108 {
109 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
110 }
111
112 return 0;
113}
114
115int
116Channel::SendPacket(int channel, const void *data, int len)
117{
118 channel = VoEChannelId(channel);
119 assert(channel == _channelId);
120
121 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
122 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
123
124 if (_transportPtr == NULL)
125 {
126 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
127 "Channel::SendPacket() failed to send RTP packet due to"
128 " invalid transport object");
129 return -1;
130 }
131
132 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
133 // API
134 if (_insertExtraRTPPacket)
135 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136 uint8_t* rtpHdr = (uint8_t*)data;
137 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (_extraMarkerBit)
139 {
140 M_PT = 0x80; // set the M-bit
141 }
142 M_PT += _extraPayloadType; // set the payload type
143 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
144 _insertExtraRTPPacket = false; // insert one packet only
145 }
146
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 uint8_t* bufferToSendPtr = (uint8_t*)data;
148 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
150 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 {
153 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
154 VoEId(_instanceId,_channelId),
155 "Channel::SendPacket() RTP dump to output file failed");
156 }
157
158 // SRTP or External encryption
159 if (_encrypting)
160 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000161 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
163 if (_encryptionPtr)
164 {
165 if (!_encryptionRTPBufferPtr)
166 {
167 // Allocate memory for encryption buffer one time only
168 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000170 memset(_encryptionRTPBufferPtr, 0,
171 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
173
174 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000175 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 _encryptionPtr->encrypt(_channelId,
177 bufferToSendPtr,
178 _encryptionRTPBufferPtr,
179 bufferLength,
180 (int*)&encryptedBufferLength);
181 if (encryptedBufferLength <= 0)
182 {
183 _engineStatisticsPtr->SetLastError(
184 VE_ENCRYPTION_FAILED,
185 kTraceError, "Channel::SendPacket() encryption failed");
186 return -1;
187 }
188
189 // Replace default data buffer with encrypted buffer
190 bufferToSendPtr = _encryptionRTPBufferPtr;
191 bufferLength = encryptedBufferLength;
192 }
193 }
194
195 // Packet transmission using WebRtc socket transport
196 if (!_externalTransport)
197 {
198 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
199 bufferLength);
200 if (n < 0)
201 {
202 WEBRTC_TRACE(kTraceError, kTraceVoice,
203 VoEId(_instanceId,_channelId),
204 "Channel::SendPacket() RTP transmission using WebRtc"
205 " sockets failed");
206 return -1;
207 }
208 return n;
209 }
210
211 // Packet transmission using external transport transport
212 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000213 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
215 int n = _transportPtr->SendPacket(channel,
216 bufferToSendPtr,
217 bufferLength);
218 if (n < 0)
219 {
220 WEBRTC_TRACE(kTraceError, kTraceVoice,
221 VoEId(_instanceId,_channelId),
222 "Channel::SendPacket() RTP transmission using external"
223 " transport failed");
224 return -1;
225 }
226 return n;
227 }
228}
229
230int
231Channel::SendRTCPPacket(int channel, const void *data, int len)
232{
233 channel = VoEChannelId(channel);
234 assert(channel == _channelId);
235
236 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
237 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
238
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000240 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000241 if (_transportPtr == NULL)
242 {
243 WEBRTC_TRACE(kTraceError, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendRTCPPacket() failed to send RTCP packet"
246 " due to invalid transport object");
247 return -1;
248 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 uint8_t* bufferToSendPtr = (uint8_t*)data;
252 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000255 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
258 VoEId(_instanceId,_channelId),
259 "Channel::SendPacket() RTCP dump to output file failed");
260 }
261
262 // SRTP or External encryption
263 if (_encrypting)
264 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000265 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
267 if (_encryptionPtr)
268 {
269 if (!_encryptionRTCPBufferPtr)
270 {
271 // Allocate memory for encryption buffer one time only
272 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000273 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
276 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000277 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 _encryptionPtr->encrypt_rtcp(_channelId,
279 bufferToSendPtr,
280 _encryptionRTCPBufferPtr,
281 bufferLength,
282 (int*)&encryptedBufferLength);
283 if (encryptedBufferLength <= 0)
284 {
285 _engineStatisticsPtr->SetLastError(
286 VE_ENCRYPTION_FAILED, kTraceError,
287 "Channel::SendRTCPPacket() encryption failed");
288 return -1;
289 }
290
291 // Replace default data buffer with encrypted buffer
292 bufferToSendPtr = _encryptionRTCPBufferPtr;
293 bufferLength = encryptedBufferLength;
294 }
295 }
296
297 // Packet transmission using WebRtc socket transport
298 if (!_externalTransport)
299 {
300 int n = _transportPtr->SendRTCPPacket(channel,
301 bufferToSendPtr,
302 bufferLength);
303 if (n < 0)
304 {
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
306 VoEId(_instanceId,_channelId),
307 "Channel::SendRTCPPacket() transmission using WebRtc"
308 " sockets failed");
309 return -1;
310 }
311 return n;
312 }
313
314 // Packet transmission using external transport transport
315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000316 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000317 if (_transportPtr == NULL)
318 {
319 return -1;
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 int n = _transportPtr->SendRTCPPacket(channel,
322 bufferToSendPtr,
323 bufferLength);
324 if (n < 0)
325 {
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using external"
329 " transport failed");
330 return -1;
331 }
332 return n;
333 }
334
335 return len;
336}
337
338void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000339Channel::OnPlayTelephoneEvent(int32_t id,
340 uint8_t event,
341 uint16_t lengthMs,
342 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343{
344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
345 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000346 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
348 if (!_playOutbandDtmfEvent || (event > 15))
349 {
350 // Ignore callback since feedback is disabled or event is not a
351 // Dtmf tone event.
352 return;
353 }
354
355 assert(_outputMixerPtr != NULL);
356
357 // Start playing out the Dtmf tone (if playout is enabled).
358 // Reduce length of tone with 80ms to the reduce risk of echo.
359 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
360}
361
362void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000363Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000367 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000369 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 assert(channel == _channelId);
371
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000372 // Update ssrc so that NTP for AV sync can be updated.
373 _rtpRtcpModule->SetRemoteSSRC(ssrc);
374
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 if (_rtpObserver)
376 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000377 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000378
379 if (_rtpObserverPtr)
380 {
381 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000382 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 }
384 }
385}
386
pbos@webrtc.org92135212013-05-14 08:31:39 +0000387void Channel::OnIncomingCSRCChanged(int32_t id,
388 uint32_t CSRC,
389 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000390{
391 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
392 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
393 id, CSRC, added);
394
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000395 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000396 assert(channel == _channelId);
397
398 if (_rtpObserver)
399 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000400 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000401
402 if (_rtpObserverPtr)
403 {
404 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
405 }
406 }
407}
408
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000409void Channel::ResetStatistics(uint32_t ssrc) {
410 StreamStatistician* statistician =
411 rtp_receive_statistics_->GetStatistician(ssrc);
412 if (statistician) {
413 statistician->ResetStatistics();
414 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000415}
416
niklase@google.com470e71d2011-07-07 08:21:25 +0000417void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000418Channel::OnApplicationDataReceived(int32_t id,
419 uint8_t subType,
420 uint32_t name,
421 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000422 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000423{
424 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
425 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
426 " name=%u, length=%u)",
427 id, subType, name, length);
428
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000429 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 assert(channel == _channelId);
431
432 if (_rtcpObserver)
433 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000434 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000435
436 if (_rtcpObserverPtr)
437 {
438 _rtcpObserverPtr->OnApplicationDataReceived(channel,
439 subType,
440 name,
441 data,
442 length);
443 }
444 }
445}
446
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000447int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000448Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000449 int32_t id,
450 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000451 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000452 int frequency,
453 uint8_t channels,
454 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000455{
456 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
457 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
458 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
459 id, payloadType, payloadName, frequency, channels, rate);
460
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000461 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000462
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000463 CodecInst receiveCodec = {0};
464 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000465
466 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 receiveCodec.plfreq = frequency;
468 receiveCodec.channels = channels;
469 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000470 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000471
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000472 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 receiveCodec.pacsize = dummyCodec.pacsize;
474
475 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000476 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 {
478 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000479 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 "Channel::OnInitializeDecoder() invalid codec ("
481 "pt=%d, name=%s) received - 1", payloadType, payloadName);
482 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
483 return -1;
484 }
485
486 return 0;
487}
488
489void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000490Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000491{
492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
493 "Channel::OnPacketTimeout(id=%d)", id);
494
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000495 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 if (_voiceEngineObserverPtr)
497 {
498 if (_receiving || _externalTransport)
499 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000500 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 assert(channel == _channelId);
502 // Ensure that next OnReceivedPacket() callback will trigger
503 // a VE_PACKET_RECEIPT_RESTARTED callback.
504 _rtpPacketTimedOut = true;
505 // Deliver callback to the observer
506 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
507 VoEId(_instanceId,_channelId),
508 "Channel::OnPacketTimeout() => "
509 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
510 _voiceEngineObserverPtr->CallbackOnError(channel,
511 VE_RECEIVE_PACKET_TIMEOUT);
512 }
513 }
514}
515
516void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000517Channel::OnReceivedPacket(int32_t id,
518 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000519{
520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
521 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
522 id, packetType);
523
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000524 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
526 // Notify only for the case when we have restarted an RTP session.
527 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
528 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000529 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 if (_voiceEngineObserverPtr)
531 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000532 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 assert(channel == _channelId);
534 // Reset timeout mechanism
535 _rtpPacketTimedOut = false;
536 // Deliver callback to the observer
537 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
538 VoEId(_instanceId,_channelId),
539 "Channel::OnPacketTimeout() =>"
540 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
541 _voiceEngineObserverPtr->CallbackOnError(
542 channel,
543 VE_PACKET_RECEIPT_RESTARTED);
544 }
545 }
546}
547
548void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000549Channel::OnPeriodicDeadOrAlive(int32_t id,
550 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000551{
552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
553 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
554
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000555 {
556 CriticalSectionScoped cs(&_callbackCritSect);
557 if (!_connectionObserver)
558 return;
559 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000560
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000561 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 assert(channel == _channelId);
563
564 // Use Alive as default to limit risk of false Dead detections
565 bool isAlive(true);
566
567 // Always mark the connection as Dead when the module reports kRtpDead
568 if (kRtpDead == alive)
569 {
570 isAlive = false;
571 }
572
573 // It is possible that the connection is alive even if no RTP packet has
574 // been received for a long time since the other side might use VAD/DTX
575 // and a low SID-packet update rate.
576 if ((kRtpNoRtp == alive) && _playing)
577 {
578 // Detect Alive for all NetEQ states except for the case when we are
579 // in PLC_CNG state.
580 // PLC_CNG <=> background noise only due to long expand or error.
581 // Note that, the case where the other side stops sending during CNG
582 // state will be detected as Alive. Dead is is not set until after
583 // missing RTCP packets for at least twelve seconds (handled
584 // internally by the RTP/RTCP module).
585 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
586 }
587
588 UpdateDeadOrAliveCounters(isAlive);
589
590 // Send callback to the registered observer
591 if (_connectionObserver)
592 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000593 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 if (_connectionObserverPtr)
595 {
596 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
597 }
598 }
599}
600
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000601int32_t
602Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000603 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 const WebRtcRTPHeader* rtpHeader)
605{
606 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
607 "Channel::OnReceivedPayloadData(payloadSize=%d,"
608 " payloadType=%u, audioChannel=%u)",
609 payloadSize,
610 rtpHeader->header.payloadType,
611 rtpHeader->type.Audio.channel);
612
roosa@google.com0870f022012-12-12 21:31:41 +0000613 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
614
niklase@google.com470e71d2011-07-07 08:21:25 +0000615 if (!_playing)
616 {
617 // Avoid inserting into NetEQ when we are not playing. Count the
618 // packet as discarded.
619 WEBRTC_TRACE(kTraceStream, kTraceVoice,
620 VoEId(_instanceId, _channelId),
621 "received packet is discarded since playing is not"
622 " activated");
623 _numberOfDiscardedPackets++;
624 return 0;
625 }
626
627 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000628 if (audio_coding_->IncomingPacket(payloadData,
629 payloadSize,
630 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 {
632 _engineStatisticsPtr->SetLastError(
633 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
634 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
635 return -1;
636 }
637
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000638 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 UpdatePacketDelay(rtpHeader->header.timestamp,
640 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000641
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000642 uint16_t round_trip_time = 0;
643 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
644 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000645
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000646 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000647 round_trip_time);
648 if (!nack_list.empty()) {
649 // Can't use nack_list.data() since it's not supported by all
650 // compilers.
651 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000652 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 return 0;
654}
655
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000656bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
657 int rtp_packet_length) {
658 RTPHeader header;
659 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
660 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
661 "IncomingPacket invalid RTP header");
662 return false;
663 }
664 header.payload_type_frequency =
665 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
666 if (header.payload_type_frequency < 0)
667 return false;
668 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
669}
670
pbos@webrtc.org92135212013-05-14 08:31:39 +0000671int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000672{
673 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
674 "Channel::GetAudioFrame(id=%d)", id);
675
676 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000677 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
678 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 {
680 WEBRTC_TRACE(kTraceError, kTraceVoice,
681 VoEId(_instanceId,_channelId),
682 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000683 // In all likelihood, the audio in this frame is garbage. We return an
684 // error so that the audio mixer module doesn't add it to the mix. As
685 // a result, it won't be played out and the actions skipped here are
686 // irrelevant.
687 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000688 }
689
690 if (_RxVadDetection)
691 {
692 UpdateRxVadDetection(audioFrame);
693 }
694
695 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000698 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000699
700 // Perform far-end AudioProcessing module processing on the received signal
701 if (_rxApmIsEnabled)
702 {
703 ApmProcessRx(audioFrame);
704 }
705
706 // Output volume scaling
707 if (_outputGain < 0.99f || _outputGain > 1.01f)
708 {
709 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
710 }
711
712 // Scale left and/or right channel(s) if stereo and master balance is
713 // active
714
715 if (_panLeft != 1.0f || _panRight != 1.0f)
716 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000717 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
719 // Emulate stereo mode since panning is active.
720 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000721 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 }
723 // For true stereo mode (when we are receiving a stereo signal), no
724 // action is needed.
725
726 // Do the panning operation (the audio frame contains stereo at this
727 // stage)
728 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
729 }
730
731 // Mix decoded PCM output with file if file mixing is enabled
732 if (_outputFilePlaying)
733 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000734 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 }
736
737 // Place channel in on-hold state (~muted) if on-hold is activated
738 if (_outputIsOnHold)
739 {
740 AudioFrameOperations::Mute(audioFrame);
741 }
742
743 // External media
744 if (_outputExternalMedia)
745 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000746 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000747 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 if (_outputExternalMediaCallbackPtr)
749 {
750 _outputExternalMediaCallbackPtr->Process(
751 _channelId,
752 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000753 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000754 audioFrame.samples_per_channel_,
755 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 isStereo);
757 }
758 }
759
760 // Record playout if enabled
761 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000762 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000763
764 if (_outputFileRecording && _outputFileRecorderPtr)
765 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000766 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 }
768 }
769
770 // Measure audio level (0-9)
771 _outputAudioLevel.ComputeLevel(audioFrame);
772
773 return 0;
774}
775
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000776int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000777Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000778{
779 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
780 "Channel::NeededFrequency(id=%d)", id);
781
782 int highestNeeded = 0;
783
784 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000785 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000786
787 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000788 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000789 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000790 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 }
792 else
793 {
794 highestNeeded = receiveFrequency;
795 }
796
797 // Special case, if we're playing a file on the playout side
798 // we take that frequency into consideration as well
799 // This is not needed on sending side, since the codec will
800 // limit the spectrum anyway.
801 if (_outputFilePlaying)
802 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000803 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 if (_outputFilePlayerPtr && _outputFilePlaying)
805 {
806 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
807 {
808 highestNeeded=_outputFilePlayerPtr->Frequency();
809 }
810 }
811 }
812
813 return(highestNeeded);
814}
815
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000816int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000817Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000818 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000819 uint32_t instanceId,
820 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000821{
822 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
823 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
824 channelId, instanceId);
825
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000826 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000827 if (channel == NULL)
828 {
829 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
830 VoEId(instanceId,channelId),
831 "Channel::CreateChannel() unable to allocate memory for"
832 " channel");
833 return -1;
834 }
835 return 0;
836}
837
838void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000839Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000840{
841 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
842 "Channel::PlayNotification(id=%d, durationMs=%d)",
843 id, durationMs);
844
845 // Not implement yet
846}
847
848void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000849Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000850{
851 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
852 "Channel::RecordNotification(id=%d, durationMs=%d)",
853 id, durationMs);
854
855 // Not implement yet
856}
857
858void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000859Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860{
861 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
862 "Channel::PlayFileEnded(id=%d)", id);
863
864 if (id == _inputFilePlayerId)
865 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000866 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000867
868 _inputFilePlaying = false;
869 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
870 VoEId(_instanceId,_channelId),
871 "Channel::PlayFileEnded() => input file player module is"
872 " shutdown");
873 }
874 else if (id == _outputFilePlayerId)
875 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000876 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 _outputFilePlaying = false;
879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_instanceId,_channelId),
881 "Channel::PlayFileEnded() => output file player module is"
882 " shutdown");
883 }
884}
885
886void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000887Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000888{
889 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
890 "Channel::RecordFileEnded(id=%d)", id);
891
892 assert(id == _outputFileRecorderId);
893
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000894 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000895
896 _outputFileRecording = false;
897 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
898 VoEId(_instanceId,_channelId),
899 "Channel::RecordFileEnded() => output file recorder module is"
900 " shutdown");
901}
902
pbos@webrtc.org92135212013-05-14 08:31:39 +0000903Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000904 uint32_t instanceId,
905 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
907 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000909 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000910 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000911 rtp_payload_registry_(
912 new RTPPayloadRegistry(channelId,
913 RTPPayloadStrategy::CreateStrategy(true))),
914 rtp_receive_statistics_(ReceiveStatistics::Create(
915 Clock::GetRealTimeClock())),
916 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
917 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
918 this, this, rtp_payload_registry_.get())),
919 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000920 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000921 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 _rtpDumpIn(*RtpDump::CreateRtpDump()),
923 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 _inputFilePlayerPtr(NULL),
927 _outputFilePlayerPtr(NULL),
928 _outputFileRecorderPtr(NULL),
929 // Avoid conflict with other channels by adding 1024 - 1026,
930 // won't use as much as 1024 channels.
931 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
932 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
933 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
934 _inputFilePlaying(false),
935 _outputFilePlaying(false),
936 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000937 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
938 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000939 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000940 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 _inputExternalMediaCallbackPtr(NULL),
942 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000943 _encryptionRTPBufferPtr(NULL),
944 _decryptionRTPBufferPtr(NULL),
945 _encryptionRTCPBufferPtr(NULL),
946 _decryptionRTCPBufferPtr(NULL),
947 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
948 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000949 playout_timestamp_rtp_(0),
950 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000951 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000952 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000953 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000954 _outputMixerPtr(NULL),
955 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000956 _moduleProcessThreadPtr(NULL),
957 _audioDeviceModulePtr(NULL),
958 _voiceEngineObserverPtr(NULL),
959 _callbackCritSectPtr(NULL),
960 _transportPtr(NULL),
961 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000962 rtp_audioproc_(NULL),
963 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000964 _rxVadObserverPtr(NULL),
965 _oldVadDecision(-1),
966 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 _rtpObserverPtr(NULL),
968 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000969 _outputIsOnHold(false),
970 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000971 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000972 _inputIsOnHold(false),
973 _playing(false),
974 _sending(false),
975 _receiving(false),
976 _mixFileWithMicrophone(false),
977 _rtpObserver(false),
978 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 _mute(false),
980 _panLeft(1.0f),
981 _panRight(1.0f),
982 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000983 _encrypting(false),
984 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 _playOutbandDtmfEvent(false),
986 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 _extraPayloadType(0),
988 _insertExtraRTPPacket(false),
989 _extraMarkerBit(false),
990 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000991 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000993 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 _rtpPacketTimedOut(false),
995 _rtpPacketTimeOutIsEnabled(false),
996 _rtpTimeOutSeconds(0),
997 _connectionObserver(false),
998 _connectionObserverPtr(NULL),
999 _countAliveDetections(0),
1000 _countDeadDetections(0),
1001 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001002 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00001003 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 _previousTimestamp(0),
1005 _recPacketDelayMs(20),
1006 _RxVadDetection(false),
1007 _rxApmIsEnabled(false),
1008 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001009 _rxNsIsEnabled(false),
1010 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001011{
1012 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1013 "Channel::Channel() - ctor");
1014 _inbandDtmfQueue.ResetDtmf();
1015 _inbandDtmfGenerator.Init();
1016 _outputAudioLevel.Clear();
1017
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001018 RtpRtcp::Configuration configuration;
1019 configuration.id = VoEModuleId(instanceId, channelId);
1020 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001021 configuration.outgoing_transport = this;
1022 configuration.rtcp_feedback = this;
1023 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001024 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001025
1026 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
niklase@google.com470e71d2011-07-07 08:21:25 +00001027}
1028
1029Channel::~Channel()
1030{
1031 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1032 "Channel::~Channel() - dtor");
1033
1034 if (_outputExternalMedia)
1035 {
1036 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1037 }
1038 if (_inputExternalMedia)
1039 {
1040 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1041 }
1042 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 StopPlayout();
1044
1045 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001046 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 if (_inputFilePlayerPtr)
1048 {
1049 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1050 _inputFilePlayerPtr->StopPlayingFile();
1051 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1052 _inputFilePlayerPtr = NULL;
1053 }
1054 if (_outputFilePlayerPtr)
1055 {
1056 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1057 _outputFilePlayerPtr->StopPlayingFile();
1058 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1059 _outputFilePlayerPtr = NULL;
1060 }
1061 if (_outputFileRecorderPtr)
1062 {
1063 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1064 _outputFileRecorderPtr->StopRecording();
1065 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1066 _outputFileRecorderPtr = NULL;
1067 }
1068 }
1069
1070 // The order to safely shutdown modules in a channel is:
1071 // 1. De-register callbacks in modules
1072 // 2. De-register modules in process thread
1073 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001074 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 {
1076 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1077 VoEId(_instanceId,_channelId),
1078 "~Channel() failed to de-register transport callback"
1079 " (Audio coding module)");
1080 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001081 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001082 {
1083 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1084 VoEId(_instanceId,_channelId),
1085 "~Channel() failed to de-register VAD callback"
1086 " (Audio coding module)");
1087 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001089 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 {
1091 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1092 VoEId(_instanceId,_channelId),
1093 "~Channel() failed to deregister RTP/RTCP module");
1094 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 // End of modules shutdown
1096
1097 // Delete other objects
1098 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1099 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1100 delete [] _encryptionRTPBufferPtr;
1101 delete [] _decryptionRTPBufferPtr;
1102 delete [] _encryptionRTCPBufferPtr;
1103 delete [] _decryptionRTCPBufferPtr;
1104 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 delete &_fileCritSect;
1106}
1107
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001108int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001109Channel::Init()
1110{
1111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1112 "Channel::Init()");
1113
1114 // --- Initial sanity
1115
1116 if ((_engineStatisticsPtr == NULL) ||
1117 (_moduleProcessThreadPtr == NULL))
1118 {
1119 WEBRTC_TRACE(kTraceError, kTraceVoice,
1120 VoEId(_instanceId,_channelId),
1121 "Channel::Init() must call SetEngineInformation() first");
1122 return -1;
1123 }
1124
1125 // --- Add modules to process thread (for periodic schedulation)
1126
1127 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001128 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 if (processThreadFail)
1131 {
1132 _engineStatisticsPtr->SetLastError(
1133 VE_CANNOT_INIT_CHANNEL, kTraceError,
1134 "Channel::Init() modules not registered");
1135 return -1;
1136 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001137 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001138
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001139 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001140#ifdef WEBRTC_CODEC_AVT
1141 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001142 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001143#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001144 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 {
1146 _engineStatisticsPtr->SetLastError(
1147 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1148 "Channel::Init() unable to initialize the ACM - 1");
1149 return -1;
1150 }
1151
1152 // --- RTP/RTCP module initialization
1153
1154 // Ensure that RTCP is enabled by default for the created channel.
1155 // Note that, the module will keep generating RTCP until it is explicitly
1156 // disabled by the user.
1157 // After StopListen (when no sockets exists), RTCP packets will no longer
1158 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001159 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1160 // RTCP is enabled by default.
1161 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
1163 _engineStatisticsPtr->SetLastError(
1164 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1165 "Channel::Init() RTP/RTCP module not initialized");
1166 return -1;
1167 }
1168
1169 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001171 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1172 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001173
1174 if (fail)
1175 {
1176 _engineStatisticsPtr->SetLastError(
1177 VE_CANNOT_INIT_CHANNEL, kTraceError,
1178 "Channel::Init() callbacks not registered");
1179 return -1;
1180 }
1181
1182 // --- Register all supported codecs to the receiving side of the
1183 // RTP/RTCP module
1184
1185 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001186 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001187
1188 for (int idx = 0; idx < nSupportedCodecs; idx++)
1189 {
1190 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001191 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001192 (rtp_receiver_->RegisterReceivePayload(
1193 codec.plname,
1194 codec.pltype,
1195 codec.plfreq,
1196 codec.channels,
1197 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 {
1199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1202 "to RTP/RTCP receiver",
1203 codec.plname, codec.pltype, codec.plfreq,
1204 codec.channels, codec.rate);
1205 }
1206 else
1207 {
1208 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1209 VoEId(_instanceId,_channelId),
1210 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1211 "the RTP/RTCP receiver",
1212 codec.plname, codec.pltype, codec.plfreq,
1213 codec.channels, codec.rate);
1214 }
1215
1216 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001217 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 {
1219 SetSendCodec(codec);
1220 }
1221
1222 // Register default PT for outband 'telephone-event'
1223 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1224 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001225 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001226 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 {
1228 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1229 VoEId(_instanceId,_channelId),
1230 "Channel::Init() failed to register outband "
1231 "'telephone-event' (%d/%d) correctly",
1232 codec.pltype, codec.plfreq);
1233 }
1234 }
1235
1236 if (!STR_CASE_CMP(codec.plname, "CN"))
1237 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001238 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1239 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001240 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 {
1242 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1243 VoEId(_instanceId,_channelId),
1244 "Channel::Init() failed to register CN (%d/%d) "
1245 "correctly - 1",
1246 codec.pltype, codec.plfreq);
1247 }
1248 }
1249#ifdef WEBRTC_CODEC_RED
1250 // Register RED to the receiving side of the ACM.
1251 // We will not receive an OnInitializeDecoder() callback for RED.
1252 if (!STR_CASE_CMP(codec.plname, "RED"))
1253 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001254 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 {
1256 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1257 VoEId(_instanceId,_channelId),
1258 "Channel::Init() failed to register RED (%d/%d) "
1259 "correctly",
1260 codec.pltype, codec.plfreq);
1261 }
1262 }
1263#endif
1264 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001265
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001266 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1267 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1268 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001270 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1271 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1272 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001273 }
1274
1275 return 0;
1276}
1277
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001278int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001279Channel::SetEngineInformation(Statistics& engineStatistics,
1280 OutputMixer& outputMixer,
1281 voe::TransmitMixer& transmitMixer,
1282 ProcessThread& moduleProcessThread,
1283 AudioDeviceModule& audioDeviceModule,
1284 VoiceEngineObserver* voiceEngineObserver,
1285 CriticalSectionWrapper* callbackCritSect)
1286{
1287 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1288 "Channel::SetEngineInformation()");
1289 _engineStatisticsPtr = &engineStatistics;
1290 _outputMixerPtr = &outputMixer;
1291 _transmitMixerPtr = &transmitMixer,
1292 _moduleProcessThreadPtr = &moduleProcessThread;
1293 _audioDeviceModulePtr = &audioDeviceModule;
1294 _voiceEngineObserverPtr = voiceEngineObserver;
1295 _callbackCritSectPtr = callbackCritSect;
1296 return 0;
1297}
1298
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001299int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001300Channel::UpdateLocalTimeStamp()
1301{
1302
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001303 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001304 return 0;
1305}
1306
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001307int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001308Channel::StartPlayout()
1309{
1310 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1311 "Channel::StartPlayout()");
1312 if (_playing)
1313 {
1314 return 0;
1315 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001316
1317 if (!_externalMixing) {
1318 // Add participant as candidates for mixing.
1319 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1320 {
1321 _engineStatisticsPtr->SetLastError(
1322 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1323 "StartPlayout() failed to add participant to mixer");
1324 return -1;
1325 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001326 }
1327
1328 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001329
1330 if (RegisterFilePlayingToMixer() != 0)
1331 return -1;
1332
niklase@google.com470e71d2011-07-07 08:21:25 +00001333 return 0;
1334}
1335
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001336int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001337Channel::StopPlayout()
1338{
1339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "Channel::StopPlayout()");
1341 if (!_playing)
1342 {
1343 return 0;
1344 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001345
1346 if (!_externalMixing) {
1347 // Remove participant as candidates for mixing
1348 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1349 {
1350 _engineStatisticsPtr->SetLastError(
1351 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1352 "StopPlayout() failed to remove participant from mixer");
1353 return -1;
1354 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 }
1356
1357 _playing = false;
1358 _outputAudioLevel.Clear();
1359
1360 return 0;
1361}
1362
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001363int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001364Channel::StartSend()
1365{
1366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1367 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001368 // Resume the previous sequence number which was reset by StopSend().
1369 // This needs to be done before |_sending| is set to true.
1370 if (send_sequence_number_)
1371 SetInitSequenceNumber(send_sequence_number_);
1372
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001374 // A lock is needed because |_sending| can be accessed or modified by
1375 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001376 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001377
1378 if (_sending)
1379 {
1380 return 0;
1381 }
1382 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001384
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001385 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001386 {
1387 _engineStatisticsPtr->SetLastError(
1388 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1389 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001390 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001391 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001392 return -1;
1393 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001394
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 return 0;
1396}
1397
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001398int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001399Channel::StopSend()
1400{
1401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1402 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001404 // A lock is needed because |_sending| can be accessed or modified by
1405 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001406 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001407
1408 if (!_sending)
1409 {
1410 return 0;
1411 }
1412 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001413 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001414
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001415 // Store the sequence number to be able to pick up the same sequence for
1416 // the next StartSend(). This is needed for restarting device, otherwise
1417 // it might cause libSRTP to complain about packets being replayed.
1418 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1419 // CL is landed. See issue
1420 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1421 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1422
niklase@google.com470e71d2011-07-07 08:21:25 +00001423 // Reset sending SSRC and sequence number and triggers direct transmission
1424 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001425 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1426 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 {
1428 _engineStatisticsPtr->SetLastError(
1429 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1430 "StartSend() RTP/RTCP failed to stop sending");
1431 }
1432
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 return 0;
1434}
1435
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001436int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001437Channel::StartReceiving()
1438{
1439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1440 "Channel::StartReceiving()");
1441 if (_receiving)
1442 {
1443 return 0;
1444 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 _receiving = true;
1446 _numberOfDiscardedPackets = 0;
1447 return 0;
1448}
1449
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001450int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001451Channel::StopReceiving()
1452{
1453 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1454 "Channel::StopReceiving()");
1455 if (!_receiving)
1456 {
1457 return 0;
1458 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001459
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001460 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001461 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 RegisterReceiveCodecsToRTPModule();
1463 _receiving = false;
1464 return 0;
1465}
1466
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001467int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001468Channel::SetNetEQPlayoutMode(NetEqModes mode)
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::SetNetEQPlayoutMode()");
1472 AudioPlayoutMode playoutMode(voice);
1473 switch (mode)
1474 {
1475 case kNetEqDefault:
1476 playoutMode = voice;
1477 break;
1478 case kNetEqStreaming:
1479 playoutMode = streaming;
1480 break;
1481 case kNetEqFax:
1482 playoutMode = fax;
1483 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001484 case kNetEqOff:
1485 playoutMode = off;
1486 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001487 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001488 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001489 {
1490 _engineStatisticsPtr->SetLastError(
1491 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1492 "SetNetEQPlayoutMode() failed to set playout mode");
1493 return -1;
1494 }
1495 return 0;
1496}
1497
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001498int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001499Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1500{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001501 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001502 switch (playoutMode)
1503 {
1504 case voice:
1505 mode = kNetEqDefault;
1506 break;
1507 case streaming:
1508 mode = kNetEqStreaming;
1509 break;
1510 case fax:
1511 mode = kNetEqFax;
1512 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001513 case off:
1514 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001515 }
1516 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1517 VoEId(_instanceId,_channelId),
1518 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1519 return 0;
1520}
1521
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001522int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001523Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1524{
1525 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "Channel::SetOnHoldStatus()");
1527 if (mode == kHoldSendAndPlay)
1528 {
1529 _outputIsOnHold = enable;
1530 _inputIsOnHold = enable;
1531 }
1532 else if (mode == kHoldPlayOnly)
1533 {
1534 _outputIsOnHold = enable;
1535 }
1536 if (mode == kHoldSendOnly)
1537 {
1538 _inputIsOnHold = enable;
1539 }
1540 return 0;
1541}
1542
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001543int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001544Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1545{
1546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1547 "Channel::GetOnHoldStatus()");
1548 enabled = (_outputIsOnHold || _inputIsOnHold);
1549 if (_outputIsOnHold && _inputIsOnHold)
1550 {
1551 mode = kHoldSendAndPlay;
1552 }
1553 else if (_outputIsOnHold && !_inputIsOnHold)
1554 {
1555 mode = kHoldPlayOnly;
1556 }
1557 else if (!_outputIsOnHold && _inputIsOnHold)
1558 {
1559 mode = kHoldSendOnly;
1560 }
1561 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1562 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1563 enabled, mode);
1564 return 0;
1565}
1566
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001567int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001568Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1569{
1570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1571 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001572 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001573
1574 if (_voiceEngineObserverPtr)
1575 {
1576 _engineStatisticsPtr->SetLastError(
1577 VE_INVALID_OPERATION, kTraceError,
1578 "RegisterVoiceEngineObserver() observer already enabled");
1579 return -1;
1580 }
1581 _voiceEngineObserverPtr = &observer;
1582 return 0;
1583}
1584
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001585int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001586Channel::DeRegisterVoiceEngineObserver()
1587{
1588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1589 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001590 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001591
1592 if (!_voiceEngineObserverPtr)
1593 {
1594 _engineStatisticsPtr->SetLastError(
1595 VE_INVALID_OPERATION, kTraceWarning,
1596 "DeRegisterVoiceEngineObserver() observer already disabled");
1597 return 0;
1598 }
1599 _voiceEngineObserverPtr = NULL;
1600 return 0;
1601}
1602
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001603int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001604Channel::GetSendCodec(CodecInst& codec)
1605{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001606 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001607}
1608
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001609int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001610Channel::GetRecCodec(CodecInst& codec)
1611{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001612 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001613}
1614
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001615int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001616Channel::SetSendCodec(const CodecInst& codec)
1617{
1618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1619 "Channel::SetSendCodec()");
1620
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001621 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001622 {
1623 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1624 "SetSendCodec() failed to register codec to ACM");
1625 return -1;
1626 }
1627
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001628 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001629 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001630 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1631 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001632 {
1633 WEBRTC_TRACE(
1634 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1635 "SetSendCodec() failed to register codec to"
1636 " RTP/RTCP module");
1637 return -1;
1638 }
1639 }
1640
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001641 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001642 {
1643 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1644 "SetSendCodec() failed to set audio packet size");
1645 return -1;
1646 }
1647
1648 return 0;
1649}
1650
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001651int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001652Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1653{
1654 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1655 "Channel::SetVADStatus(mode=%d)", mode);
1656 // To disable VAD, DTX must be disabled too
1657 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001658 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001659 {
1660 _engineStatisticsPtr->SetLastError(
1661 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1662 "SetVADStatus() failed to set VAD");
1663 return -1;
1664 }
1665 return 0;
1666}
1667
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001668int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001669Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1670{
1671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1672 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001673 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001674 {
1675 _engineStatisticsPtr->SetLastError(
1676 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1677 "GetVADStatus() failed to get VAD status");
1678 return -1;
1679 }
1680 disabledDTX = !disabledDTX;
1681 return 0;
1682}
1683
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001684int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001685Channel::SetRecPayloadType(const CodecInst& codec)
1686{
1687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1688 "Channel::SetRecPayloadType()");
1689
1690 if (_playing)
1691 {
1692 _engineStatisticsPtr->SetLastError(
1693 VE_ALREADY_PLAYING, kTraceError,
1694 "SetRecPayloadType() unable to set PT while playing");
1695 return -1;
1696 }
1697 if (_receiving)
1698 {
1699 _engineStatisticsPtr->SetLastError(
1700 VE_ALREADY_LISTENING, kTraceError,
1701 "SetRecPayloadType() unable to set PT while listening");
1702 return -1;
1703 }
1704
1705 if (codec.pltype == -1)
1706 {
1707 // De-register the selected codec (RTP/RTCP module and ACM)
1708
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001709 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001710 CodecInst rxCodec = codec;
1711
1712 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001713 rtp_payload_registry_->ReceivePayloadType(
1714 rxCodec.plname,
1715 rxCodec.plfreq,
1716 rxCodec.channels,
1717 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1718 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001719 rxCodec.pltype = pltype;
1720
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001721 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001722 {
1723 _engineStatisticsPtr->SetLastError(
1724 VE_RTP_RTCP_MODULE_ERROR,
1725 kTraceError,
1726 "SetRecPayloadType() RTP/RTCP-module deregistration "
1727 "failed");
1728 return -1;
1729 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001730 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001731 {
1732 _engineStatisticsPtr->SetLastError(
1733 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1734 "SetRecPayloadType() ACM deregistration failed - 1");
1735 return -1;
1736 }
1737 return 0;
1738 }
1739
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001740 if (rtp_receiver_->RegisterReceivePayload(
1741 codec.plname,
1742 codec.pltype,
1743 codec.plfreq,
1744 codec.channels,
1745 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001746 {
1747 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001748 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1749 if (rtp_receiver_->RegisterReceivePayload(
1750 codec.plname,
1751 codec.pltype,
1752 codec.plfreq,
1753 codec.channels,
1754 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001755 {
1756 _engineStatisticsPtr->SetLastError(
1757 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1758 "SetRecPayloadType() RTP/RTCP-module registration failed");
1759 return -1;
1760 }
1761 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001762 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001764 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1765 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001766 {
1767 _engineStatisticsPtr->SetLastError(
1768 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1769 "SetRecPayloadType() ACM registration failed - 1");
1770 return -1;
1771 }
1772 }
1773 return 0;
1774}
1775
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001776int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001777Channel::GetRecPayloadType(CodecInst& codec)
1778{
1779 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1780 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001781 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001782 if (rtp_payload_registry_->ReceivePayloadType(
1783 codec.plname,
1784 codec.plfreq,
1785 codec.channels,
1786 (codec.rate < 0) ? 0 : codec.rate,
1787 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001788 {
1789 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001790 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001791 "GetRecPayloadType() failed to retrieve RX payload type");
1792 return -1;
1793 }
1794 codec.pltype = payloadType;
1795 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1796 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1797 return 0;
1798}
1799
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001800int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001801Channel::SetAMREncFormat(AmrMode mode)
1802{
1803 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1804 "Channel::SetAMREncFormat()");
1805
1806 // ACM doesn't support AMR
1807 return -1;
1808}
1809
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001810int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001811Channel::SetAMRDecFormat(AmrMode mode)
1812{
1813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1814 "Channel::SetAMRDecFormat()");
1815
1816 // ACM doesn't support AMR
1817 return -1;
1818}
1819
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001820int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001821Channel::SetAMRWbEncFormat(AmrMode mode)
1822{
1823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1824 "Channel::SetAMRWbEncFormat()");
1825
1826 // ACM doesn't support AMR
1827 return -1;
1828
1829}
1830
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001831int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001832Channel::SetAMRWbDecFormat(AmrMode mode)
1833{
1834 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1835 "Channel::SetAMRWbDecFormat()");
1836
1837 // ACM doesn't support AMR
1838 return -1;
1839}
1840
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001841int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001842Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1843{
1844 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1845 "Channel::SetSendCNPayloadType()");
1846
1847 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001849 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001850 if (frequency == kFreq32000Hz)
1851 samplingFreqHz = 32000;
1852 else if (frequency == kFreq16000Hz)
1853 samplingFreqHz = 16000;
1854
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001855 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001856 {
1857 _engineStatisticsPtr->SetLastError(
1858 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1859 "SetSendCNPayloadType() failed to retrieve default CN codec "
1860 "settings");
1861 return -1;
1862 }
1863
1864 // Modify the payload type (must be set to dynamic range)
1865 codec.pltype = type;
1866
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001867 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1871 "SetSendCNPayloadType() failed to register CN to ACM");
1872 return -1;
1873 }
1874
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001875 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001876 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001877 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1878 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001879 {
1880 _engineStatisticsPtr->SetLastError(
1881 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1882 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1883 "module");
1884 return -1;
1885 }
1886 }
1887 return 0;
1888}
1889
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001890int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001891Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1892{
1893 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1894 "Channel::SetISACInitTargetRate()");
1895
1896 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001897 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001898 {
1899 _engineStatisticsPtr->SetLastError(
1900 VE_CODEC_ERROR, kTraceError,
1901 "SetISACInitTargetRate() failed to retrieve send codec");
1902 return -1;
1903 }
1904 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1905 {
1906 // This API is only valid if iSAC is setup to run in channel-adaptive
1907 // mode.
1908 // We do not validate the adaptive mode here. It is done later in the
1909 // ConfigISACBandwidthEstimator() API.
1910 _engineStatisticsPtr->SetLastError(
1911 VE_CODEC_ERROR, kTraceError,
1912 "SetISACInitTargetRate() send codec is not iSAC");
1913 return -1;
1914 }
1915
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001916 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001917 if (16000 == sendCodec.plfreq)
1918 {
1919 // Note that 0 is a valid and corresponds to "use default
1920 if ((rateBps != 0 &&
1921 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1922 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1923 {
1924 _engineStatisticsPtr->SetLastError(
1925 VE_INVALID_ARGUMENT, kTraceError,
1926 "SetISACInitTargetRate() invalid target rate - 1");
1927 return -1;
1928 }
1929 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001930 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001931 }
1932 else if (32000 == sendCodec.plfreq)
1933 {
1934 if ((rateBps != 0 &&
1935 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1936 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1937 {
1938 _engineStatisticsPtr->SetLastError(
1939 VE_INVALID_ARGUMENT, kTraceError,
1940 "SetISACInitTargetRate() invalid target rate - 2");
1941 return -1;
1942 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001943 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001944 }
1945
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001946 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001947 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1948 {
1949 _engineStatisticsPtr->SetLastError(
1950 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1951 "SetISACInitTargetRate() iSAC BWE config failed");
1952 return -1;
1953 }
1954
1955 return 0;
1956}
1957
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001958int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001959Channel::SetISACMaxRate(int rateBps)
1960{
1961 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1962 "Channel::SetISACMaxRate()");
1963
1964 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001965 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001966 {
1967 _engineStatisticsPtr->SetLastError(
1968 VE_CODEC_ERROR, kTraceError,
1969 "SetISACMaxRate() failed to retrieve send codec");
1970 return -1;
1971 }
1972 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1973 {
1974 // This API is only valid if iSAC is selected as sending codec.
1975 _engineStatisticsPtr->SetLastError(
1976 VE_CODEC_ERROR, kTraceError,
1977 "SetISACMaxRate() send codec is not iSAC");
1978 return -1;
1979 }
1980 if (16000 == sendCodec.plfreq)
1981 {
1982 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1983 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1984 {
1985 _engineStatisticsPtr->SetLastError(
1986 VE_INVALID_ARGUMENT, kTraceError,
1987 "SetISACMaxRate() invalid max rate - 1");
1988 return -1;
1989 }
1990 }
1991 else if (32000 == sendCodec.plfreq)
1992 {
1993 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1994 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1995 {
1996 _engineStatisticsPtr->SetLastError(
1997 VE_INVALID_ARGUMENT, kTraceError,
1998 "SetISACMaxRate() invalid max rate - 2");
1999 return -1;
2000 }
2001 }
2002 if (_sending)
2003 {
2004 _engineStatisticsPtr->SetLastError(
2005 VE_SENDING, kTraceError,
2006 "SetISACMaxRate() unable to set max rate while sending");
2007 return -1;
2008 }
2009
2010 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2011 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002012 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002013 {
2014 _engineStatisticsPtr->SetLastError(
2015 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2016 "SetISACMaxRate() failed to set max rate");
2017 return -1;
2018 }
2019
2020 return 0;
2021}
2022
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002023int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002024Channel::SetISACMaxPayloadSize(int sizeBytes)
2025{
2026 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2027 "Channel::SetISACMaxPayloadSize()");
2028 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002029 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002030 {
2031 _engineStatisticsPtr->SetLastError(
2032 VE_CODEC_ERROR, kTraceError,
2033 "SetISACMaxPayloadSize() failed to retrieve send codec");
2034 return -1;
2035 }
2036 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2037 {
2038 _engineStatisticsPtr->SetLastError(
2039 VE_CODEC_ERROR, kTraceError,
2040 "SetISACMaxPayloadSize() send codec is not iSAC");
2041 return -1;
2042 }
2043 if (16000 == sendCodec.plfreq)
2044 {
2045 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2046 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2047 {
2048 _engineStatisticsPtr->SetLastError(
2049 VE_INVALID_ARGUMENT, kTraceError,
2050 "SetISACMaxPayloadSize() invalid max payload - 1");
2051 return -1;
2052 }
2053 }
2054 else if (32000 == sendCodec.plfreq)
2055 {
2056 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2057 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2058 {
2059 _engineStatisticsPtr->SetLastError(
2060 VE_INVALID_ARGUMENT, kTraceError,
2061 "SetISACMaxPayloadSize() invalid max payload - 2");
2062 return -1;
2063 }
2064 }
2065 if (_sending)
2066 {
2067 _engineStatisticsPtr->SetLastError(
2068 VE_SENDING, kTraceError,
2069 "SetISACMaxPayloadSize() unable to set max rate while sending");
2070 return -1;
2071 }
2072
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002073 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002074 {
2075 _engineStatisticsPtr->SetLastError(
2076 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2077 "SetISACMaxPayloadSize() failed to set max payload size");
2078 return -1;
2079 }
2080 return 0;
2081}
2082
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002083int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002084{
2085 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2086 "Channel::RegisterExternalTransport()");
2087
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002088 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002089
niklase@google.com470e71d2011-07-07 08:21:25 +00002090 if (_externalTransport)
2091 {
2092 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2093 kTraceError,
2094 "RegisterExternalTransport() external transport already enabled");
2095 return -1;
2096 }
2097 _externalTransport = true;
2098 _transportPtr = &transport;
2099 return 0;
2100}
2101
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002102int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002103Channel::DeRegisterExternalTransport()
2104{
2105 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2106 "Channel::DeRegisterExternalTransport()");
2107
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002108 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002109
niklase@google.com470e71d2011-07-07 08:21:25 +00002110 if (!_transportPtr)
2111 {
2112 _engineStatisticsPtr->SetLastError(
2113 VE_INVALID_OPERATION, kTraceWarning,
2114 "DeRegisterExternalTransport() external transport already "
2115 "disabled");
2116 return 0;
2117 }
2118 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002119 _transportPtr = NULL;
2120 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2121 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002122 return 0;
2123}
2124
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002125int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002126 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2127 "Channel::ReceivedRTPPacket()");
2128
2129 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002130 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002131
2132 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002133 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2134 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002135 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2136 VoEId(_instanceId,_channelId),
2137 "Channel::SendPacket() RTP dump to input file failed");
2138 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002139 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002140 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002141 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2142 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2143 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002144 return -1;
2145 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002146 header.payload_type_frequency =
2147 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002148 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002149 return -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002150 rtp_receive_statistics_->IncomingPacket(header, length,
2151 IsPacketRetransmitted(header));
2152 rtp_payload_registry_->SetIncomingPayloadType(header);
2153 return ReceivePacket(received_packet, length, header,
2154 IsPacketInOrder(header)) ? 0 : -1;
2155}
2156
2157bool Channel::ReceivePacket(const uint8_t* packet,
2158 int packet_length,
2159 const RTPHeader& header,
2160 bool in_order) {
2161 if (rtp_payload_registry_->IsEncapsulated(header)) {
2162 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002163 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002164 const uint8_t* payload = packet + header.headerLength;
2165 int payload_length = packet_length - header.headerLength;
2166 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002167 PayloadUnion payload_specific;
2168 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002169 &payload_specific)) {
2170 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002171 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002172 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2173 payload_specific, in_order);
2174}
2175
2176bool Channel::HandleEncapsulation(const uint8_t* packet,
2177 int packet_length,
2178 const RTPHeader& header) {
2179 if (!rtp_payload_registry_->IsRtx(header))
2180 return false;
2181
2182 // Remove the RTX header and parse the original RTP header.
2183 if (packet_length < header.headerLength)
2184 return false;
2185 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2186 return false;
2187 if (restored_packet_in_use_) {
2188 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2189 "Multiple RTX headers detected, dropping packet");
2190 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002191 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002192 uint8_t* restored_packet_ptr = restored_packet_;
2193 if (!rtp_payload_registry_->RestoreOriginalPacket(
2194 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2195 header)) {
2196 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2197 "Incoming RTX packet: invalid RTP header");
2198 return false;
2199 }
2200 restored_packet_in_use_ = true;
2201 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2202 restored_packet_in_use_ = false;
2203 return ret;
2204}
2205
2206bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2207 StreamStatistician* statistician =
2208 rtp_receive_statistics_->GetStatistician(header.ssrc);
2209 if (!statistician)
2210 return false;
2211 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002212}
2213
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002214bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002215 // Retransmissions are handled separately if RTX is enabled.
2216 if (rtp_payload_registry_->RtxEnabled())
2217 return false;
2218 StreamStatistician* statistician =
2219 rtp_receive_statistics_->GetStatistician(header.ssrc);
2220 if (!statistician)
2221 return false;
2222 // Check if this is a retransmission.
2223 uint16_t min_rtt = 0;
2224 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
2225 return !IsPacketInOrder(header) &&
2226 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002227}
2228
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002229int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002230 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2231 "Channel::ReceivedRTCPPacket()");
2232 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002233 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002234
2235 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002236 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2237 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002238 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2239 VoEId(_instanceId,_channelId),
2240 "Channel::SendPacket() RTCP dump to input file failed");
2241 }
2242
2243 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002244 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2245 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002246 _engineStatisticsPtr->SetLastError(
2247 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2248 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2249 }
2250 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002251}
2252
niklase@google.com470e71d2011-07-07 08:21:25 +00002253int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002254 bool loop,
2255 FileFormats format,
2256 int startPosition,
2257 float volumeScaling,
2258 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002259 const CodecInst* codecInst)
2260{
2261 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2262 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2263 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2264 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2265 startPosition, stopPosition);
2266
2267 if (_outputFilePlaying)
2268 {
2269 _engineStatisticsPtr->SetLastError(
2270 VE_ALREADY_PLAYING, kTraceError,
2271 "StartPlayingFileLocally() is already playing");
2272 return -1;
2273 }
2274
niklase@google.com470e71d2011-07-07 08:21:25 +00002275 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002276 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002277
2278 if (_outputFilePlayerPtr)
2279 {
2280 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2281 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2282 _outputFilePlayerPtr = NULL;
2283 }
2284
2285 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2286 _outputFilePlayerId, (const FileFormats)format);
2287
2288 if (_outputFilePlayerPtr == NULL)
2289 {
2290 _engineStatisticsPtr->SetLastError(
2291 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002292 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002293 return -1;
2294 }
2295
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002296 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002297
2298 if (_outputFilePlayerPtr->StartPlayingFile(
2299 fileName,
2300 loop,
2301 startPosition,
2302 volumeScaling,
2303 notificationTime,
2304 stopPosition,
2305 (const CodecInst*)codecInst) != 0)
2306 {
2307 _engineStatisticsPtr->SetLastError(
2308 VE_BAD_FILE, kTraceError,
2309 "StartPlayingFile() failed to start file playout");
2310 _outputFilePlayerPtr->StopPlayingFile();
2311 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2312 _outputFilePlayerPtr = NULL;
2313 return -1;
2314 }
2315 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2316 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002317 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002318
2319 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002320 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002321
2322 return 0;
2323}
2324
2325int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002326 FileFormats format,
2327 int startPosition,
2328 float volumeScaling,
2329 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002330 const CodecInst* codecInst)
2331{
2332 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2333 "Channel::StartPlayingFileLocally(format=%d,"
2334 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2335 format, volumeScaling, startPosition, stopPosition);
2336
2337 if(stream == NULL)
2338 {
2339 _engineStatisticsPtr->SetLastError(
2340 VE_BAD_FILE, kTraceError,
2341 "StartPlayingFileLocally() NULL as input stream");
2342 return -1;
2343 }
2344
2345
2346 if (_outputFilePlaying)
2347 {
2348 _engineStatisticsPtr->SetLastError(
2349 VE_ALREADY_PLAYING, kTraceError,
2350 "StartPlayingFileLocally() is already playing");
2351 return -1;
2352 }
2353
niklase@google.com470e71d2011-07-07 08:21:25 +00002354 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002355 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002356
2357 // Destroy the old instance
2358 if (_outputFilePlayerPtr)
2359 {
2360 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2361 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2362 _outputFilePlayerPtr = NULL;
2363 }
2364
2365 // Create the instance
2366 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2367 _outputFilePlayerId,
2368 (const FileFormats)format);
2369
2370 if (_outputFilePlayerPtr == NULL)
2371 {
2372 _engineStatisticsPtr->SetLastError(
2373 VE_INVALID_ARGUMENT, kTraceError,
2374 "StartPlayingFileLocally() filePlayer format isnot correct");
2375 return -1;
2376 }
2377
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002378 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002379
2380 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2381 volumeScaling,
2382 notificationTime,
2383 stopPosition, codecInst) != 0)
2384 {
2385 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2386 "StartPlayingFile() failed to "
2387 "start file playout");
2388 _outputFilePlayerPtr->StopPlayingFile();
2389 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2390 _outputFilePlayerPtr = NULL;
2391 return -1;
2392 }
2393 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2394 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002395 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002396
2397 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002398 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002399
niklase@google.com470e71d2011-07-07 08:21:25 +00002400 return 0;
2401}
2402
2403int Channel::StopPlayingFileLocally()
2404{
2405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2406 "Channel::StopPlayingFileLocally()");
2407
2408 if (!_outputFilePlaying)
2409 {
2410 _engineStatisticsPtr->SetLastError(
2411 VE_INVALID_OPERATION, kTraceWarning,
2412 "StopPlayingFileLocally() isnot playing");
2413 return 0;
2414 }
2415
niklase@google.com470e71d2011-07-07 08:21:25 +00002416 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002417 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002418
2419 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2420 {
2421 _engineStatisticsPtr->SetLastError(
2422 VE_STOP_RECORDING_FAILED, kTraceError,
2423 "StopPlayingFile() could not stop playing");
2424 return -1;
2425 }
2426 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2427 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2428 _outputFilePlayerPtr = NULL;
2429 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002430 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002431 // _fileCritSect cannot be taken while calling
2432 // SetAnonymousMixibilityStatus. Refer to comments in
2433 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002434 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2435 {
2436 _engineStatisticsPtr->SetLastError(
2437 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002438 "StopPlayingFile() failed to stop participant from playing as"
2439 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002440 return -1;
2441 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002442
2443 return 0;
2444}
2445
2446int Channel::IsPlayingFileLocally() const
2447{
2448 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2449 "Channel::IsPlayingFileLocally()");
2450
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002451 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002452}
2453
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002454int Channel::RegisterFilePlayingToMixer()
2455{
2456 // Return success for not registering for file playing to mixer if:
2457 // 1. playing file before playout is started on that channel.
2458 // 2. starting playout without file playing on that channel.
2459 if (!_playing || !_outputFilePlaying)
2460 {
2461 return 0;
2462 }
2463
2464 // |_fileCritSect| cannot be taken while calling
2465 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2466 // frames can be pulled by the mixer. Since the frames are generated from
2467 // the file, _fileCritSect will be taken. This would result in a deadlock.
2468 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2469 {
2470 CriticalSectionScoped cs(&_fileCritSect);
2471 _outputFilePlaying = false;
2472 _engineStatisticsPtr->SetLastError(
2473 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2474 "StartPlayingFile() failed to add participant as file to mixer");
2475 _outputFilePlayerPtr->StopPlayingFile();
2476 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2477 _outputFilePlayerPtr = NULL;
2478 return -1;
2479 }
2480
2481 return 0;
2482}
2483
pbos@webrtc.org92135212013-05-14 08:31:39 +00002484int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002485{
2486 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2487 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2488
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002489 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002490
2491 if (!_outputFilePlaying)
2492 {
2493 _engineStatisticsPtr->SetLastError(
2494 VE_INVALID_OPERATION, kTraceError,
2495 "ScaleLocalFilePlayout() isnot playing");
2496 return -1;
2497 }
2498 if ((_outputFilePlayerPtr == NULL) ||
2499 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2500 {
2501 _engineStatisticsPtr->SetLastError(
2502 VE_BAD_ARGUMENT, kTraceError,
2503 "SetAudioScaling() failed to scale the playout");
2504 return -1;
2505 }
2506
2507 return 0;
2508}
2509
2510int Channel::GetLocalPlayoutPosition(int& positionMs)
2511{
2512 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2513 "Channel::GetLocalPlayoutPosition(position=?)");
2514
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002515 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002516
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002517 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002518
2519 if (_outputFilePlayerPtr == NULL)
2520 {
2521 _engineStatisticsPtr->SetLastError(
2522 VE_INVALID_OPERATION, kTraceError,
2523 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2524 return -1;
2525 }
2526
2527 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2528 {
2529 _engineStatisticsPtr->SetLastError(
2530 VE_BAD_FILE, kTraceError,
2531 "GetLocalPlayoutPosition() failed");
2532 return -1;
2533 }
2534 positionMs = position;
2535
2536 return 0;
2537}
2538
2539int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002540 bool loop,
2541 FileFormats format,
2542 int startPosition,
2543 float volumeScaling,
2544 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002545 const CodecInst* codecInst)
2546{
2547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2548 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2549 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2550 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2551 startPosition, stopPosition);
2552
2553 if (_inputFilePlaying)
2554 {
2555 _engineStatisticsPtr->SetLastError(
2556 VE_ALREADY_PLAYING, kTraceWarning,
2557 "StartPlayingFileAsMicrophone() filePlayer is playing");
2558 return 0;
2559 }
2560
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002561 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002562
2563 // Destroy the old instance
2564 if (_inputFilePlayerPtr)
2565 {
2566 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2567 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2568 _inputFilePlayerPtr = NULL;
2569 }
2570
2571 // Create the instance
2572 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2573 _inputFilePlayerId, (const FileFormats)format);
2574
2575 if (_inputFilePlayerPtr == NULL)
2576 {
2577 _engineStatisticsPtr->SetLastError(
2578 VE_INVALID_ARGUMENT, kTraceError,
2579 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2580 return -1;
2581 }
2582
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002583 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002584
2585 if (_inputFilePlayerPtr->StartPlayingFile(
2586 fileName,
2587 loop,
2588 startPosition,
2589 volumeScaling,
2590 notificationTime,
2591 stopPosition,
2592 (const CodecInst*)codecInst) != 0)
2593 {
2594 _engineStatisticsPtr->SetLastError(
2595 VE_BAD_FILE, kTraceError,
2596 "StartPlayingFile() failed to start file playout");
2597 _inputFilePlayerPtr->StopPlayingFile();
2598 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2599 _inputFilePlayerPtr = NULL;
2600 return -1;
2601 }
2602 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2603 _inputFilePlaying = true;
2604
2605 return 0;
2606}
2607
2608int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002609 FileFormats format,
2610 int startPosition,
2611 float volumeScaling,
2612 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002613 const CodecInst* codecInst)
2614{
2615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2616 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2617 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2618 format, volumeScaling, startPosition, stopPosition);
2619
2620 if(stream == NULL)
2621 {
2622 _engineStatisticsPtr->SetLastError(
2623 VE_BAD_FILE, kTraceError,
2624 "StartPlayingFileAsMicrophone NULL as input stream");
2625 return -1;
2626 }
2627
2628 if (_inputFilePlaying)
2629 {
2630 _engineStatisticsPtr->SetLastError(
2631 VE_ALREADY_PLAYING, kTraceWarning,
2632 "StartPlayingFileAsMicrophone() is playing");
2633 return 0;
2634 }
2635
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002636 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002637
2638 // Destroy the old instance
2639 if (_inputFilePlayerPtr)
2640 {
2641 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2642 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2643 _inputFilePlayerPtr = NULL;
2644 }
2645
2646 // Create the instance
2647 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2648 _inputFilePlayerId, (const FileFormats)format);
2649
2650 if (_inputFilePlayerPtr == NULL)
2651 {
2652 _engineStatisticsPtr->SetLastError(
2653 VE_INVALID_ARGUMENT, kTraceError,
2654 "StartPlayingInputFile() filePlayer format isnot correct");
2655 return -1;
2656 }
2657
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002658 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002659
2660 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2661 volumeScaling, notificationTime,
2662 stopPosition, codecInst) != 0)
2663 {
2664 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2665 "StartPlayingFile() failed to start "
2666 "file playout");
2667 _inputFilePlayerPtr->StopPlayingFile();
2668 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2669 _inputFilePlayerPtr = NULL;
2670 return -1;
2671 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002672
niklase@google.com470e71d2011-07-07 08:21:25 +00002673 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2674 _inputFilePlaying = true;
2675
2676 return 0;
2677}
2678
2679int Channel::StopPlayingFileAsMicrophone()
2680{
2681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2682 "Channel::StopPlayingFileAsMicrophone()");
2683
2684 if (!_inputFilePlaying)
2685 {
2686 _engineStatisticsPtr->SetLastError(
2687 VE_INVALID_OPERATION, kTraceWarning,
2688 "StopPlayingFileAsMicrophone() isnot playing");
2689 return 0;
2690 }
2691
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002692 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002693 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2694 {
2695 _engineStatisticsPtr->SetLastError(
2696 VE_STOP_RECORDING_FAILED, kTraceError,
2697 "StopPlayingFile() could not stop playing");
2698 return -1;
2699 }
2700 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2701 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2702 _inputFilePlayerPtr = NULL;
2703 _inputFilePlaying = false;
2704
2705 return 0;
2706}
2707
2708int Channel::IsPlayingFileAsMicrophone() const
2709{
2710 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2711 "Channel::IsPlayingFileAsMicrophone()");
2712
2713 return _inputFilePlaying;
2714}
2715
pbos@webrtc.org92135212013-05-14 08:31:39 +00002716int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002717{
2718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2719 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2720
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002721 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002722
2723 if (!_inputFilePlaying)
2724 {
2725 _engineStatisticsPtr->SetLastError(
2726 VE_INVALID_OPERATION, kTraceError,
2727 "ScaleFileAsMicrophonePlayout() isnot playing");
2728 return -1;
2729 }
2730
2731 if ((_inputFilePlayerPtr == NULL) ||
2732 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2733 {
2734 _engineStatisticsPtr->SetLastError(
2735 VE_BAD_ARGUMENT, kTraceError,
2736 "SetAudioScaling() failed to scale playout");
2737 return -1;
2738 }
2739
2740 return 0;
2741}
2742
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002743int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002744 const CodecInst* codecInst)
2745{
2746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2747 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2748
2749 if (_outputFileRecording)
2750 {
2751 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2752 "StartRecordingPlayout() is already recording");
2753 return 0;
2754 }
2755
2756 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002757 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002758 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2759
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002760 if ((codecInst != NULL) &&
2761 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 {
2763 _engineStatisticsPtr->SetLastError(
2764 VE_BAD_ARGUMENT, kTraceError,
2765 "StartRecordingPlayout() invalid compression");
2766 return(-1);
2767 }
2768 if(codecInst == NULL)
2769 {
2770 format = kFileFormatPcm16kHzFile;
2771 codecInst=&dummyCodec;
2772 }
2773 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2774 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2775 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2776 {
2777 format = kFileFormatWavFile;
2778 }
2779 else
2780 {
2781 format = kFileFormatCompressedFile;
2782 }
2783
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002784 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002785
2786 // Destroy the old instance
2787 if (_outputFileRecorderPtr)
2788 {
2789 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2790 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2791 _outputFileRecorderPtr = NULL;
2792 }
2793
2794 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2795 _outputFileRecorderId, (const FileFormats)format);
2796 if (_outputFileRecorderPtr == NULL)
2797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_INVALID_ARGUMENT, kTraceError,
2800 "StartRecordingPlayout() fileRecorder format isnot correct");
2801 return -1;
2802 }
2803
2804 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2805 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2806 {
2807 _engineStatisticsPtr->SetLastError(
2808 VE_BAD_FILE, kTraceError,
2809 "StartRecordingAudioFile() failed to start file recording");
2810 _outputFileRecorderPtr->StopRecording();
2811 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2812 _outputFileRecorderPtr = NULL;
2813 return -1;
2814 }
2815 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2816 _outputFileRecording = true;
2817
2818 return 0;
2819}
2820
2821int Channel::StartRecordingPlayout(OutStream* stream,
2822 const CodecInst* codecInst)
2823{
2824 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2825 "Channel::StartRecordingPlayout()");
2826
2827 if (_outputFileRecording)
2828 {
2829 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2830 "StartRecordingPlayout() is already recording");
2831 return 0;
2832 }
2833
2834 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002835 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002836 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2837
2838 if (codecInst != NULL && codecInst->channels != 1)
2839 {
2840 _engineStatisticsPtr->SetLastError(
2841 VE_BAD_ARGUMENT, kTraceError,
2842 "StartRecordingPlayout() invalid compression");
2843 return(-1);
2844 }
2845 if(codecInst == NULL)
2846 {
2847 format = kFileFormatPcm16kHzFile;
2848 codecInst=&dummyCodec;
2849 }
2850 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2851 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2852 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2853 {
2854 format = kFileFormatWavFile;
2855 }
2856 else
2857 {
2858 format = kFileFormatCompressedFile;
2859 }
2860
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002861 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002862
2863 // Destroy the old instance
2864 if (_outputFileRecorderPtr)
2865 {
2866 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2867 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2868 _outputFileRecorderPtr = NULL;
2869 }
2870
2871 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2872 _outputFileRecorderId, (const FileFormats)format);
2873 if (_outputFileRecorderPtr == NULL)
2874 {
2875 _engineStatisticsPtr->SetLastError(
2876 VE_INVALID_ARGUMENT, kTraceError,
2877 "StartRecordingPlayout() fileRecorder format isnot correct");
2878 return -1;
2879 }
2880
2881 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2882 notificationTime) != 0)
2883 {
2884 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2885 "StartRecordingPlayout() failed to "
2886 "start file recording");
2887 _outputFileRecorderPtr->StopRecording();
2888 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2889 _outputFileRecorderPtr = NULL;
2890 return -1;
2891 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002892
niklase@google.com470e71d2011-07-07 08:21:25 +00002893 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2894 _outputFileRecording = true;
2895
2896 return 0;
2897}
2898
2899int Channel::StopRecordingPlayout()
2900{
2901 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2902 "Channel::StopRecordingPlayout()");
2903
2904 if (!_outputFileRecording)
2905 {
2906 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2907 "StopRecordingPlayout() isnot recording");
2908 return -1;
2909 }
2910
2911
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002912 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002913
2914 if (_outputFileRecorderPtr->StopRecording() != 0)
2915 {
2916 _engineStatisticsPtr->SetLastError(
2917 VE_STOP_RECORDING_FAILED, kTraceError,
2918 "StopRecording() could not stop recording");
2919 return(-1);
2920 }
2921 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2922 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2923 _outputFileRecorderPtr = NULL;
2924 _outputFileRecording = false;
2925
2926 return 0;
2927}
2928
2929void
2930Channel::SetMixWithMicStatus(bool mix)
2931{
2932 _mixFileWithMicrophone=mix;
2933}
2934
2935int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002936Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002937{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002938 int8_t currentLevel = _outputAudioLevel.Level();
2939 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002940 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2941 VoEId(_instanceId,_channelId),
2942 "GetSpeechOutputLevel() => level=%u", level);
2943 return 0;
2944}
2945
2946int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002947Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002948{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002949 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2950 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002951 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2952 VoEId(_instanceId,_channelId),
2953 "GetSpeechOutputLevelFullRange() => level=%u", level);
2954 return 0;
2955}
2956
2957int
2958Channel::SetMute(bool enable)
2959{
2960 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2961 "Channel::SetMute(enable=%d)", enable);
2962 _mute = enable;
2963 return 0;
2964}
2965
2966bool
2967Channel::Mute() const
2968{
2969 return _mute;
2970}
2971
2972int
2973Channel::SetOutputVolumePan(float left, float right)
2974{
2975 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2976 "Channel::SetOutputVolumePan()");
2977 _panLeft = left;
2978 _panRight = right;
2979 return 0;
2980}
2981
2982int
2983Channel::GetOutputVolumePan(float& left, float& right) const
2984{
2985 left = _panLeft;
2986 right = _panRight;
2987 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2988 VoEId(_instanceId,_channelId),
2989 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2990 return 0;
2991}
2992
2993int
2994Channel::SetChannelOutputVolumeScaling(float scaling)
2995{
2996 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2997 "Channel::SetChannelOutputVolumeScaling()");
2998 _outputGain = scaling;
2999 return 0;
3000}
3001
3002int
3003Channel::GetChannelOutputVolumeScaling(float& scaling) const
3004{
3005 scaling = _outputGain;
3006 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3007 VoEId(_instanceId,_channelId),
3008 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3009 return 0;
3010}
3011
niklase@google.com470e71d2011-07-07 08:21:25 +00003012int
3013Channel::RegisterExternalEncryption(Encryption& encryption)
3014{
3015 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3016 "Channel::RegisterExternalEncryption()");
3017
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003018 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003019
3020 if (_encryptionPtr)
3021 {
3022 _engineStatisticsPtr->SetLastError(
3023 VE_INVALID_OPERATION, kTraceError,
3024 "RegisterExternalEncryption() encryption already enabled");
3025 return -1;
3026 }
3027
3028 _encryptionPtr = &encryption;
3029
3030 _decrypting = true;
3031 _encrypting = true;
3032
3033 return 0;
3034}
3035
3036int
3037Channel::DeRegisterExternalEncryption()
3038{
3039 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3040 "Channel::DeRegisterExternalEncryption()");
3041
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003042 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003043
3044 if (!_encryptionPtr)
3045 {
3046 _engineStatisticsPtr->SetLastError(
3047 VE_INVALID_OPERATION, kTraceWarning,
3048 "DeRegisterExternalEncryption() encryption already disabled");
3049 return 0;
3050 }
3051
3052 _decrypting = false;
3053 _encrypting = false;
3054
3055 _encryptionPtr = NULL;
3056
3057 return 0;
3058}
3059
3060int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003061 int lengthMs, int attenuationDb,
3062 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003063{
3064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3065 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3066 playDtmfEvent);
3067
3068 _playOutbandDtmfEvent = playDtmfEvent;
3069
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003070 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003071 attenuationDb) != 0)
3072 {
3073 _engineStatisticsPtr->SetLastError(
3074 VE_SEND_DTMF_FAILED,
3075 kTraceWarning,
3076 "SendTelephoneEventOutband() failed to send event");
3077 return -1;
3078 }
3079 return 0;
3080}
3081
3082int Channel::SendTelephoneEventInband(unsigned char eventCode,
3083 int lengthMs,
3084 int attenuationDb,
3085 bool playDtmfEvent)
3086{
3087 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3088 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3089 playDtmfEvent);
3090
3091 _playInbandDtmfEvent = playDtmfEvent;
3092 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3093
3094 return 0;
3095}
3096
3097int
3098Channel::SetDtmfPlayoutStatus(bool enable)
3099{
3100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3101 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003102 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003103 {
3104 _engineStatisticsPtr->SetLastError(
3105 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3106 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3107 return -1;
3108 }
3109 return 0;
3110}
3111
3112bool
3113Channel::DtmfPlayoutStatus() const
3114{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003115 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003116}
3117
3118int
3119Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3120{
3121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3122 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003123 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003124 {
3125 _engineStatisticsPtr->SetLastError(
3126 VE_INVALID_ARGUMENT, kTraceError,
3127 "SetSendTelephoneEventPayloadType() invalid type");
3128 return -1;
3129 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003130 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003131 codec.plfreq = 8000;
3132 codec.pltype = type;
3133 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003134 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003135 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003136 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3137 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3138 _engineStatisticsPtr->SetLastError(
3139 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3140 "SetSendTelephoneEventPayloadType() failed to register send"
3141 "payload type");
3142 return -1;
3143 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003144 }
3145 _sendTelephoneEventPayloadType = type;
3146 return 0;
3147}
3148
3149int
3150Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3151{
3152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3153 "Channel::GetSendTelephoneEventPayloadType()");
3154 type = _sendTelephoneEventPayloadType;
3155 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3156 VoEId(_instanceId,_channelId),
3157 "GetSendTelephoneEventPayloadType() => type=%u", type);
3158 return 0;
3159}
3160
niklase@google.com470e71d2011-07-07 08:21:25 +00003161int
3162Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3163{
3164 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3165 "Channel::UpdateRxVadDetection()");
3166
3167 int vadDecision = 1;
3168
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003169 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003170
3171 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3172 {
3173 OnRxVadDetected(vadDecision);
3174 _oldVadDecision = vadDecision;
3175 }
3176
3177 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3178 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3179 vadDecision);
3180 return 0;
3181}
3182
3183int
3184Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3185{
3186 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3187 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003188 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003189
3190 if (_rxVadObserverPtr)
3191 {
3192 _engineStatisticsPtr->SetLastError(
3193 VE_INVALID_OPERATION, kTraceError,
3194 "RegisterRxVadObserver() observer already enabled");
3195 return -1;
3196 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003197 _rxVadObserverPtr = &observer;
3198 _RxVadDetection = true;
3199 return 0;
3200}
3201
3202int
3203Channel::DeRegisterRxVadObserver()
3204{
3205 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3206 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003207 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003208
3209 if (!_rxVadObserverPtr)
3210 {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_INVALID_OPERATION, kTraceWarning,
3213 "DeRegisterRxVadObserver() observer already disabled");
3214 return 0;
3215 }
3216 _rxVadObserverPtr = NULL;
3217 _RxVadDetection = false;
3218 return 0;
3219}
3220
3221int
3222Channel::VoiceActivityIndicator(int &activity)
3223{
3224 activity = _sendFrameType;
3225
3226 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003227 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003228 return 0;
3229}
3230
3231#ifdef WEBRTC_VOICE_ENGINE_AGC
3232
3233int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003234Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003235{
3236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3237 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3238 (int)enable, (int)mode);
3239
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003240 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003241 switch (mode)
3242 {
3243 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003244 break;
3245 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003246 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003247 break;
3248 case kAgcFixedDigital:
3249 agcMode = GainControl::kFixedDigital;
3250 break;
3251 case kAgcAdaptiveDigital:
3252 agcMode =GainControl::kAdaptiveDigital;
3253 break;
3254 default:
3255 _engineStatisticsPtr->SetLastError(
3256 VE_INVALID_ARGUMENT, kTraceError,
3257 "SetRxAgcStatus() invalid Agc mode");
3258 return -1;
3259 }
3260
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003261 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003262 {
3263 _engineStatisticsPtr->SetLastError(
3264 VE_APM_ERROR, kTraceError,
3265 "SetRxAgcStatus() failed to set Agc mode");
3266 return -1;
3267 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003268 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 {
3270 _engineStatisticsPtr->SetLastError(
3271 VE_APM_ERROR, kTraceError,
3272 "SetRxAgcStatus() failed to set Agc state");
3273 return -1;
3274 }
3275
3276 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3278
3279 return 0;
3280}
3281
3282int
3283Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3284{
3285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3286 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3287
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003288 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003289 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003290 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003291
3292 enabled = enable;
3293
3294 switch (agcMode)
3295 {
3296 case GainControl::kFixedDigital:
3297 mode = kAgcFixedDigital;
3298 break;
3299 case GainControl::kAdaptiveDigital:
3300 mode = kAgcAdaptiveDigital;
3301 break;
3302 default:
3303 _engineStatisticsPtr->SetLastError(
3304 VE_APM_ERROR, kTraceError,
3305 "GetRxAgcStatus() invalid Agc mode");
3306 return -1;
3307 }
3308
3309 return 0;
3310}
3311
3312int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003313Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003314{
3315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3316 "Channel::SetRxAgcConfig()");
3317
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003318 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003319 config.targetLeveldBOv) != 0)
3320 {
3321 _engineStatisticsPtr->SetLastError(
3322 VE_APM_ERROR, kTraceError,
3323 "SetRxAgcConfig() failed to set target peak |level|"
3324 "(or envelope) of the Agc");
3325 return -1;
3326 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003327 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003328 config.digitalCompressionGaindB) != 0)
3329 {
3330 _engineStatisticsPtr->SetLastError(
3331 VE_APM_ERROR, kTraceError,
3332 "SetRxAgcConfig() failed to set the range in |gain| the"
3333 " digital compression stage may apply");
3334 return -1;
3335 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003336 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003337 config.limiterEnable) != 0)
3338 {
3339 _engineStatisticsPtr->SetLastError(
3340 VE_APM_ERROR, kTraceError,
3341 "SetRxAgcConfig() failed to set hard limiter to the signal");
3342 return -1;
3343 }
3344
3345 return 0;
3346}
3347
3348int
3349Channel::GetRxAgcConfig(AgcConfig& config)
3350{
3351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3352 "Channel::GetRxAgcConfig(config=%?)");
3353
3354 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003355 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003356 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003357 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003358 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003359 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003360
3361 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3362 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3363 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3364 " limiterEnable=%d",
3365 config.targetLeveldBOv,
3366 config.digitalCompressionGaindB,
3367 config.limiterEnable);
3368
3369 return 0;
3370}
3371
3372#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3373
3374#ifdef WEBRTC_VOICE_ENGINE_NR
3375
3376int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003377Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003378{
3379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3380 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3381 (int)enable, (int)mode);
3382
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003383 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003384 switch (mode)
3385 {
3386
3387 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003388 break;
3389 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003390 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003391 break;
3392 case kNsConference:
3393 nsLevel = NoiseSuppression::kHigh;
3394 break;
3395 case kNsLowSuppression:
3396 nsLevel = NoiseSuppression::kLow;
3397 break;
3398 case kNsModerateSuppression:
3399 nsLevel = NoiseSuppression::kModerate;
3400 break;
3401 case kNsHighSuppression:
3402 nsLevel = NoiseSuppression::kHigh;
3403 break;
3404 case kNsVeryHighSuppression:
3405 nsLevel = NoiseSuppression::kVeryHigh;
3406 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003407 }
3408
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003409 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 != 0)
3411 {
3412 _engineStatisticsPtr->SetLastError(
3413 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003414 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003415 return -1;
3416 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003417 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003418 {
3419 _engineStatisticsPtr->SetLastError(
3420 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003421 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003422 return -1;
3423 }
3424
3425 _rxNsIsEnabled = enable;
3426 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3427
3428 return 0;
3429}
3430
3431int
3432Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3433{
3434 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3435 "Channel::GetRxNsStatus(enable=?, mode=?)");
3436
3437 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003438 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003439 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003440 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003441
3442 enabled = enable;
3443
3444 switch (ncLevel)
3445 {
3446 case NoiseSuppression::kLow:
3447 mode = kNsLowSuppression;
3448 break;
3449 case NoiseSuppression::kModerate:
3450 mode = kNsModerateSuppression;
3451 break;
3452 case NoiseSuppression::kHigh:
3453 mode = kNsHighSuppression;
3454 break;
3455 case NoiseSuppression::kVeryHigh:
3456 mode = kNsVeryHighSuppression;
3457 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003458 }
3459
3460 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3461 VoEId(_instanceId,_channelId),
3462 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3463 return 0;
3464}
3465
3466#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3467
3468int
3469Channel::RegisterRTPObserver(VoERTPObserver& observer)
3470{
3471 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3472 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003473 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003474
3475 if (_rtpObserverPtr)
3476 {
3477 _engineStatisticsPtr->SetLastError(
3478 VE_INVALID_OPERATION, kTraceError,
3479 "RegisterRTPObserver() observer already enabled");
3480 return -1;
3481 }
3482
3483 _rtpObserverPtr = &observer;
3484 _rtpObserver = true;
3485
3486 return 0;
3487}
3488
3489int
3490Channel::DeRegisterRTPObserver()
3491{
3492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3493 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003494 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003495
3496 if (!_rtpObserverPtr)
3497 {
3498 _engineStatisticsPtr->SetLastError(
3499 VE_INVALID_OPERATION, kTraceWarning,
3500 "DeRegisterRTPObserver() observer already disabled");
3501 return 0;
3502 }
3503
3504 _rtpObserver = false;
3505 _rtpObserverPtr = NULL;
3506
3507 return 0;
3508}
3509
3510int
3511Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3512{
3513 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3514 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003515 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003516
3517 if (_rtcpObserverPtr)
3518 {
3519 _engineStatisticsPtr->SetLastError(
3520 VE_INVALID_OPERATION, kTraceError,
3521 "RegisterRTCPObserver() observer already enabled");
3522 return -1;
3523 }
3524
3525 _rtcpObserverPtr = &observer;
3526 _rtcpObserver = true;
3527
3528 return 0;
3529}
3530
3531int
3532Channel::DeRegisterRTCPObserver()
3533{
3534 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3535 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003536 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003537
3538 if (!_rtcpObserverPtr)
3539 {
3540 _engineStatisticsPtr->SetLastError(
3541 VE_INVALID_OPERATION, kTraceWarning,
3542 "DeRegisterRTCPObserver() observer already disabled");
3543 return 0;
3544 }
3545
3546 _rtcpObserver = false;
3547 _rtcpObserverPtr = NULL;
3548
3549 return 0;
3550}
3551
3552int
3553Channel::SetLocalSSRC(unsigned int ssrc)
3554{
3555 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3556 "Channel::SetLocalSSRC()");
3557 if (_sending)
3558 {
3559 _engineStatisticsPtr->SetLastError(
3560 VE_ALREADY_SENDING, kTraceError,
3561 "SetLocalSSRC() already sending");
3562 return -1;
3563 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003564 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003565 {
3566 _engineStatisticsPtr->SetLastError(
3567 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3568 "SetLocalSSRC() failed to set SSRC");
3569 return -1;
3570 }
3571 return 0;
3572}
3573
3574int
3575Channel::GetLocalSSRC(unsigned int& ssrc)
3576{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003577 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003578 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3579 VoEId(_instanceId,_channelId),
3580 "GetLocalSSRC() => ssrc=%lu", ssrc);
3581 return 0;
3582}
3583
3584int
3585Channel::GetRemoteSSRC(unsigned int& ssrc)
3586{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003587 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003588 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3589 VoEId(_instanceId,_channelId),
3590 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3591 return 0;
3592}
3593
3594int
3595Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3596{
3597 if (arrCSRC == NULL)
3598 {
3599 _engineStatisticsPtr->SetLastError(
3600 VE_INVALID_ARGUMENT, kTraceError,
3601 "GetRemoteCSRCs() invalid array argument");
3602 return -1;
3603 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003604 uint32_t arrOfCSRC[kRtpCsrcSize];
3605 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003606 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003607 if (CSRCs > 0)
3608 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003609 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003610 for (int i = 0; i < (int) CSRCs; i++)
3611 {
3612 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3613 VoEId(_instanceId, _channelId),
3614 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3615 }
3616 } else
3617 {
3618 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3619 VoEId(_instanceId, _channelId),
3620 "GetRemoteCSRCs() => list is empty!");
3621 }
3622 return CSRCs;
3623}
3624
3625int
3626Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3627{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003628 if (rtp_audioproc_.get() == NULL) {
3629 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3630 _channelId)));
3631 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003632
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003633 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3634 AudioProcessing::kNoError) {
3635 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3636 "Failed to enable AudioProcessing::level_estimator()");
3637 return -1;
3638 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003639
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003640 _includeAudioLevelIndication = enable;
3641 if (enable) {
3642 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3643 ID);
3644 } else {
3645 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3646 }
3647 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003648}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003649
niklase@google.com470e71d2011-07-07 08:21:25 +00003650int
3651Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3652{
3653 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3654 VoEId(_instanceId,_channelId),
3655 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3656 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003657 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003658}
3659
3660int
3661Channel::SetRTCPStatus(bool enable)
3662{
3663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3664 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003665 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003666 kRtcpCompound : kRtcpOff) != 0)
3667 {
3668 _engineStatisticsPtr->SetLastError(
3669 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3670 "SetRTCPStatus() failed to set RTCP status");
3671 return -1;
3672 }
3673 return 0;
3674}
3675
3676int
3677Channel::GetRTCPStatus(bool& enabled)
3678{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003679 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003680 enabled = (method != kRtcpOff);
3681 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3682 VoEId(_instanceId,_channelId),
3683 "GetRTCPStatus() => enabled=%d", enabled);
3684 return 0;
3685}
3686
3687int
3688Channel::SetRTCP_CNAME(const char cName[256])
3689{
3690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3691 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003692 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003693 {
3694 _engineStatisticsPtr->SetLastError(
3695 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3696 "SetRTCP_CNAME() failed to set RTCP CNAME");
3697 return -1;
3698 }
3699 return 0;
3700}
3701
3702int
3703Channel::GetRTCP_CNAME(char cName[256])
3704{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003705 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003706 {
3707 _engineStatisticsPtr->SetLastError(
3708 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3709 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3710 return -1;
3711 }
3712 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3713 VoEId(_instanceId, _channelId),
3714 "GetRTCP_CNAME() => cName=%s", cName);
3715 return 0;
3716}
3717
3718int
3719Channel::GetRemoteRTCP_CNAME(char cName[256])
3720{
3721 if (cName == NULL)
3722 {
3723 _engineStatisticsPtr->SetLastError(
3724 VE_INVALID_ARGUMENT, kTraceError,
3725 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3726 return -1;
3727 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003728 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003729 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003730 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003731 {
3732 _engineStatisticsPtr->SetLastError(
3733 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3734 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3735 return -1;
3736 }
3737 strcpy(cName, cname);
3738 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3739 VoEId(_instanceId, _channelId),
3740 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3741 return 0;
3742}
3743
3744int
3745Channel::GetRemoteRTCPData(
3746 unsigned int& NTPHigh,
3747 unsigned int& NTPLow,
3748 unsigned int& timestamp,
3749 unsigned int& playoutTimestamp,
3750 unsigned int* jitter,
3751 unsigned short* fractionLost)
3752{
3753 // --- Information from sender info in received Sender Reports
3754
3755 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003756 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 {
3758 _engineStatisticsPtr->SetLastError(
3759 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003760 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003761 "side");
3762 return -1;
3763 }
3764
3765 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3766 // and octet count)
3767 NTPHigh = senderInfo.NTPseconds;
3768 NTPLow = senderInfo.NTPfraction;
3769 timestamp = senderInfo.RTPtimeStamp;
3770
3771 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3772 VoEId(_instanceId, _channelId),
3773 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3774 "timestamp=%lu",
3775 NTPHigh, NTPLow, timestamp);
3776
3777 // --- Locally derived information
3778
3779 // This value is updated on each incoming RTCP packet (0 when no packet
3780 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003781 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003782
3783 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3784 VoEId(_instanceId, _channelId),
3785 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003786 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003787
3788 if (NULL != jitter || NULL != fractionLost)
3789 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003790 // Get all RTCP receiver report blocks that have been received on this
3791 // channel. If we receive RTP packets from a remote source we know the
3792 // remote SSRC and use the report block from him.
3793 // Otherwise use the first report block.
3794 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003795 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003796 remote_stats.empty()) {
3797 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3798 VoEId(_instanceId, _channelId),
3799 "GetRemoteRTCPData() failed to measure statistics due"
3800 " to lack of received RTP and/or RTCP packets");
3801 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003802 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003803
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003804 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003805 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3806 for (; it != remote_stats.end(); ++it) {
3807 if (it->remoteSSRC == remoteSSRC)
3808 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003809 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003810
3811 if (it == remote_stats.end()) {
3812 // If we have not received any RTCP packets from this SSRC it probably
3813 // means that we have not received any RTP packets.
3814 // Use the first received report block instead.
3815 it = remote_stats.begin();
3816 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003817 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003818
xians@webrtc.org79af7342012-01-31 12:22:14 +00003819 if (jitter) {
3820 *jitter = it->jitter;
3821 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3822 VoEId(_instanceId, _channelId),
3823 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3824 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003825
xians@webrtc.org79af7342012-01-31 12:22:14 +00003826 if (fractionLost) {
3827 *fractionLost = it->fractionLost;
3828 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3829 VoEId(_instanceId, _channelId),
3830 "GetRemoteRTCPData() => fractionLost = %lu",
3831 *fractionLost);
3832 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003833 }
3834 return 0;
3835}
3836
3837int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003838Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003839 unsigned int name,
3840 const char* data,
3841 unsigned short dataLengthInBytes)
3842{
3843 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3844 "Channel::SendApplicationDefinedRTCPPacket()");
3845 if (!_sending)
3846 {
3847 _engineStatisticsPtr->SetLastError(
3848 VE_NOT_SENDING, kTraceError,
3849 "SendApplicationDefinedRTCPPacket() not sending");
3850 return -1;
3851 }
3852 if (NULL == data)
3853 {
3854 _engineStatisticsPtr->SetLastError(
3855 VE_INVALID_ARGUMENT, kTraceError,
3856 "SendApplicationDefinedRTCPPacket() invalid data value");
3857 return -1;
3858 }
3859 if (dataLengthInBytes % 4 != 0)
3860 {
3861 _engineStatisticsPtr->SetLastError(
3862 VE_INVALID_ARGUMENT, kTraceError,
3863 "SendApplicationDefinedRTCPPacket() invalid length value");
3864 return -1;
3865 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003866 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003867 if (status == kRtcpOff)
3868 {
3869 _engineStatisticsPtr->SetLastError(
3870 VE_RTCP_ERROR, kTraceError,
3871 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3872 return -1;
3873 }
3874
3875 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003876 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003877 subType,
3878 name,
3879 (const unsigned char*) data,
3880 dataLengthInBytes) != 0)
3881 {
3882 _engineStatisticsPtr->SetLastError(
3883 VE_SEND_ERROR, kTraceError,
3884 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3885 return -1;
3886 }
3887 return 0;
3888}
3889
3890int
3891Channel::GetRTPStatistics(
3892 unsigned int& averageJitterMs,
3893 unsigned int& maxJitterMs,
3894 unsigned int& discardedPackets)
3895{
niklase@google.com470e71d2011-07-07 08:21:25 +00003896 // The jitter statistics is updated for each received RTP packet and is
3897 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003898 StreamStatistician::Statistics statistics;
3899 StreamStatistician* statistician =
3900 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3901 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003902 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3903 _engineStatisticsPtr->SetLastError(
3904 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3905 "GetRTPStatistics() failed to read RTP statistics from the "
3906 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003907 }
3908
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003909 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003910 if (playoutFrequency > 0)
3911 {
3912 // Scale RTP statistics given the current playout frequency
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003913 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3914 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003915 }
3916
3917 discardedPackets = _numberOfDiscardedPackets;
3918
3919 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3920 VoEId(_instanceId, _channelId),
3921 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003922 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 averageJitterMs, maxJitterMs, discardedPackets);
3924 return 0;
3925}
3926
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003927int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3928 if (sender_info == NULL) {
3929 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3930 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3931 return -1;
3932 }
3933
3934 // Get the sender info from the latest received RTCP Sender Report.
3935 RTCPSenderInfo rtcp_sender_info;
3936 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3937 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3938 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3939 return -1;
3940 }
3941
3942 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3943 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3944 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3945 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3946 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3947 return 0;
3948}
3949
3950int Channel::GetRemoteRTCPReportBlocks(
3951 std::vector<ReportBlock>* report_blocks) {
3952 if (report_blocks == NULL) {
3953 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3954 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3955 return -1;
3956 }
3957
3958 // Get the report blocks from the latest received RTCP Sender or Receiver
3959 // Report. Each element in the vector contains the sender's SSRC and a
3960 // report block according to RFC 3550.
3961 std::vector<RTCPReportBlock> rtcp_report_blocks;
3962 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3963 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3964 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3965 return -1;
3966 }
3967
3968 if (rtcp_report_blocks.empty())
3969 return 0;
3970
3971 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3972 for (; it != rtcp_report_blocks.end(); ++it) {
3973 ReportBlock report_block;
3974 report_block.sender_SSRC = it->remoteSSRC;
3975 report_block.source_SSRC = it->sourceSSRC;
3976 report_block.fraction_lost = it->fractionLost;
3977 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3978 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3979 report_block.interarrival_jitter = it->jitter;
3980 report_block.last_SR_timestamp = it->lastSR;
3981 report_block.delay_since_last_SR = it->delaySinceLastSR;
3982 report_blocks->push_back(report_block);
3983 }
3984 return 0;
3985}
3986
niklase@google.com470e71d2011-07-07 08:21:25 +00003987int
3988Channel::GetRTPStatistics(CallStatistics& stats)
3989{
niklase@google.com470e71d2011-07-07 08:21:25 +00003990 // --- Part one of the final structure (four values)
3991
3992 // The jitter statistics is updated for each received RTP packet and is
3993 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003994 StreamStatistician::Statistics statistics;
3995 StreamStatistician* statistician =
3996 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3997 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003998 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3999 _engineStatisticsPtr->SetLastError(
4000 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4001 "GetRTPStatistics() failed to read RTP statistics from the "
4002 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004003 }
4004
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004005 stats.fractionLost = statistics.fraction_lost;
4006 stats.cumulativeLost = statistics.cumulative_lost;
4007 stats.extendedMax = statistics.extended_max_sequence_number;
4008 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004009
4010 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4011 VoEId(_instanceId, _channelId),
4012 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004013 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004014 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4015 stats.jitterSamples);
4016
4017 // --- Part two of the final structure (one value)
4018
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004019 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004020 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004021 if (method == kRtcpOff)
4022 {
4023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4024 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004025 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004026 "measurements cannot be retrieved");
4027 } else
4028 {
4029 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004030 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004031 if (remoteSSRC > 0)
4032 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004033 uint16_t avgRTT(0);
4034 uint16_t maxRTT(0);
4035 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004036
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004037 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004038 != 0)
4039 {
4040 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4041 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004042 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004043 "the RTP/RTCP module");
4044 }
4045 } else
4046 {
4047 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4048 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004049 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004050 "RTP packets have been received yet");
4051 }
4052 }
4053
4054 stats.rttMs = static_cast<int> (RTT);
4055
4056 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4057 VoEId(_instanceId, _channelId),
4058 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4059
4060 // --- Part three of the final structure (four values)
4061
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004062 uint32_t bytesSent(0);
4063 uint32_t packetsSent(0);
4064 uint32_t bytesReceived(0);
4065 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004066
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004067 if (statistician) {
4068 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4069 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004070
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004071 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004072 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004073 {
4074 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4075 VoEId(_instanceId, _channelId),
4076 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004077 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004078 }
4079
4080 stats.bytesSent = bytesSent;
4081 stats.packetsSent = packetsSent;
4082 stats.bytesReceived = bytesReceived;
4083 stats.packetsReceived = packetsReceived;
4084
4085 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4086 VoEId(_instanceId, _channelId),
4087 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004088 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004089 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4090 stats.packetsReceived);
4091
4092 return 0;
4093}
4094
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004095int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4096 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4097 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004098
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004099 if (enable) {
4100 if (redPayloadtype < 0 || redPayloadtype > 127) {
4101 _engineStatisticsPtr->SetLastError(
4102 VE_PLTYPE_ERROR, kTraceError,
4103 "SetFECStatus() invalid RED payload type");
4104 return -1;
4105 }
4106
4107 if (SetRedPayloadType(redPayloadtype) < 0) {
4108 _engineStatisticsPtr->SetLastError(
4109 VE_CODEC_ERROR, kTraceError,
4110 "SetSecondarySendCodec() Failed to register RED ACM");
4111 return -1;
4112 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004113 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004114
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004115 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004116 _engineStatisticsPtr->SetLastError(
4117 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4118 "SetFECStatus() failed to set FEC state in the ACM");
4119 return -1;
4120 }
4121 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004122}
4123
4124int
4125Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4126{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004127 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004128 if (enabled)
4129 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004130 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004131 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004132 {
4133 _engineStatisticsPtr->SetLastError(
4134 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4135 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4136 "module");
4137 return -1;
4138 }
4139 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4140 VoEId(_instanceId, _channelId),
4141 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4142 enabled, redPayloadtype);
4143 return 0;
4144 }
4145 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4146 VoEId(_instanceId, _channelId),
4147 "GetFECStatus() => enabled=%d", enabled);
4148 return 0;
4149}
4150
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004151void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4152 // None of these functions can fail.
4153 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004154 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4155 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004156 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004157 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004158 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004159 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004160}
4161
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004162// Called when we are missing one or more packets.
4163int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004164 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4165}
4166
niklase@google.com470e71d2011-07-07 08:21:25 +00004167int
niklase@google.com470e71d2011-07-07 08:21:25 +00004168Channel::StartRTPDump(const char fileNameUTF8[1024],
4169 RTPDirections direction)
4170{
4171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4172 "Channel::StartRTPDump()");
4173 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4174 {
4175 _engineStatisticsPtr->SetLastError(
4176 VE_INVALID_ARGUMENT, kTraceError,
4177 "StartRTPDump() invalid RTP direction");
4178 return -1;
4179 }
4180 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4181 &_rtpDumpIn : &_rtpDumpOut;
4182 if (rtpDumpPtr == NULL)
4183 {
4184 assert(false);
4185 return -1;
4186 }
4187 if (rtpDumpPtr->IsActive())
4188 {
4189 rtpDumpPtr->Stop();
4190 }
4191 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4192 {
4193 _engineStatisticsPtr->SetLastError(
4194 VE_BAD_FILE, kTraceError,
4195 "StartRTPDump() failed to create file");
4196 return -1;
4197 }
4198 return 0;
4199}
4200
4201int
4202Channel::StopRTPDump(RTPDirections direction)
4203{
4204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4205 "Channel::StopRTPDump()");
4206 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4207 {
4208 _engineStatisticsPtr->SetLastError(
4209 VE_INVALID_ARGUMENT, kTraceError,
4210 "StopRTPDump() invalid RTP direction");
4211 return -1;
4212 }
4213 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4214 &_rtpDumpIn : &_rtpDumpOut;
4215 if (rtpDumpPtr == NULL)
4216 {
4217 assert(false);
4218 return -1;
4219 }
4220 if (!rtpDumpPtr->IsActive())
4221 {
4222 return 0;
4223 }
4224 return rtpDumpPtr->Stop();
4225}
4226
4227bool
4228Channel::RTPDumpIsActive(RTPDirections direction)
4229{
4230 if ((direction != kRtpIncoming) &&
4231 (direction != kRtpOutgoing))
4232 {
4233 _engineStatisticsPtr->SetLastError(
4234 VE_INVALID_ARGUMENT, kTraceError,
4235 "RTPDumpIsActive() invalid RTP direction");
4236 return false;
4237 }
4238 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4239 &_rtpDumpIn : &_rtpDumpOut;
4240 return rtpDumpPtr->IsActive();
4241}
4242
4243int
4244Channel::InsertExtraRTPPacket(unsigned char payloadType,
4245 bool markerBit,
4246 const char* payloadData,
4247 unsigned short payloadSize)
4248{
4249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4250 "Channel::InsertExtraRTPPacket()");
4251 if (payloadType > 127)
4252 {
4253 _engineStatisticsPtr->SetLastError(
4254 VE_INVALID_PLTYPE, kTraceError,
4255 "InsertExtraRTPPacket() invalid payload type");
4256 return -1;
4257 }
4258 if (payloadData == NULL)
4259 {
4260 _engineStatisticsPtr->SetLastError(
4261 VE_INVALID_ARGUMENT, kTraceError,
4262 "InsertExtraRTPPacket() invalid payload data");
4263 return -1;
4264 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004265 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004266 {
4267 _engineStatisticsPtr->SetLastError(
4268 VE_INVALID_ARGUMENT, kTraceError,
4269 "InsertExtraRTPPacket() invalid payload size");
4270 return -1;
4271 }
4272 if (!_sending)
4273 {
4274 _engineStatisticsPtr->SetLastError(
4275 VE_NOT_SENDING, kTraceError,
4276 "InsertExtraRTPPacket() not sending");
4277 return -1;
4278 }
4279
4280 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4281 // Transport::SendPacket() will be called by the module when the RTP packet
4282 // is created.
4283 // The call to SendOutgoingData() does *not* modify the timestamp and
4284 // payloadtype to ensure that the RTP module generates a valid RTP packet
4285 // (user might utilize a non-registered payload type).
4286 // The marker bit and payload type will be replaced just before the actual
4287 // transmission, i.e., the actual modification is done *after* the RTP
4288 // module has delivered its RTP packet back to the VoE.
4289 // We will use the stored values above when the packet is modified
4290 // (see Channel::SendPacket()).
4291
4292 _extraPayloadType = payloadType;
4293 _extraMarkerBit = markerBit;
4294 _insertExtraRTPPacket = true;
4295
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004296 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004297 _lastPayloadType,
4298 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004299 // Leaving the time when this frame was
4300 // received from the capture device as
4301 // undefined for voice for now.
4302 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004303 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004304 payloadSize) != 0)
4305 {
4306 _engineStatisticsPtr->SetLastError(
4307 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4308 "InsertExtraRTPPacket() failed to send extra RTP packet");
4309 return -1;
4310 }
4311
4312 return 0;
4313}
4314
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004315uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004316Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004317{
4318 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004319 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004320 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004321 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004322 return 0;
4323}
4324
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004325// TODO(xians): This method borrows quite some code from
4326// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4327// code duplication.
4328void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004329 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004330 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004331 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004332 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4333 static const int kMaxNumberOfFrames = 960;
4334 assert(number_of_frames <= kMaxNumberOfFrames);
4335
4336 // Get the send codec information for doing resampling or downmixing later on.
4337 CodecInst codec;
4338 GetSendCodec(codec);
4339 assert(codec.channels == 1 || codec.channels == 2);
4340 int support_sample_rate = std::min(32000,
4341 std::min(sample_rate, codec.plfreq));
4342
4343 // Downmix the data to mono if needed.
4344 const int16_t* audio_ptr = audio_data;
4345 if (number_of_channels == 2 && codec.channels == 1) {
4346 if (!mono_recording_audio_.get())
4347 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4348
4349 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4350 mono_recording_audio_.get());
4351 audio_ptr = mono_recording_audio_.get();
4352 }
4353
4354 // Resample the data to the sample rate that the codec is using.
4355 if (input_resampler_.InitializeIfNeeded(sample_rate,
4356 support_sample_rate,
4357 codec.channels)) {
4358 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4359 "Channel::Demultiplex() unable to resample");
4360 return;
4361 }
4362
4363 int out_length = input_resampler_.Resample(audio_ptr,
4364 number_of_frames * codec.channels,
4365 _audioFrame.data_,
4366 AudioFrame::kMaxDataSizeSamples);
4367 if (out_length == -1) {
4368 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4369 "Channel::Demultiplex() resampling failed");
4370 return;
4371 }
4372
4373 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4374 _audioFrame.timestamp_ = -1;
4375 _audioFrame.sample_rate_hz_ = support_sample_rate;
4376 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4377 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4378 _audioFrame.num_channels_ = codec.channels;
4379 _audioFrame.id_ = _channelId;
4380}
4381
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004382uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004383Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004384{
4385 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4386 "Channel::PrepareEncodeAndSend()");
4387
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004388 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004389 {
4390 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4391 "Channel::PrepareEncodeAndSend() invalid audio frame");
4392 return -1;
4393 }
4394
4395 if (_inputFilePlaying)
4396 {
4397 MixOrReplaceAudioWithFile(mixingFrequency);
4398 }
4399
4400 if (_mute)
4401 {
4402 AudioFrameOperations::Mute(_audioFrame);
4403 }
4404
4405 if (_inputExternalMedia)
4406 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004407 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004408 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004409 if (_inputExternalMediaCallbackPtr)
4410 {
4411 _inputExternalMediaCallbackPtr->Process(
4412 _channelId,
4413 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004414 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004415 _audioFrame.samples_per_channel_,
4416 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004417 isStereo);
4418 }
4419 }
4420
4421 InsertInbandDtmfTone();
4422
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004423 if (_includeAudioLevelIndication)
4424 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004425 if (rtp_audioproc_->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4426 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004427 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004428 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4429 VoEId(_instanceId, _channelId),
4430 "Error setting AudioProcessing sample rate");
4431 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004432 }
4433
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004434 if (rtp_audioproc_->set_num_channels(_audioFrame.num_channels_,
4435 _audioFrame.num_channels_) !=
4436 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004437 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004438 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4439 VoEId(_instanceId, _channelId),
4440 "Error setting AudioProcessing channels");
4441 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004442 }
4443
4444 // Performs level analysis only; does not affect the signal.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004445 rtp_audioproc_->ProcessStream(&_audioFrame);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004446 }
4447
niklase@google.com470e71d2011-07-07 08:21:25 +00004448 return 0;
4449}
4450
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004451uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004452Channel::EncodeAndSend()
4453{
4454 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4455 "Channel::EncodeAndSend()");
4456
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004457 assert(_audioFrame.num_channels_ <= 2);
4458 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004459 {
4460 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4461 "Channel::EncodeAndSend() invalid audio frame");
4462 return -1;
4463 }
4464
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004465 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004466
4467 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4468
4469 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004470 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004471 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004472 {
4473 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4474 "Channel::EncodeAndSend() ACM encoding failed");
4475 return -1;
4476 }
4477
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004478 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004479
4480 // --- Encode if complete frame is ready
4481
4482 // This call will trigger AudioPacketizationCallback::SendData if encoding
4483 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004484 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004485}
4486
4487int Channel::RegisterExternalMediaProcessing(
4488 ProcessingTypes type,
4489 VoEMediaProcess& processObject)
4490{
4491 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4492 "Channel::RegisterExternalMediaProcessing()");
4493
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004494 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004495
4496 if (kPlaybackPerChannel == type)
4497 {
4498 if (_outputExternalMediaCallbackPtr)
4499 {
4500 _engineStatisticsPtr->SetLastError(
4501 VE_INVALID_OPERATION, kTraceError,
4502 "Channel::RegisterExternalMediaProcessing() "
4503 "output external media already enabled");
4504 return -1;
4505 }
4506 _outputExternalMediaCallbackPtr = &processObject;
4507 _outputExternalMedia = true;
4508 }
4509 else if (kRecordingPerChannel == type)
4510 {
4511 if (_inputExternalMediaCallbackPtr)
4512 {
4513 _engineStatisticsPtr->SetLastError(
4514 VE_INVALID_OPERATION, kTraceError,
4515 "Channel::RegisterExternalMediaProcessing() "
4516 "output external media already enabled");
4517 return -1;
4518 }
4519 _inputExternalMediaCallbackPtr = &processObject;
4520 _inputExternalMedia = true;
4521 }
4522 return 0;
4523}
4524
4525int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4526{
4527 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4528 "Channel::DeRegisterExternalMediaProcessing()");
4529
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004530 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004531
4532 if (kPlaybackPerChannel == type)
4533 {
4534 if (!_outputExternalMediaCallbackPtr)
4535 {
4536 _engineStatisticsPtr->SetLastError(
4537 VE_INVALID_OPERATION, kTraceWarning,
4538 "Channel::DeRegisterExternalMediaProcessing() "
4539 "output external media already disabled");
4540 return 0;
4541 }
4542 _outputExternalMedia = false;
4543 _outputExternalMediaCallbackPtr = NULL;
4544 }
4545 else if (kRecordingPerChannel == type)
4546 {
4547 if (!_inputExternalMediaCallbackPtr)
4548 {
4549 _engineStatisticsPtr->SetLastError(
4550 VE_INVALID_OPERATION, kTraceWarning,
4551 "Channel::DeRegisterExternalMediaProcessing() "
4552 "input external media already disabled");
4553 return 0;
4554 }
4555 _inputExternalMedia = false;
4556 _inputExternalMediaCallbackPtr = NULL;
4557 }
4558
4559 return 0;
4560}
4561
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004562int Channel::SetExternalMixing(bool enabled) {
4563 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4564 "Channel::SetExternalMixing(enabled=%d)", enabled);
4565
4566 if (_playing)
4567 {
4568 _engineStatisticsPtr->SetLastError(
4569 VE_INVALID_OPERATION, kTraceError,
4570 "Channel::SetExternalMixing() "
4571 "external mixing cannot be changed while playing.");
4572 return -1;
4573 }
4574
4575 _externalMixing = enabled;
4576
4577 return 0;
4578}
4579
niklase@google.com470e71d2011-07-07 08:21:25 +00004580int
4581Channel::ResetRTCPStatistics()
4582{
4583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4584 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004585 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004586 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004587 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004588}
4589
4590int
4591Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4592{
4593 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4594 "Channel::GetRoundTripTimeSummary()");
4595 // Override default module outputs for the case when RTCP is disabled.
4596 // This is done to ensure that we are backward compatible with the
4597 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004598 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004599 {
4600 delaysMs.min = -1;
4601 delaysMs.max = -1;
4602 delaysMs.average = -1;
4603 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4604 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4605 " valid RTT measurements cannot be retrieved");
4606 return 0;
4607 }
4608
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004609 uint32_t remoteSSRC;
4610 uint16_t RTT;
4611 uint16_t avgRTT;
4612 uint16_t maxRTT;
4613 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004614 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004615 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004616 if (remoteSSRC == 0)
4617 {
4618 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4619 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4620 " since no RTP packet has been received yet");
4621 }
4622
4623 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4624 // channel and SSRC. The SSRC is required to parse out the correct source
4625 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004626 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004627 {
4628 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4629 "GetRoundTripTimeSummary unable to retrieve RTT values"
4630 " from the RTCP layer");
4631 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4632 }
4633 else
4634 {
4635 delaysMs.min = minRTT;
4636 delaysMs.max = maxRTT;
4637 delaysMs.average = avgRTT;
4638 }
4639 return 0;
4640}
4641
4642int
4643Channel::GetNetworkStatistics(NetworkStatistics& stats)
4644{
4645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4646 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004647 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004648 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004649 if (return_value >= 0) {
4650 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4651 }
4652 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004653}
4654
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004655bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4656 int* playout_buffer_delay_ms) const {
4657 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004658 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004659 "Channel::GetDelayEstimate() no valid estimate.");
4660 return false;
4661 }
4662 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4663 _recPacketDelayMs;
4664 *playout_buffer_delay_ms = playout_delay_ms_;
4665 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4666 "Channel::GetDelayEstimate()");
4667 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004668}
4669
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004670int Channel::SetInitialPlayoutDelay(int delay_ms)
4671{
4672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4673 "Channel::SetInitialPlayoutDelay()");
4674 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4675 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4676 {
4677 _engineStatisticsPtr->SetLastError(
4678 VE_INVALID_ARGUMENT, kTraceError,
4679 "SetInitialPlayoutDelay() invalid min delay");
4680 return -1;
4681 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004682 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004683 {
4684 _engineStatisticsPtr->SetLastError(
4685 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4686 "SetInitialPlayoutDelay() failed to set min playout delay");
4687 return -1;
4688 }
4689 return 0;
4690}
4691
4692
niklase@google.com470e71d2011-07-07 08:21:25 +00004693int
4694Channel::SetMinimumPlayoutDelay(int delayMs)
4695{
4696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4697 "Channel::SetMinimumPlayoutDelay()");
4698 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4699 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4700 {
4701 _engineStatisticsPtr->SetLastError(
4702 VE_INVALID_ARGUMENT, kTraceError,
4703 "SetMinimumPlayoutDelay() invalid min delay");
4704 return -1;
4705 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004706 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004707 {
4708 _engineStatisticsPtr->SetLastError(
4709 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4710 "SetMinimumPlayoutDelay() failed to set min playout delay");
4711 return -1;
4712 }
4713 return 0;
4714}
4715
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004716void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4717 uint32_t playout_timestamp = 0;
4718
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004719 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004720 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4721 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4722 " timestamp from the ACM");
4723 _engineStatisticsPtr->SetLastError(
4724 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4725 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4726 return;
4727 }
4728
4729 uint16_t delay_ms = 0;
4730 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4731 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4732 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4733 " delay from the ADM");
4734 _engineStatisticsPtr->SetLastError(
4735 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4736 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4737 return;
4738 }
4739
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004740 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004741 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004742 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004743 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4744 playout_frequency = 8000;
4745 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4746 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004747 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004748 }
4749
4750 // Remove the playout delay.
4751 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4752
4753 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4754 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4755 playout_timestamp);
4756
4757 if (rtcp) {
4758 playout_timestamp_rtcp_ = playout_timestamp;
4759 } else {
4760 playout_timestamp_rtp_ = playout_timestamp;
4761 }
4762 playout_delay_ms_ = delay_ms;
4763}
4764
4765int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4766 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4767 "Channel::GetPlayoutTimestamp()");
4768 if (playout_timestamp_rtp_ == 0) {
4769 _engineStatisticsPtr->SetLastError(
4770 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4771 "GetPlayoutTimestamp() failed to retrieve timestamp");
4772 return -1;
4773 }
4774 timestamp = playout_timestamp_rtp_;
4775 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4776 VoEId(_instanceId,_channelId),
4777 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4778 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004779}
4780
4781int
4782Channel::SetInitTimestamp(unsigned int timestamp)
4783{
4784 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4785 "Channel::SetInitTimestamp()");
4786 if (_sending)
4787 {
4788 _engineStatisticsPtr->SetLastError(
4789 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4790 return -1;
4791 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004792 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004793 {
4794 _engineStatisticsPtr->SetLastError(
4795 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4796 "SetInitTimestamp() failed to set timestamp");
4797 return -1;
4798 }
4799 return 0;
4800}
4801
4802int
4803Channel::SetInitSequenceNumber(short sequenceNumber)
4804{
4805 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4806 "Channel::SetInitSequenceNumber()");
4807 if (_sending)
4808 {
4809 _engineStatisticsPtr->SetLastError(
4810 VE_SENDING, kTraceError,
4811 "SetInitSequenceNumber() already sending");
4812 return -1;
4813 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004814 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004815 {
4816 _engineStatisticsPtr->SetLastError(
4817 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4818 "SetInitSequenceNumber() failed to set sequence number");
4819 return -1;
4820 }
4821 return 0;
4822}
4823
4824int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004825Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004826{
4827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4828 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004829 *rtpRtcpModule = _rtpRtcpModule.get();
4830 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004831 return 0;
4832}
4833
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004834// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4835// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004836int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004837Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004838{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004839 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004840 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004841
4842 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004843 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004844
4845 if (_inputFilePlayerPtr == NULL)
4846 {
4847 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4848 VoEId(_instanceId, _channelId),
4849 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4850 " doesnt exist");
4851 return -1;
4852 }
4853
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004854 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004855 fileSamples,
4856 mixingFrequency) == -1)
4857 {
4858 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4859 VoEId(_instanceId, _channelId),
4860 "Channel::MixOrReplaceAudioWithFile() file mixing "
4861 "failed");
4862 return -1;
4863 }
4864 if (fileSamples == 0)
4865 {
4866 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4867 VoEId(_instanceId, _channelId),
4868 "Channel::MixOrReplaceAudioWithFile() file is ended");
4869 return 0;
4870 }
4871 }
4872
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004873 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004874
4875 if (_mixFileWithMicrophone)
4876 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004877 // Currently file stream is always mono.
4878 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004879 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004880 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004881 fileBuffer.get(),
4882 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004883 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004884 }
4885 else
4886 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004887 // Replace ACM audio with file.
4888 // Currently file stream is always mono.
4889 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004890 _audioFrame.UpdateFrame(_channelId,
4891 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004892 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004893 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004894 mixingFrequency,
4895 AudioFrame::kNormalSpeech,
4896 AudioFrame::kVadUnknown,
4897 1);
4898
4899 }
4900 return 0;
4901}
4902
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004903int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004904Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004905 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004906{
4907 assert(mixingFrequency <= 32000);
4908
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004909 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004910 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004911
4912 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004913 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004914
4915 if (_outputFilePlayerPtr == NULL)
4916 {
4917 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4918 VoEId(_instanceId, _channelId),
4919 "Channel::MixAudioWithFile() file mixing failed");
4920 return -1;
4921 }
4922
4923 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004924 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004925 fileSamples,
4926 mixingFrequency) == -1)
4927 {
4928 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4929 VoEId(_instanceId, _channelId),
4930 "Channel::MixAudioWithFile() file mixing failed");
4931 return -1;
4932 }
4933 }
4934
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004935 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004936 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004937 // Currently file stream is always mono.
4938 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004939 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004940 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004941 fileBuffer.get(),
4942 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004943 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004944 }
4945 else
4946 {
4947 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004948 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004949 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004950 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004951 return -1;
4952 }
4953
4954 return 0;
4955}
4956
4957int
4958Channel::InsertInbandDtmfTone()
4959{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004960 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004961 if (_inbandDtmfQueue.PendingDtmf() &&
4962 !_inbandDtmfGenerator.IsAddingTone() &&
4963 _inbandDtmfGenerator.DelaySinceLastTone() >
4964 kMinTelephoneEventSeparationMs)
4965 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004966 int8_t eventCode(0);
4967 uint16_t lengthMs(0);
4968 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004969
4970 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4971 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4972 if (_playInbandDtmfEvent)
4973 {
4974 // Add tone to output mixer using a reduced length to minimize
4975 // risk of echo.
4976 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4977 attenuationDb);
4978 }
4979 }
4980
4981 if (_inbandDtmfGenerator.IsAddingTone())
4982 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004983 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004984 _inbandDtmfGenerator.GetSampleRate(frequency);
4985
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004986 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004987 {
4988 // Update sample rate of Dtmf tone since the mixing frequency
4989 // has changed.
4990 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004991 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004992 // Reset the tone to be added taking the new sample rate into
4993 // account.
4994 _inbandDtmfGenerator.ResetTone();
4995 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004996
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004997 int16_t toneBuffer[320];
4998 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004999 // Get 10ms tone segment and set time since last tone to zero
5000 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5001 {
5002 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5003 VoEId(_instanceId, _channelId),
5004 "Channel::EncodeAndSend() inserting Dtmf failed");
5005 return -1;
5006 }
5007
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005008 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005009 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005010 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005011 sample++)
5012 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005013 for (int channel = 0;
5014 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005015 channel++)
5016 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005017 const int index = sample * _audioFrame.num_channels_ + channel;
5018 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005019 }
5020 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005021
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005022 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005023 } else
5024 {
5025 // Add 10ms to "delay-since-last-tone" counter
5026 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5027 }
5028 return 0;
5029}
5030
niklase@google.com470e71d2011-07-07 08:21:25 +00005031void
5032Channel::ResetDeadOrAliveCounters()
5033{
5034 _countDeadDetections = 0;
5035 _countAliveDetections = 0;
5036}
5037
5038void
5039Channel::UpdateDeadOrAliveCounters(bool alive)
5040{
5041 if (alive)
5042 _countAliveDetections++;
5043 else
5044 _countDeadDetections++;
5045}
5046
5047int
5048Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5049{
niklase@google.com470e71d2011-07-07 08:21:25 +00005050 return 0;
5051}
5052
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005053int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005054Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5055{
5056 if (_transportPtr == NULL)
5057 {
5058 return -1;
5059 }
5060 if (!RTCP)
5061 {
5062 return _transportPtr->SendPacket(_channelId, data, len);
5063 }
5064 else
5065 {
5066 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5067 }
5068}
5069
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005070// Called for incoming RTP packets after successful RTP header parsing.
5071void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5072 uint16_t sequence_number) {
5073 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5074 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5075 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005076
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005077 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005078 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005079
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005080 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005081 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005082 return;
5083 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005084
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005085 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005086 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005087
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005088 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5089 // Even though the actual sampling rate for G.722 audio is
5090 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5091 // 8,000 Hz because that value was erroneously assigned in
5092 // RFC 1890 and must remain unchanged for backward compatibility.
5093 rtp_receive_frequency = 8000;
5094 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5095 // We are resampling Opus internally to 32,000 Hz until all our
5096 // DSP routines can operate at 48,000 Hz, but the RTP clock
5097 // rate for the Opus payload format is standardized to 48,000 Hz,
5098 // because that is the maximum supported decoding sampling rate.
5099 rtp_receive_frequency = 48000;
5100 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005101
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005102 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5103 // packet.
5104 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5105 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005106
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005107 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5108 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005109
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005110 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005111
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005112 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5113 timestamp_diff_ms = 0;
5114 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005115
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005116 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005117
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005118 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5119 _recPacketDelayMs = packet_delay_ms;
5120 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005121
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005122 if (_average_jitter_buffer_delay_us == 0) {
5123 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5124 return;
5125 }
5126
5127 // Filter average delay value using exponential filter (alpha is
5128 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5129 // risk of rounding error) and compensate for it in GetDelayEstimate()
5130 // later.
5131 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5132 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005133}
5134
5135void
5136Channel::RegisterReceiveCodecsToRTPModule()
5137{
5138 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5139 "Channel::RegisterReceiveCodecsToRTPModule()");
5140
5141
5142 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005143 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005144
5145 for (int idx = 0; idx < nSupportedCodecs; idx++)
5146 {
5147 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005148 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005149 (rtp_receiver_->RegisterReceivePayload(
5150 codec.plname,
5151 codec.pltype,
5152 codec.plfreq,
5153 codec.channels,
5154 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005155 {
5156 WEBRTC_TRACE(
5157 kTraceWarning,
5158 kTraceVoice,
5159 VoEId(_instanceId, _channelId),
5160 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5161 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5162 codec.plname, codec.pltype, codec.plfreq,
5163 codec.channels, codec.rate);
5164 }
5165 else
5166 {
5167 WEBRTC_TRACE(
5168 kTraceInfo,
5169 kTraceVoice,
5170 VoEId(_instanceId, _channelId),
5171 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005172 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005173 "receiver",
5174 codec.plname, codec.pltype, codec.plfreq,
5175 codec.channels, codec.rate);
5176 }
5177 }
5178}
5179
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005180int Channel::ApmProcessRx(AudioFrame& frame) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005181 // Register the (possibly new) frame parameters.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005182 if (rx_audioproc_->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005183 assert(false);
5184 LOG_FERR1(LS_ERROR, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005185 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005186 if (rx_audioproc_->set_num_channels(frame.num_channels_,
5187 frame.num_channels_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005188 assert(false);
5189 LOG_FERR2(LS_ERROR, set_num_channels, frame.num_channels_,
5190 frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005191 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005192 if (rx_audioproc_->ProcessStream(&frame) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005193 assert(false);
5194 LOG_FERR0(LS_ERROR, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005195 }
5196 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005197}
5198
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005199int Channel::SetSecondarySendCodec(const CodecInst& codec,
5200 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005201 // Sanity check for payload type.
5202 if (red_payload_type < 0 || red_payload_type > 127) {
5203 _engineStatisticsPtr->SetLastError(
5204 VE_PLTYPE_ERROR, kTraceError,
5205 "SetRedPayloadType() invalid RED payload type");
5206 return -1;
5207 }
5208
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005209 if (SetRedPayloadType(red_payload_type) < 0) {
5210 _engineStatisticsPtr->SetLastError(
5211 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5212 "SetSecondarySendCodec() Failed to register RED ACM");
5213 return -1;
5214 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005215 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005216 _engineStatisticsPtr->SetLastError(
5217 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5218 "SetSecondarySendCodec() Failed to register secondary send codec in "
5219 "ACM");
5220 return -1;
5221 }
5222
5223 return 0;
5224}
5225
5226void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005227 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005228}
5229
5230int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005231 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005232 _engineStatisticsPtr->SetLastError(
5233 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5234 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5235 return -1;
5236 }
5237 return 0;
5238}
5239
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005240// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005241int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005242 CodecInst codec;
5243 bool found_red = false;
5244
5245 // Get default RED settings from the ACM database
5246 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5247 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005248 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005249 if (!STR_CASE_CMP(codec.plname, "RED")) {
5250 found_red = true;
5251 break;
5252 }
5253 }
5254
5255 if (!found_red) {
5256 _engineStatisticsPtr->SetLastError(
5257 VE_CODEC_ERROR, kTraceError,
5258 "SetRedPayloadType() RED is not supported");
5259 return -1;
5260 }
5261
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005262 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005263 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005264 _engineStatisticsPtr->SetLastError(
5265 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5266 "SetRedPayloadType() RED registration in ACM module failed");
5267 return -1;
5268 }
5269
5270 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5271 _engineStatisticsPtr->SetLastError(
5272 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5273 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5274 return -1;
5275 }
5276 return 0;
5277}
5278
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005279} // namespace voe
5280} // namespace webrtc