blob: 5cb2ac36178233f3bd91db89d476368ae8b1f40d [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000013#include "webrtc/modules/audio_device/include/audio_device.h"
14#include "webrtc/modules/audio_processing/include/audio_processing.h"
15#include "webrtc/modules/utility/interface/audio_frame_operations.h"
16#include "webrtc/modules/utility/interface/process_thread.h"
17#include "webrtc/modules/utility/interface/rtp_dump.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/logging.h"
20#include "webrtc/system_wrappers/interface/trace.h"
21#include "webrtc/voice_engine/include/voe_base.h"
22#include "webrtc/voice_engine/include/voe_external_media.h"
23#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
24#include "webrtc/voice_engine/output_mixer.h"
25#include "webrtc/voice_engine/statistics.h"
26#include "webrtc/voice_engine/transmit_mixer.h"
27#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000028
29#if defined(_WIN32)
30#include <Qos.h>
31#endif
32
andrew@webrtc.org50419b02012-11-14 19:07:54 +000033namespace webrtc {
34namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000035
pbos@webrtc.org6141e132013-04-09 10:09:10 +000036int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000037Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000038 uint8_t payloadType,
39 uint32_t timeStamp,
40 const uint8_t* payloadData,
41 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000042 const RTPFragmentationHeader* fragmentation)
43{
44 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
45 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
46 " payloadSize=%u, fragmentation=0x%x)",
47 frameType, payloadType, timeStamp, payloadSize, fragmentation);
48
49 if (_includeAudioLevelIndication)
50 {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000051 assert(_rtpAudioProc.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000052 // Store current audio level in the RTP/RTCP module.
53 // The level will be used in combination with voice-activity state
54 // (frameType) to add an RTP header extension
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000055 _rtpRtcpModule->SetAudioLevel(_rtpAudioProc->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000056 }
57
58 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
59 // packetization.
60 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000061 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000062 payloadType,
63 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000064 // Leaving the time when this frame was
65 // received from the capture device as
66 // undefined for voice for now.
67 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000068 payloadData,
69 payloadSize,
70 fragmentation) == -1)
71 {
72 _engineStatisticsPtr->SetLastError(
73 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
74 "Channel::SendData() failed to send data to RTP/RTCP module");
75 return -1;
76 }
77
78 _lastLocalTimeStamp = timeStamp;
79 _lastPayloadType = payloadType;
80
81 return 0;
82}
83
pbos@webrtc.org6141e132013-04-09 10:09:10 +000084int32_t
85Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +000086{
87 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
88 "Channel::InFrameType(frameType=%d)", frameType);
89
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000090 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000091 // 1 indicates speech
92 _sendFrameType = (frameType == 1) ? 1 : 0;
93 return 0;
94}
95
pbos@webrtc.org6141e132013-04-09 10:09:10 +000096int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +000097Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +000098{
99 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
100 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
101
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000102 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000103 if (_rxVadObserverPtr)
104 {
105 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
106 }
107
108 return 0;
109}
110
111int
112Channel::SendPacket(int channel, const void *data, int len)
113{
114 channel = VoEChannelId(channel);
115 assert(channel == _channelId);
116
117 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
118 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
119
120 if (_transportPtr == NULL)
121 {
122 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
123 "Channel::SendPacket() failed to send RTP packet due to"
124 " invalid transport object");
125 return -1;
126 }
127
128 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
129 // API
130 if (_insertExtraRTPPacket)
131 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000132 uint8_t* rtpHdr = (uint8_t*)data;
133 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 if (_extraMarkerBit)
135 {
136 M_PT = 0x80; // set the M-bit
137 }
138 M_PT += _extraPayloadType; // set the payload type
139 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
140 _insertExtraRTPPacket = false; // insert one packet only
141 }
142
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000143 uint8_t* bufferToSendPtr = (uint8_t*)data;
144 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000145
146 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 {
149 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
150 VoEId(_instanceId,_channelId),
151 "Channel::SendPacket() RTP dump to output file failed");
152 }
153
154 // SRTP or External encryption
155 if (_encrypting)
156 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000157 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 if (_encryptionPtr)
160 {
161 if (!_encryptionRTPBufferPtr)
162 {
163 // Allocate memory for encryption buffer one time only
164 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000165 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000166 memset(_encryptionRTPBufferPtr, 0,
167 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 }
169
170 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000171 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 _encryptionPtr->encrypt(_channelId,
173 bufferToSendPtr,
174 _encryptionRTPBufferPtr,
175 bufferLength,
176 (int*)&encryptedBufferLength);
177 if (encryptedBufferLength <= 0)
178 {
179 _engineStatisticsPtr->SetLastError(
180 VE_ENCRYPTION_FAILED,
181 kTraceError, "Channel::SendPacket() encryption failed");
182 return -1;
183 }
184
185 // Replace default data buffer with encrypted buffer
186 bufferToSendPtr = _encryptionRTPBufferPtr;
187 bufferLength = encryptedBufferLength;
188 }
189 }
190
191 // Packet transmission using WebRtc socket transport
192 if (!_externalTransport)
193 {
194 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
195 bufferLength);
196 if (n < 0)
197 {
198 WEBRTC_TRACE(kTraceError, kTraceVoice,
199 VoEId(_instanceId,_channelId),
200 "Channel::SendPacket() RTP transmission using WebRtc"
201 " sockets failed");
202 return -1;
203 }
204 return n;
205 }
206
207 // Packet transmission using external transport transport
208 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000209 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000210
211 int n = _transportPtr->SendPacket(channel,
212 bufferToSendPtr,
213 bufferLength);
214 if (n < 0)
215 {
216 WEBRTC_TRACE(kTraceError, kTraceVoice,
217 VoEId(_instanceId,_channelId),
218 "Channel::SendPacket() RTP transmission using external"
219 " transport failed");
220 return -1;
221 }
222 return n;
223 }
224}
225
226int
227Channel::SendRTCPPacket(int channel, const void *data, int len)
228{
229 channel = VoEChannelId(channel);
230 assert(channel == _channelId);
231
232 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
233 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
234
niklase@google.com470e71d2011-07-07 08:21:25 +0000235 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000236 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000237 if (_transportPtr == NULL)
238 {
239 WEBRTC_TRACE(kTraceError, kTraceVoice,
240 VoEId(_instanceId,_channelId),
241 "Channel::SendRTCPPacket() failed to send RTCP packet"
242 " due to invalid transport object");
243 return -1;
244 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
246
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000247 uint8_t* bufferToSendPtr = (uint8_t*)data;
248 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
250 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 {
253 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254 VoEId(_instanceId,_channelId),
255 "Channel::SendPacket() RTCP dump to output file failed");
256 }
257
258 // SRTP or External encryption
259 if (_encrypting)
260 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000261 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
263 if (_encryptionPtr)
264 {
265 if (!_encryptionRTCPBufferPtr)
266 {
267 // Allocate memory for encryption buffer one time only
268 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000269 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 }
271
272 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000273 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 _encryptionPtr->encrypt_rtcp(_channelId,
275 bufferToSendPtr,
276 _encryptionRTCPBufferPtr,
277 bufferLength,
278 (int*)&encryptedBufferLength);
279 if (encryptedBufferLength <= 0)
280 {
281 _engineStatisticsPtr->SetLastError(
282 VE_ENCRYPTION_FAILED, kTraceError,
283 "Channel::SendRTCPPacket() encryption failed");
284 return -1;
285 }
286
287 // Replace default data buffer with encrypted buffer
288 bufferToSendPtr = _encryptionRTCPBufferPtr;
289 bufferLength = encryptedBufferLength;
290 }
291 }
292
293 // Packet transmission using WebRtc socket transport
294 if (!_externalTransport)
295 {
296 int n = _transportPtr->SendRTCPPacket(channel,
297 bufferToSendPtr,
298 bufferLength);
299 if (n < 0)
300 {
301 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
302 VoEId(_instanceId,_channelId),
303 "Channel::SendRTCPPacket() transmission using WebRtc"
304 " sockets failed");
305 return -1;
306 }
307 return n;
308 }
309
310 // Packet transmission using external transport transport
311 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000312 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000313 if (_transportPtr == NULL)
314 {
315 return -1;
316 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000317 int n = _transportPtr->SendRTCPPacket(channel,
318 bufferToSendPtr,
319 bufferLength);
320 if (n < 0)
321 {
322 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
323 VoEId(_instanceId,_channelId),
324 "Channel::SendRTCPPacket() transmission using external"
325 " transport failed");
326 return -1;
327 }
328 return n;
329 }
330
331 return len;
332}
333
334void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000335Channel::OnPlayTelephoneEvent(int32_t id,
336 uint8_t event,
337 uint16_t lengthMs,
338 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000339{
340 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
341 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000342 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000343
344 if (!_playOutbandDtmfEvent || (event > 15))
345 {
346 // Ignore callback since feedback is disabled or event is not a
347 // Dtmf tone event.
348 return;
349 }
350
351 assert(_outputMixerPtr != NULL);
352
353 // Start playing out the Dtmf tone (if playout is enabled).
354 // Reduce length of tone with 80ms to the reduce risk of echo.
355 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
356}
357
358void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000359Channel::OnIncomingSSRCChanged(int32_t id,
360 uint32_t SSRC)
niklase@google.com470e71d2011-07-07 08:21:25 +0000361{
362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
363 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
364 id, SSRC);
365
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000366 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 assert(channel == _channelId);
368
369 // Reset RTP-module counters since a new incoming RTP stream is detected
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000370 _rtpRtcpModule->ResetReceiveDataCountersRTP();
371 _rtpRtcpModule->ResetStatisticsRTP();
niklase@google.com470e71d2011-07-07 08:21:25 +0000372
373 if (_rtpObserver)
374 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000375 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000376
377 if (_rtpObserverPtr)
378 {
379 // Send new SSRC to registered observer using callback
380 _rtpObserverPtr->OnIncomingSSRCChanged(channel, SSRC);
381 }
382 }
383}
384
pbos@webrtc.org92135212013-05-14 08:31:39 +0000385void Channel::OnIncomingCSRCChanged(int32_t id,
386 uint32_t CSRC,
387 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000388{
389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
390 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
391 id, CSRC, added);
392
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000393 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 assert(channel == _channelId);
395
396 if (_rtpObserver)
397 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000398 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000399
400 if (_rtpObserverPtr)
401 {
402 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
403 }
404 }
405}
406
407void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000408Channel::OnApplicationDataReceived(int32_t id,
409 uint8_t subType,
410 uint32_t name,
411 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000412 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000413{
414 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
415 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
416 " name=%u, length=%u)",
417 id, subType, name, length);
418
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000419 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 assert(channel == _channelId);
421
422 if (_rtcpObserver)
423 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000424 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000425
426 if (_rtcpObserverPtr)
427 {
428 _rtcpObserverPtr->OnApplicationDataReceived(channel,
429 subType,
430 name,
431 data,
432 length);
433 }
434 }
435}
436
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000437int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000438Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000439 int32_t id,
440 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000441 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000442 int frequency,
443 uint8_t channels,
444 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000445{
446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
447 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
448 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
449 id, payloadType, payloadName, frequency, channels, rate);
450
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000451 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000452
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000453 CodecInst receiveCodec = {0};
454 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000455
456 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 receiveCodec.plfreq = frequency;
458 receiveCodec.channels = channels;
459 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000460 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000461
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000462 _audioCodingModule.Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000463 receiveCodec.pacsize = dummyCodec.pacsize;
464
465 // Register the new codec to the ACM
466 if (_audioCodingModule.RegisterReceiveCodec(receiveCodec) == -1)
467 {
468 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000469 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 "Channel::OnInitializeDecoder() invalid codec ("
471 "pt=%d, name=%s) received - 1", payloadType, payloadName);
472 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
473 return -1;
474 }
475
476 return 0;
477}
478
479void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000480Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000481{
482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
483 "Channel::OnPacketTimeout(id=%d)", id);
484
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000485 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 if (_voiceEngineObserverPtr)
487 {
488 if (_receiving || _externalTransport)
489 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000490 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 assert(channel == _channelId);
492 // Ensure that next OnReceivedPacket() callback will trigger
493 // a VE_PACKET_RECEIPT_RESTARTED callback.
494 _rtpPacketTimedOut = true;
495 // Deliver callback to the observer
496 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
497 VoEId(_instanceId,_channelId),
498 "Channel::OnPacketTimeout() => "
499 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
500 _voiceEngineObserverPtr->CallbackOnError(channel,
501 VE_RECEIVE_PACKET_TIMEOUT);
502 }
503 }
504}
505
506void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000507Channel::OnReceivedPacket(int32_t id,
508 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000509{
510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
511 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
512 id, packetType);
513
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000514 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000515
516 // Notify only for the case when we have restarted an RTP session.
517 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
518 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000519 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000520 if (_voiceEngineObserverPtr)
521 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000522 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000523 assert(channel == _channelId);
524 // Reset timeout mechanism
525 _rtpPacketTimedOut = false;
526 // Deliver callback to the observer
527 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
528 VoEId(_instanceId,_channelId),
529 "Channel::OnPacketTimeout() =>"
530 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
531 _voiceEngineObserverPtr->CallbackOnError(
532 channel,
533 VE_PACKET_RECEIPT_RESTARTED);
534 }
535 }
536}
537
538void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000539Channel::OnPeriodicDeadOrAlive(int32_t id,
540 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000541{
542 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
543 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
544
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000545 {
546 CriticalSectionScoped cs(&_callbackCritSect);
547 if (!_connectionObserver)
548 return;
549 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000550
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000551 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 assert(channel == _channelId);
553
554 // Use Alive as default to limit risk of false Dead detections
555 bool isAlive(true);
556
557 // Always mark the connection as Dead when the module reports kRtpDead
558 if (kRtpDead == alive)
559 {
560 isAlive = false;
561 }
562
563 // It is possible that the connection is alive even if no RTP packet has
564 // been received for a long time since the other side might use VAD/DTX
565 // and a low SID-packet update rate.
566 if ((kRtpNoRtp == alive) && _playing)
567 {
568 // Detect Alive for all NetEQ states except for the case when we are
569 // in PLC_CNG state.
570 // PLC_CNG <=> background noise only due to long expand or error.
571 // Note that, the case where the other side stops sending during CNG
572 // state will be detected as Alive. Dead is is not set until after
573 // missing RTCP packets for at least twelve seconds (handled
574 // internally by the RTP/RTCP module).
575 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
576 }
577
578 UpdateDeadOrAliveCounters(isAlive);
579
580 // Send callback to the registered observer
581 if (_connectionObserver)
582 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000583 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 if (_connectionObserverPtr)
585 {
586 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
587 }
588 }
589}
590
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000591int32_t
592Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000593 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 const WebRtcRTPHeader* rtpHeader)
595{
596 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
597 "Channel::OnReceivedPayloadData(payloadSize=%d,"
598 " payloadType=%u, audioChannel=%u)",
599 payloadSize,
600 rtpHeader->header.payloadType,
601 rtpHeader->type.Audio.channel);
602
roosa@google.com0870f022012-12-12 21:31:41 +0000603 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
604
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 if (!_playing)
606 {
607 // Avoid inserting into NetEQ when we are not playing. Count the
608 // packet as discarded.
609 WEBRTC_TRACE(kTraceStream, kTraceVoice,
610 VoEId(_instanceId, _channelId),
611 "received packet is discarded since playing is not"
612 " activated");
613 _numberOfDiscardedPackets++;
614 return 0;
615 }
616
617 // Push the incoming payload (parsed and ready for decoding) into the ACM
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +0000618 if (_audioCodingModule.IncomingPacket(payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 payloadSize,
620 *rtpHeader) != 0)
621 {
622 _engineStatisticsPtr->SetLastError(
623 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
624 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
625 return -1;
626 }
627
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000628 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 UpdatePacketDelay(rtpHeader->header.timestamp,
630 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000631
632 if (kNackOff != _rtpRtcpModule->NACK()) { // Is NACK on?
633 uint16_t round_trip_time = 0;
634 _rtpRtcpModule->RTT(_rtpRtcpModule->RemoteSSRC(), &round_trip_time,
635 NULL, NULL, NULL);
636
637 std::vector<uint16_t> nack_list = _audioCodingModule.GetNackList(
638 round_trip_time);
639 if (!nack_list.empty()) {
640 ResendPackets(nack_list.data(), nack_list.size());
641 }
642 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 return 0;
644}
645
pbos@webrtc.org92135212013-05-14 08:31:39 +0000646int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647{
648 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
649 "Channel::GetAudioFrame(id=%d)", id);
650
651 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000652 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000653 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 {
655 WEBRTC_TRACE(kTraceError, kTraceVoice,
656 VoEId(_instanceId,_channelId),
657 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000658 // In all likelihood, the audio in this frame is garbage. We return an
659 // error so that the audio mixer module doesn't add it to the mix. As
660 // a result, it won't be played out and the actions skipped here are
661 // irrelevant.
662 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 }
664
665 if (_RxVadDetection)
666 {
667 UpdateRxVadDetection(audioFrame);
668 }
669
670 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000671 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000673 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000674
675 // Perform far-end AudioProcessing module processing on the received signal
676 if (_rxApmIsEnabled)
677 {
678 ApmProcessRx(audioFrame);
679 }
680
681 // Output volume scaling
682 if (_outputGain < 0.99f || _outputGain > 1.01f)
683 {
684 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
685 }
686
687 // Scale left and/or right channel(s) if stereo and master balance is
688 // active
689
690 if (_panLeft != 1.0f || _panRight != 1.0f)
691 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000692 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000693 {
694 // Emulate stereo mode since panning is active.
695 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000696 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 }
698 // For true stereo mode (when we are receiving a stereo signal), no
699 // action is needed.
700
701 // Do the panning operation (the audio frame contains stereo at this
702 // stage)
703 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
704 }
705
706 // Mix decoded PCM output with file if file mixing is enabled
707 if (_outputFilePlaying)
708 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000709 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 }
711
712 // Place channel in on-hold state (~muted) if on-hold is activated
713 if (_outputIsOnHold)
714 {
715 AudioFrameOperations::Mute(audioFrame);
716 }
717
718 // External media
719 if (_outputExternalMedia)
720 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000721 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000722 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000723 if (_outputExternalMediaCallbackPtr)
724 {
725 _outputExternalMediaCallbackPtr->Process(
726 _channelId,
727 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000728 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000729 audioFrame.samples_per_channel_,
730 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 isStereo);
732 }
733 }
734
735 // Record playout if enabled
736 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000737 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000738
739 if (_outputFileRecording && _outputFileRecorderPtr)
740 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000741 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000742 }
743 }
744
745 // Measure audio level (0-9)
746 _outputAudioLevel.ComputeLevel(audioFrame);
747
748 return 0;
749}
750
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000751int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000752Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000753{
754 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
755 "Channel::NeededFrequency(id=%d)", id);
756
757 int highestNeeded = 0;
758
759 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000760 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000761
762 // Return the bigger of playout and receive frequency in the ACM.
763 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
764 {
765 highestNeeded = _audioCodingModule.PlayoutFrequency();
766 }
767 else
768 {
769 highestNeeded = receiveFrequency;
770 }
771
772 // Special case, if we're playing a file on the playout side
773 // we take that frequency into consideration as well
774 // This is not needed on sending side, since the codec will
775 // limit the spectrum anyway.
776 if (_outputFilePlaying)
777 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000778 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000779 if (_outputFilePlayerPtr && _outputFilePlaying)
780 {
781 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
782 {
783 highestNeeded=_outputFilePlayerPtr->Frequency();
784 }
785 }
786 }
787
788 return(highestNeeded);
789}
790
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000791int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000792Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000793 int32_t channelId,
794 uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000795{
796 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
797 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
798 channelId, instanceId);
799
800 channel = new Channel(channelId, instanceId);
801 if (channel == NULL)
802 {
803 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
804 VoEId(instanceId,channelId),
805 "Channel::CreateChannel() unable to allocate memory for"
806 " channel");
807 return -1;
808 }
809 return 0;
810}
811
812void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000813Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000814{
815 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
816 "Channel::PlayNotification(id=%d, durationMs=%d)",
817 id, durationMs);
818
819 // Not implement yet
820}
821
822void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000823Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000824{
825 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
826 "Channel::RecordNotification(id=%d, durationMs=%d)",
827 id, durationMs);
828
829 // Not implement yet
830}
831
832void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000833Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000834{
835 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
836 "Channel::PlayFileEnded(id=%d)", id);
837
838 if (id == _inputFilePlayerId)
839 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000840 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000841
842 _inputFilePlaying = false;
843 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
844 VoEId(_instanceId,_channelId),
845 "Channel::PlayFileEnded() => input file player module is"
846 " shutdown");
847 }
848 else if (id == _outputFilePlayerId)
849 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000850 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000851
852 _outputFilePlaying = false;
853 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
854 VoEId(_instanceId,_channelId),
855 "Channel::PlayFileEnded() => output file player module is"
856 " shutdown");
857 }
858}
859
860void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000861Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000862{
863 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
864 "Channel::RecordFileEnded(id=%d)", id);
865
866 assert(id == _outputFileRecorderId);
867
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000868 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000869
870 _outputFileRecording = false;
871 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
872 VoEId(_instanceId,_channelId),
873 "Channel::RecordFileEnded() => output file recorder module is"
874 " shutdown");
875}
876
pbos@webrtc.org92135212013-05-14 08:31:39 +0000877Channel::Channel(int32_t channelId,
878 uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
880 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000882 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000883 rtp_header_parser_(RtpHeaderParser::Create()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000885 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 _rtpDumpIn(*RtpDump::CreateRtpDump()),
887 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000890 _inputFilePlayerPtr(NULL),
891 _outputFilePlayerPtr(NULL),
892 _outputFileRecorderPtr(NULL),
893 // Avoid conflict with other channels by adding 1024 - 1026,
894 // won't use as much as 1024 channels.
895 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
896 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
897 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
898 _inputFilePlaying(false),
899 _outputFilePlaying(false),
900 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000901 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
902 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000904 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _inputExternalMediaCallbackPtr(NULL),
906 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000907 _encryptionRTPBufferPtr(NULL),
908 _decryptionRTPBufferPtr(NULL),
909 _encryptionRTCPBufferPtr(NULL),
910 _decryptionRTCPBufferPtr(NULL),
911 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
912 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000913 playout_timestamp_rtp_(0),
914 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000915 _numberOfDiscardedPackets(0),
916 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000917 _outputMixerPtr(NULL),
918 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000919 _moduleProcessThreadPtr(NULL),
920 _audioDeviceModulePtr(NULL),
921 _voiceEngineObserverPtr(NULL),
922 _callbackCritSectPtr(NULL),
923 _transportPtr(NULL),
924 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000925 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000926 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000927 _rxVadObserverPtr(NULL),
928 _oldVadDecision(-1),
929 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 _rtpObserverPtr(NULL),
931 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000932 _outputIsOnHold(false),
933 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000934 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000935 _inputIsOnHold(false),
936 _playing(false),
937 _sending(false),
938 _receiving(false),
939 _mixFileWithMicrophone(false),
940 _rtpObserver(false),
941 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 _mute(false),
943 _panLeft(1.0f),
944 _panRight(1.0f),
945 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000946 _encrypting(false),
947 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 _playOutbandDtmfEvent(false),
949 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 _extraPayloadType(0),
951 _insertExtraRTPPacket(false),
952 _extraMarkerBit(false),
953 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000954 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000956 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 _rtpPacketTimedOut(false),
958 _rtpPacketTimeOutIsEnabled(false),
959 _rtpTimeOutSeconds(0),
960 _connectionObserver(false),
961 _connectionObserverPtr(NULL),
962 _countAliveDetections(0),
963 _countDeadDetections(0),
964 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000965 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000966 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 _previousTimestamp(0),
968 _recPacketDelayMs(20),
969 _RxVadDetection(false),
970 _rxApmIsEnabled(false),
971 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000972 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000973{
974 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
975 "Channel::Channel() - ctor");
976 _inbandDtmfQueue.ResetDtmf();
977 _inbandDtmfGenerator.Init();
978 _outputAudioLevel.Clear();
979
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000980 RtpRtcp::Configuration configuration;
981 configuration.id = VoEModuleId(instanceId, channelId);
982 configuration.audio = true;
983 configuration.incoming_data = this;
984 configuration.incoming_messages = this;
985 configuration.outgoing_transport = this;
986 configuration.rtcp_feedback = this;
987 configuration.audio_messages = this;
988
989 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
990
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 // Create far end AudioProcessing Module
992 _rxAudioProcessingModulePtr = AudioProcessing::Create(
993 VoEModuleId(instanceId, channelId));
994}
995
996Channel::~Channel()
997{
998 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
999 "Channel::~Channel() - dtor");
1000
1001 if (_outputExternalMedia)
1002 {
1003 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1004 }
1005 if (_inputExternalMedia)
1006 {
1007 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1008 }
1009 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 StopPlayout();
1011
1012 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001013 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001014 if (_inputFilePlayerPtr)
1015 {
1016 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1017 _inputFilePlayerPtr->StopPlayingFile();
1018 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1019 _inputFilePlayerPtr = NULL;
1020 }
1021 if (_outputFilePlayerPtr)
1022 {
1023 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1024 _outputFilePlayerPtr->StopPlayingFile();
1025 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1026 _outputFilePlayerPtr = NULL;
1027 }
1028 if (_outputFileRecorderPtr)
1029 {
1030 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1031 _outputFileRecorderPtr->StopRecording();
1032 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1033 _outputFileRecorderPtr = NULL;
1034 }
1035 }
1036
1037 // The order to safely shutdown modules in a channel is:
1038 // 1. De-register callbacks in modules
1039 // 2. De-register modules in process thread
1040 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1042 {
1043 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1044 VoEId(_instanceId,_channelId),
1045 "~Channel() failed to de-register transport callback"
1046 " (Audio coding module)");
1047 }
1048 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1049 {
1050 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1051 VoEId(_instanceId,_channelId),
1052 "~Channel() failed to de-register VAD callback"
1053 " (Audio coding module)");
1054 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001056 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 {
1058 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1059 VoEId(_instanceId,_channelId),
1060 "~Channel() failed to deregister RTP/RTCP module");
1061 }
1062
1063 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 if (_rxAudioProcessingModulePtr != NULL)
1066 {
1067 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1068 _rxAudioProcessingModulePtr = NULL;
1069 }
1070
1071 // End of modules shutdown
1072
1073 // Delete other objects
1074 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1075 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1076 delete [] _encryptionRTPBufferPtr;
1077 delete [] _decryptionRTPBufferPtr;
1078 delete [] _encryptionRTCPBufferPtr;
1079 delete [] _decryptionRTCPBufferPtr;
1080 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 delete &_fileCritSect;
1082}
1083
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001084int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001085Channel::Init()
1086{
1087 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1088 "Channel::Init()");
1089
1090 // --- Initial sanity
1091
1092 if ((_engineStatisticsPtr == NULL) ||
1093 (_moduleProcessThreadPtr == NULL))
1094 {
1095 WEBRTC_TRACE(kTraceError, kTraceVoice,
1096 VoEId(_instanceId,_channelId),
1097 "Channel::Init() must call SetEngineInformation() first");
1098 return -1;
1099 }
1100
1101 // --- Add modules to process thread (for periodic schedulation)
1102
1103 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001104 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 if (processThreadFail)
1107 {
1108 _engineStatisticsPtr->SetLastError(
1109 VE_CANNOT_INIT_CHANNEL, kTraceError,
1110 "Channel::Init() modules not registered");
1111 return -1;
1112 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001113 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001114
1115 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1116#ifdef WEBRTC_CODEC_AVT
1117 // out-of-band Dtmf tones are played out by default
1118 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1119#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 (_audioCodingModule.InitializeSender() == -1))
1121 {
1122 _engineStatisticsPtr->SetLastError(
1123 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1124 "Channel::Init() unable to initialize the ACM - 1");
1125 return -1;
1126 }
1127
1128 // --- RTP/RTCP module initialization
1129
1130 // Ensure that RTCP is enabled by default for the created channel.
1131 // Note that, the module will keep generating RTCP until it is explicitly
1132 // disabled by the user.
1133 // After StopListen (when no sockets exists), RTCP packets will no longer
1134 // be transmitted since the Transport object will then be invalid.
1135
1136 const bool rtpRtcpFail =
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001137 ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 // RTCP is enabled by default
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001139 (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 if (rtpRtcpFail)
1141 {
1142 _engineStatisticsPtr->SetLastError(
1143 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1144 "Channel::Init() RTP/RTCP module not initialized");
1145 return -1;
1146 }
1147
1148 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1151 (_audioCodingModule.RegisterVADCallback(this) == -1);
1152
1153 if (fail)
1154 {
1155 _engineStatisticsPtr->SetLastError(
1156 VE_CANNOT_INIT_CHANNEL, kTraceError,
1157 "Channel::Init() callbacks not registered");
1158 return -1;
1159 }
1160
1161 // --- Register all supported codecs to the receiving side of the
1162 // RTP/RTCP module
1163
1164 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001165 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001166
1167 for (int idx = 0; idx < nSupportedCodecs; idx++)
1168 {
1169 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001170 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001171 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 {
1173 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1174 VoEId(_instanceId,_channelId),
1175 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1176 "to RTP/RTCP receiver",
1177 codec.plname, codec.pltype, codec.plfreq,
1178 codec.channels, codec.rate);
1179 }
1180 else
1181 {
1182 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1183 VoEId(_instanceId,_channelId),
1184 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1185 "the RTP/RTCP receiver",
1186 codec.plname, codec.pltype, codec.plfreq,
1187 codec.channels, codec.rate);
1188 }
1189
1190 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001191 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 {
1193 SetSendCodec(codec);
1194 }
1195
1196 // Register default PT for outband 'telephone-event'
1197 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1198 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001199 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001200 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1201 {
1202 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1203 VoEId(_instanceId,_channelId),
1204 "Channel::Init() failed to register outband "
1205 "'telephone-event' (%d/%d) correctly",
1206 codec.pltype, codec.plfreq);
1207 }
1208 }
1209
1210 if (!STR_CASE_CMP(codec.plname, "CN"))
1211 {
1212 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1213 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001214 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 {
1216 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1217 VoEId(_instanceId,_channelId),
1218 "Channel::Init() failed to register CN (%d/%d) "
1219 "correctly - 1",
1220 codec.pltype, codec.plfreq);
1221 }
1222 }
1223#ifdef WEBRTC_CODEC_RED
1224 // Register RED to the receiving side of the ACM.
1225 // We will not receive an OnInitializeDecoder() callback for RED.
1226 if (!STR_CASE_CMP(codec.plname, "RED"))
1227 {
1228 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1229 {
1230 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1231 VoEId(_instanceId,_channelId),
1232 "Channel::Init() failed to register RED (%d/%d) "
1233 "correctly",
1234 codec.pltype, codec.plfreq);
1235 }
1236 }
1237#endif
1238 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001239
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 // Initialize the far end AP module
1241 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1242 // changed at the first receiving audio.
1243 if (_rxAudioProcessingModulePtr == NULL)
1244 {
1245 _engineStatisticsPtr->SetLastError(
1246 VE_NO_MEMORY, kTraceCritical,
1247 "Channel::Init() failed to create the far-end AudioProcessing"
1248 " module");
1249 return -1;
1250 }
1251
niklase@google.com470e71d2011-07-07 08:21:25 +00001252 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1253 {
1254 _engineStatisticsPtr->SetLastError(
1255 VE_APM_ERROR, kTraceWarning,
1256 "Channel::Init() failed to set the sample rate to 8K for"
1257 " far-end AP module");
1258 }
1259
1260 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1261 {
1262 _engineStatisticsPtr->SetLastError(
1263 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001264 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001265 }
1266
1267 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1268 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1269 {
1270 _engineStatisticsPtr->SetLastError(
1271 VE_APM_ERROR, kTraceWarning,
1272 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001273 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 }
1275
1276 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1277 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1278 {
1279 _engineStatisticsPtr->SetLastError(
1280 VE_APM_ERROR, kTraceWarning,
1281 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001282 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 }
1284 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1285 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1286 {
1287 _engineStatisticsPtr->SetLastError(
1288 VE_APM_ERROR, kTraceWarning,
1289 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001290 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001291 }
1292
1293 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1294 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1295 {
1296 _engineStatisticsPtr->SetLastError(
1297 VE_APM_ERROR, kTraceWarning,
1298 "Init() failed to set AGC mode for far-end AP module");
1299 }
1300 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1301 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1302 {
1303 _engineStatisticsPtr->SetLastError(
1304 VE_APM_ERROR, kTraceWarning,
1305 "Init() failed to set AGC state for far-end AP module");
1306 }
1307
1308 return 0;
1309}
1310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001312Channel::SetEngineInformation(Statistics& engineStatistics,
1313 OutputMixer& outputMixer,
1314 voe::TransmitMixer& transmitMixer,
1315 ProcessThread& moduleProcessThread,
1316 AudioDeviceModule& audioDeviceModule,
1317 VoiceEngineObserver* voiceEngineObserver,
1318 CriticalSectionWrapper* callbackCritSect)
1319{
1320 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1321 "Channel::SetEngineInformation()");
1322 _engineStatisticsPtr = &engineStatistics;
1323 _outputMixerPtr = &outputMixer;
1324 _transmitMixerPtr = &transmitMixer,
1325 _moduleProcessThreadPtr = &moduleProcessThread;
1326 _audioDeviceModulePtr = &audioDeviceModule;
1327 _voiceEngineObserverPtr = voiceEngineObserver;
1328 _callbackCritSectPtr = callbackCritSect;
1329 return 0;
1330}
1331
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001332int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001333Channel::UpdateLocalTimeStamp()
1334{
1335
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001336 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 return 0;
1338}
1339
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001340int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001341Channel::StartPlayout()
1342{
1343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1344 "Channel::StartPlayout()");
1345 if (_playing)
1346 {
1347 return 0;
1348 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001349
1350 if (!_externalMixing) {
1351 // Add participant as candidates for mixing.
1352 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1353 {
1354 _engineStatisticsPtr->SetLastError(
1355 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1356 "StartPlayout() failed to add participant to mixer");
1357 return -1;
1358 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001359 }
1360
1361 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001362
1363 if (RegisterFilePlayingToMixer() != 0)
1364 return -1;
1365
niklase@google.com470e71d2011-07-07 08:21:25 +00001366 return 0;
1367}
1368
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001369int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001370Channel::StopPlayout()
1371{
1372 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1373 "Channel::StopPlayout()");
1374 if (!_playing)
1375 {
1376 return 0;
1377 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001378
1379 if (!_externalMixing) {
1380 // Remove participant as candidates for mixing
1381 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1382 {
1383 _engineStatisticsPtr->SetLastError(
1384 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1385 "StopPlayout() failed to remove participant from mixer");
1386 return -1;
1387 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 }
1389
1390 _playing = false;
1391 _outputAudioLevel.Clear();
1392
1393 return 0;
1394}
1395
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001396int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001397Channel::StartSend()
1398{
1399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1400 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001401 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001402 // A lock is needed because |_sending| can be accessed or modified by
1403 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001404 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001405
1406 if (_sending)
1407 {
1408 return 0;
1409 }
1410 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001412
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001413 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 {
1415 _engineStatisticsPtr->SetLastError(
1416 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1417 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001418 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001419 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001420 return -1;
1421 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001422
niklase@google.com470e71d2011-07-07 08:21:25 +00001423 return 0;
1424}
1425
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001426int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001427Channel::StopSend()
1428{
1429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1430 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001432 // A lock is needed because |_sending| can be accessed or modified by
1433 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001434 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001435
1436 if (!_sending)
1437 {
1438 return 0;
1439 }
1440 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001441 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001442
niklase@google.com470e71d2011-07-07 08:21:25 +00001443 // Reset sending SSRC and sequence number and triggers direct transmission
1444 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001445 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1446 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001447 {
1448 _engineStatisticsPtr->SetLastError(
1449 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1450 "StartSend() RTP/RTCP failed to stop sending");
1451 }
1452
niklase@google.com470e71d2011-07-07 08:21:25 +00001453 return 0;
1454}
1455
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001456int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001457Channel::StartReceiving()
1458{
1459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1460 "Channel::StartReceiving()");
1461 if (_receiving)
1462 {
1463 return 0;
1464 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 _receiving = true;
1466 _numberOfDiscardedPackets = 0;
1467 return 0;
1468}
1469
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001470int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001471Channel::StopReceiving()
1472{
1473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1474 "Channel::StopReceiving()");
1475 if (!_receiving)
1476 {
1477 return 0;
1478 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001479
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001480 // Recover DTMF detection status.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001481 int32_t ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001482 if (ret != 0) {
1483 _engineStatisticsPtr->SetLastError(
1484 VE_INVALID_OPERATION, kTraceWarning,
1485 "StopReceiving() failed to restore telephone-event status.");
1486 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001487 RegisterReceiveCodecsToRTPModule();
1488 _receiving = false;
1489 return 0;
1490}
1491
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001492int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001493Channel::SetNetEQPlayoutMode(NetEqModes mode)
1494{
1495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1496 "Channel::SetNetEQPlayoutMode()");
1497 AudioPlayoutMode playoutMode(voice);
1498 switch (mode)
1499 {
1500 case kNetEqDefault:
1501 playoutMode = voice;
1502 break;
1503 case kNetEqStreaming:
1504 playoutMode = streaming;
1505 break;
1506 case kNetEqFax:
1507 playoutMode = fax;
1508 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001509 case kNetEqOff:
1510 playoutMode = off;
1511 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001512 }
1513 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1514 {
1515 _engineStatisticsPtr->SetLastError(
1516 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1517 "SetNetEQPlayoutMode() failed to set playout mode");
1518 return -1;
1519 }
1520 return 0;
1521}
1522
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001523int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001524Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1525{
1526 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1527 switch (playoutMode)
1528 {
1529 case voice:
1530 mode = kNetEqDefault;
1531 break;
1532 case streaming:
1533 mode = kNetEqStreaming;
1534 break;
1535 case fax:
1536 mode = kNetEqFax;
1537 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001538 case off:
1539 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001540 }
1541 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1542 VoEId(_instanceId,_channelId),
1543 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1544 return 0;
1545}
1546
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001547int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001548Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1549{
1550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1551 "Channel::SetOnHoldStatus()");
1552 if (mode == kHoldSendAndPlay)
1553 {
1554 _outputIsOnHold = enable;
1555 _inputIsOnHold = enable;
1556 }
1557 else if (mode == kHoldPlayOnly)
1558 {
1559 _outputIsOnHold = enable;
1560 }
1561 if (mode == kHoldSendOnly)
1562 {
1563 _inputIsOnHold = enable;
1564 }
1565 return 0;
1566}
1567
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001568int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001569Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1570{
1571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1572 "Channel::GetOnHoldStatus()");
1573 enabled = (_outputIsOnHold || _inputIsOnHold);
1574 if (_outputIsOnHold && _inputIsOnHold)
1575 {
1576 mode = kHoldSendAndPlay;
1577 }
1578 else if (_outputIsOnHold && !_inputIsOnHold)
1579 {
1580 mode = kHoldPlayOnly;
1581 }
1582 else if (!_outputIsOnHold && _inputIsOnHold)
1583 {
1584 mode = kHoldSendOnly;
1585 }
1586 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1587 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1588 enabled, mode);
1589 return 0;
1590}
1591
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001592int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001593Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1594{
1595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1596 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001597 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001598
1599 if (_voiceEngineObserverPtr)
1600 {
1601 _engineStatisticsPtr->SetLastError(
1602 VE_INVALID_OPERATION, kTraceError,
1603 "RegisterVoiceEngineObserver() observer already enabled");
1604 return -1;
1605 }
1606 _voiceEngineObserverPtr = &observer;
1607 return 0;
1608}
1609
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001610int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001611Channel::DeRegisterVoiceEngineObserver()
1612{
1613 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1614 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001615 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001616
1617 if (!_voiceEngineObserverPtr)
1618 {
1619 _engineStatisticsPtr->SetLastError(
1620 VE_INVALID_OPERATION, kTraceWarning,
1621 "DeRegisterVoiceEngineObserver() observer already disabled");
1622 return 0;
1623 }
1624 _voiceEngineObserverPtr = NULL;
1625 return 0;
1626}
1627
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001628int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001629Channel::GetSendCodec(CodecInst& codec)
1630{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001631 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001632}
1633
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001634int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001635Channel::GetRecCodec(CodecInst& codec)
1636{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001637 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001638}
1639
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001640int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001641Channel::SetSendCodec(const CodecInst& codec)
1642{
1643 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1644 "Channel::SetSendCodec()");
1645
1646 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1647 {
1648 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1649 "SetSendCodec() failed to register codec to ACM");
1650 return -1;
1651 }
1652
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001653 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001654 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001655 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1656 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001657 {
1658 WEBRTC_TRACE(
1659 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1660 "SetSendCodec() failed to register codec to"
1661 " RTP/RTCP module");
1662 return -1;
1663 }
1664 }
1665
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001666 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001667 {
1668 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1669 "SetSendCodec() failed to set audio packet size");
1670 return -1;
1671 }
1672
1673 return 0;
1674}
1675
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001676int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001677Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1678{
1679 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1680 "Channel::SetVADStatus(mode=%d)", mode);
1681 // To disable VAD, DTX must be disabled too
1682 disableDTX = ((enableVAD == false) ? true : disableDTX);
1683 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1684 {
1685 _engineStatisticsPtr->SetLastError(
1686 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1687 "SetVADStatus() failed to set VAD");
1688 return -1;
1689 }
1690 return 0;
1691}
1692
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001693int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001694Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1695{
1696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1697 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001698 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001699 {
1700 _engineStatisticsPtr->SetLastError(
1701 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1702 "GetVADStatus() failed to get VAD status");
1703 return -1;
1704 }
1705 disabledDTX = !disabledDTX;
1706 return 0;
1707}
1708
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001709int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001710Channel::SetRecPayloadType(const CodecInst& codec)
1711{
1712 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1713 "Channel::SetRecPayloadType()");
1714
1715 if (_playing)
1716 {
1717 _engineStatisticsPtr->SetLastError(
1718 VE_ALREADY_PLAYING, kTraceError,
1719 "SetRecPayloadType() unable to set PT while playing");
1720 return -1;
1721 }
1722 if (_receiving)
1723 {
1724 _engineStatisticsPtr->SetLastError(
1725 VE_ALREADY_LISTENING, kTraceError,
1726 "SetRecPayloadType() unable to set PT while listening");
1727 return -1;
1728 }
1729
1730 if (codec.pltype == -1)
1731 {
1732 // De-register the selected codec (RTP/RTCP module and ACM)
1733
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001734 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001735 CodecInst rxCodec = codec;
1736
1737 // Get payload type for the given codec
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001738 _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001739 rxCodec.pltype = pltype;
1740
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001741 if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001742 {
1743 _engineStatisticsPtr->SetLastError(
1744 VE_RTP_RTCP_MODULE_ERROR,
1745 kTraceError,
1746 "SetRecPayloadType() RTP/RTCP-module deregistration "
1747 "failed");
1748 return -1;
1749 }
1750 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1751 {
1752 _engineStatisticsPtr->SetLastError(
1753 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1754 "SetRecPayloadType() ACM deregistration failed - 1");
1755 return -1;
1756 }
1757 return 0;
1758 }
1759
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001760 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001761 {
1762 // First attempt to register failed => de-register and try again
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001763 _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
1764 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001765 {
1766 _engineStatisticsPtr->SetLastError(
1767 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1768 "SetRecPayloadType() RTP/RTCP-module registration failed");
1769 return -1;
1770 }
1771 }
1772 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1773 {
1774 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1775 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1776 {
1777 _engineStatisticsPtr->SetLastError(
1778 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1779 "SetRecPayloadType() ACM registration failed - 1");
1780 return -1;
1781 }
1782 }
1783 return 0;
1784}
1785
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001786int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001787Channel::GetRecPayloadType(CodecInst& codec)
1788{
1789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1790 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001791 int8_t payloadType(-1);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001792 if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001793 {
1794 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001795 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001796 "GetRecPayloadType() failed to retrieve RX payload type");
1797 return -1;
1798 }
1799 codec.pltype = payloadType;
1800 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1801 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1802 return 0;
1803}
1804
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001805int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001806Channel::SetAMREncFormat(AmrMode mode)
1807{
1808 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1809 "Channel::SetAMREncFormat()");
1810
1811 // ACM doesn't support AMR
1812 return -1;
1813}
1814
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001815int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001816Channel::SetAMRDecFormat(AmrMode mode)
1817{
1818 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1819 "Channel::SetAMRDecFormat()");
1820
1821 // ACM doesn't support AMR
1822 return -1;
1823}
1824
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001825int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001826Channel::SetAMRWbEncFormat(AmrMode mode)
1827{
1828 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1829 "Channel::SetAMRWbEncFormat()");
1830
1831 // ACM doesn't support AMR
1832 return -1;
1833
1834}
1835
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001836int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001837Channel::SetAMRWbDecFormat(AmrMode mode)
1838{
1839 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1840 "Channel::SetAMRWbDecFormat()");
1841
1842 // ACM doesn't support AMR
1843 return -1;
1844}
1845
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001846int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001847Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1848{
1849 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1850 "Channel::SetSendCNPayloadType()");
1851
1852 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001853 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001854 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001855 if (frequency == kFreq32000Hz)
1856 samplingFreqHz = 32000;
1857 else if (frequency == kFreq16000Hz)
1858 samplingFreqHz = 16000;
1859
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001860 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001861 {
1862 _engineStatisticsPtr->SetLastError(
1863 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1864 "SetSendCNPayloadType() failed to retrieve default CN codec "
1865 "settings");
1866 return -1;
1867 }
1868
1869 // Modify the payload type (must be set to dynamic range)
1870 codec.pltype = type;
1871
1872 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1876 "SetSendCNPayloadType() failed to register CN to ACM");
1877 return -1;
1878 }
1879
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001880 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001881 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001882 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1883 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001884 {
1885 _engineStatisticsPtr->SetLastError(
1886 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1887 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1888 "module");
1889 return -1;
1890 }
1891 }
1892 return 0;
1893}
1894
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001895int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001896Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1897{
1898 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1899 "Channel::SetISACInitTargetRate()");
1900
1901 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001902 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001903 {
1904 _engineStatisticsPtr->SetLastError(
1905 VE_CODEC_ERROR, kTraceError,
1906 "SetISACInitTargetRate() failed to retrieve send codec");
1907 return -1;
1908 }
1909 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1910 {
1911 // This API is only valid if iSAC is setup to run in channel-adaptive
1912 // mode.
1913 // We do not validate the adaptive mode here. It is done later in the
1914 // ConfigISACBandwidthEstimator() API.
1915 _engineStatisticsPtr->SetLastError(
1916 VE_CODEC_ERROR, kTraceError,
1917 "SetISACInitTargetRate() send codec is not iSAC");
1918 return -1;
1919 }
1920
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001921 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001922 if (16000 == sendCodec.plfreq)
1923 {
1924 // Note that 0 is a valid and corresponds to "use default
1925 if ((rateBps != 0 &&
1926 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1927 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1928 {
1929 _engineStatisticsPtr->SetLastError(
1930 VE_INVALID_ARGUMENT, kTraceError,
1931 "SetISACInitTargetRate() invalid target rate - 1");
1932 return -1;
1933 }
1934 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001935 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001936 }
1937 else if (32000 == sendCodec.plfreq)
1938 {
1939 if ((rateBps != 0 &&
1940 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1941 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1942 {
1943 _engineStatisticsPtr->SetLastError(
1944 VE_INVALID_ARGUMENT, kTraceError,
1945 "SetISACInitTargetRate() invalid target rate - 2");
1946 return -1;
1947 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001948 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001949 }
1950
1951 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1952 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1953 {
1954 _engineStatisticsPtr->SetLastError(
1955 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1956 "SetISACInitTargetRate() iSAC BWE config failed");
1957 return -1;
1958 }
1959
1960 return 0;
1961}
1962
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001963int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001964Channel::SetISACMaxRate(int rateBps)
1965{
1966 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1967 "Channel::SetISACMaxRate()");
1968
1969 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001970 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001971 {
1972 _engineStatisticsPtr->SetLastError(
1973 VE_CODEC_ERROR, kTraceError,
1974 "SetISACMaxRate() failed to retrieve send codec");
1975 return -1;
1976 }
1977 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1978 {
1979 // This API is only valid if iSAC is selected as sending codec.
1980 _engineStatisticsPtr->SetLastError(
1981 VE_CODEC_ERROR, kTraceError,
1982 "SetISACMaxRate() send codec is not iSAC");
1983 return -1;
1984 }
1985 if (16000 == sendCodec.plfreq)
1986 {
1987 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1988 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1989 {
1990 _engineStatisticsPtr->SetLastError(
1991 VE_INVALID_ARGUMENT, kTraceError,
1992 "SetISACMaxRate() invalid max rate - 1");
1993 return -1;
1994 }
1995 }
1996 else if (32000 == sendCodec.plfreq)
1997 {
1998 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1999 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2000 {
2001 _engineStatisticsPtr->SetLastError(
2002 VE_INVALID_ARGUMENT, kTraceError,
2003 "SetISACMaxRate() invalid max rate - 2");
2004 return -1;
2005 }
2006 }
2007 if (_sending)
2008 {
2009 _engineStatisticsPtr->SetLastError(
2010 VE_SENDING, kTraceError,
2011 "SetISACMaxRate() unable to set max rate while sending");
2012 return -1;
2013 }
2014
2015 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2016 // and non-adaptive mode)
2017 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2018 {
2019 _engineStatisticsPtr->SetLastError(
2020 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2021 "SetISACMaxRate() failed to set max rate");
2022 return -1;
2023 }
2024
2025 return 0;
2026}
2027
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002028int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002029Channel::SetISACMaxPayloadSize(int sizeBytes)
2030{
2031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2032 "Channel::SetISACMaxPayloadSize()");
2033 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002034 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002035 {
2036 _engineStatisticsPtr->SetLastError(
2037 VE_CODEC_ERROR, kTraceError,
2038 "SetISACMaxPayloadSize() failed to retrieve send codec");
2039 return -1;
2040 }
2041 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2042 {
2043 _engineStatisticsPtr->SetLastError(
2044 VE_CODEC_ERROR, kTraceError,
2045 "SetISACMaxPayloadSize() send codec is not iSAC");
2046 return -1;
2047 }
2048 if (16000 == sendCodec.plfreq)
2049 {
2050 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2051 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2052 {
2053 _engineStatisticsPtr->SetLastError(
2054 VE_INVALID_ARGUMENT, kTraceError,
2055 "SetISACMaxPayloadSize() invalid max payload - 1");
2056 return -1;
2057 }
2058 }
2059 else if (32000 == sendCodec.plfreq)
2060 {
2061 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2062 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2063 {
2064 _engineStatisticsPtr->SetLastError(
2065 VE_INVALID_ARGUMENT, kTraceError,
2066 "SetISACMaxPayloadSize() invalid max payload - 2");
2067 return -1;
2068 }
2069 }
2070 if (_sending)
2071 {
2072 _engineStatisticsPtr->SetLastError(
2073 VE_SENDING, kTraceError,
2074 "SetISACMaxPayloadSize() unable to set max rate while sending");
2075 return -1;
2076 }
2077
2078 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2079 {
2080 _engineStatisticsPtr->SetLastError(
2081 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2082 "SetISACMaxPayloadSize() failed to set max payload size");
2083 return -1;
2084 }
2085 return 0;
2086}
2087
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002088int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002089{
2090 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2091 "Channel::RegisterExternalTransport()");
2092
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002093 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002094
niklase@google.com470e71d2011-07-07 08:21:25 +00002095 if (_externalTransport)
2096 {
2097 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2098 kTraceError,
2099 "RegisterExternalTransport() external transport already enabled");
2100 return -1;
2101 }
2102 _externalTransport = true;
2103 _transportPtr = &transport;
2104 return 0;
2105}
2106
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002107int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002108Channel::DeRegisterExternalTransport()
2109{
2110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2111 "Channel::DeRegisterExternalTransport()");
2112
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002113 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002114
niklase@google.com470e71d2011-07-07 08:21:25 +00002115 if (!_transportPtr)
2116 {
2117 _engineStatisticsPtr->SetLastError(
2118 VE_INVALID_OPERATION, kTraceWarning,
2119 "DeRegisterExternalTransport() external transport already "
2120 "disabled");
2121 return 0;
2122 }
2123 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002124 _transportPtr = NULL;
2125 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2126 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002127 return 0;
2128}
2129
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002130int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002131 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2132 "Channel::ReceivedRTPPacket()");
2133
2134 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002135 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002136
2137 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002138 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2139 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002140 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2141 VoEId(_instanceId,_channelId),
2142 "Channel::SendPacket() RTP dump to input file failed");
2143 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002144 RTPHeader header;
2145 if (!rtp_header_parser_->Parse(reinterpret_cast<const uint8_t*>(data),
2146 static_cast<uint16_t>(length), &header)) {
2147 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo,
2148 VoEId(_instanceId,_channelId),
2149 "IncomingPacket invalid RTP header");
2150 return -1;
2151 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002152 // Deliver RTP packet to RTP/RTCP module for parsing
2153 // The packet will be pushed back to the channel thru the
2154 // OnReceivedPayloadData callback so we don't push it to the ACM here
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002155 if (_rtpRtcpModule->IncomingRtpPacket(reinterpret_cast<const uint8_t*>(data),
2156 static_cast<uint16_t>(length),
2157 header) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002158 _engineStatisticsPtr->SetLastError(
2159 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2160 "Channel::IncomingRTPPacket() RTP packet is invalid");
2161 }
2162 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002163}
2164
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002165int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002166 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2167 "Channel::ReceivedRTCPPacket()");
2168 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002169 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002170
2171 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002172 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2173 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002174 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2175 VoEId(_instanceId,_channelId),
2176 "Channel::SendPacket() RTCP dump to input file failed");
2177 }
2178
2179 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002180 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2181 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002182 _engineStatisticsPtr->SetLastError(
2183 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2184 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2185 }
2186 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002187}
2188
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002189int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002190Channel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
2191{
2192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2193 "Channel::SetPacketTimeoutNotification()");
2194 if (enable)
2195 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002196 const uint32_t RTPtimeoutMS = 1000*timeoutSeconds;
2197 const uint32_t RTCPtimeoutMS = 0;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002198 _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
niklase@google.com470e71d2011-07-07 08:21:25 +00002199 _rtpPacketTimeOutIsEnabled = true;
2200 _rtpTimeOutSeconds = timeoutSeconds;
2201 }
2202 else
2203 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002204 _rtpRtcpModule->SetPacketTimeout(0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002205 _rtpPacketTimeOutIsEnabled = false;
2206 _rtpTimeOutSeconds = 0;
2207 }
2208 return 0;
2209}
2210
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002211int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002212Channel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
2213{
2214 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2215 "Channel::GetPacketTimeoutNotification()");
2216 enabled = _rtpPacketTimeOutIsEnabled;
2217 if (enabled)
2218 {
2219 timeoutSeconds = _rtpTimeOutSeconds;
2220 }
2221 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2222 "GetPacketTimeoutNotification() => enabled=%d,"
2223 " timeoutSeconds=%d",
2224 enabled, timeoutSeconds);
2225 return 0;
2226}
2227
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002228int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002229Channel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
2230{
2231 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2232 "Channel::RegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002233 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002234
2235 if (_connectionObserverPtr)
2236 {
2237 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
2238 "RegisterDeadOrAliveObserver() observer already enabled");
2239 return -1;
2240 }
2241
2242 _connectionObserverPtr = &observer;
2243 _connectionObserver = true;
2244
2245 return 0;
2246}
2247
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002248int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002249Channel::DeRegisterDeadOrAliveObserver()
2250{
2251 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2252 "Channel::DeRegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002253 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002254
2255 if (!_connectionObserverPtr)
2256 {
2257 _engineStatisticsPtr->SetLastError(
2258 VE_INVALID_OPERATION, kTraceWarning,
2259 "DeRegisterDeadOrAliveObserver() observer already disabled");
2260 return 0;
2261 }
2262
2263 _connectionObserver = false;
2264 _connectionObserverPtr = NULL;
2265
2266 return 0;
2267}
2268
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002269int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002270Channel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
2271{
2272 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2273 "Channel::SetPeriodicDeadOrAliveStatus()");
2274 if (!_connectionObserverPtr)
2275 {
2276 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
2277 "SetPeriodicDeadOrAliveStatus() connection observer has"
2278 " not been registered");
2279 }
2280 if (enable)
2281 {
2282 ResetDeadOrAliveCounters();
2283 }
2284 bool enabled(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002285 uint8_t currentSampleTimeSec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002286 // Store last state (will be used later if dead-or-alive is disabled).
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002287 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00002288 // Update the dead-or-alive state.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002289 if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002290 enable, (uint8_t)sampleTimeSeconds) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002291 {
2292 _engineStatisticsPtr->SetLastError(
2293 VE_RTP_RTCP_MODULE_ERROR,
2294 kTraceError,
2295 "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
2296 "status");
2297 return -1;
2298 }
2299 if (!enable)
2300 {
2301 // Restore last utilized sample time.
2302 // Without this, the sample time would always be reset to default
2303 // (2 sec), each time dead-or-alived was disabled without sample-time
2304 // parameter.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002305 _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
niklase@google.com470e71d2011-07-07 08:21:25 +00002306 currentSampleTimeSec);
2307 }
2308 return 0;
2309}
2310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002312Channel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
2313{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002314 _rtpRtcpModule->PeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00002315 enabled,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002316 (uint8_t&)sampleTimeSeconds);
niklase@google.com470e71d2011-07-07 08:21:25 +00002317 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2318 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
2319 " sampleTimeSeconds=%d",
2320 enabled, sampleTimeSeconds);
2321 return 0;
2322}
2323
niklase@google.com470e71d2011-07-07 08:21:25 +00002324int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002325 bool loop,
2326 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(fileNameUTF8[]=%s, loop=%d,"
2334 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2335 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2336 startPosition, stopPosition);
2337
2338 if (_outputFilePlaying)
2339 {
2340 _engineStatisticsPtr->SetLastError(
2341 VE_ALREADY_PLAYING, kTraceError,
2342 "StartPlayingFileLocally() is already playing");
2343 return -1;
2344 }
2345
niklase@google.com470e71d2011-07-07 08:21:25 +00002346 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002347 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002348
2349 if (_outputFilePlayerPtr)
2350 {
2351 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2352 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2353 _outputFilePlayerPtr = NULL;
2354 }
2355
2356 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2357 _outputFilePlayerId, (const FileFormats)format);
2358
2359 if (_outputFilePlayerPtr == NULL)
2360 {
2361 _engineStatisticsPtr->SetLastError(
2362 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002363 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002364 return -1;
2365 }
2366
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002367 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002368
2369 if (_outputFilePlayerPtr->StartPlayingFile(
2370 fileName,
2371 loop,
2372 startPosition,
2373 volumeScaling,
2374 notificationTime,
2375 stopPosition,
2376 (const CodecInst*)codecInst) != 0)
2377 {
2378 _engineStatisticsPtr->SetLastError(
2379 VE_BAD_FILE, kTraceError,
2380 "StartPlayingFile() failed to start file playout");
2381 _outputFilePlayerPtr->StopPlayingFile();
2382 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2383 _outputFilePlayerPtr = NULL;
2384 return -1;
2385 }
2386 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2387 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002388 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002389
2390 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002391 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002392
2393 return 0;
2394}
2395
2396int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002397 FileFormats format,
2398 int startPosition,
2399 float volumeScaling,
2400 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002401 const CodecInst* codecInst)
2402{
2403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2404 "Channel::StartPlayingFileLocally(format=%d,"
2405 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2406 format, volumeScaling, startPosition, stopPosition);
2407
2408 if(stream == NULL)
2409 {
2410 _engineStatisticsPtr->SetLastError(
2411 VE_BAD_FILE, kTraceError,
2412 "StartPlayingFileLocally() NULL as input stream");
2413 return -1;
2414 }
2415
2416
2417 if (_outputFilePlaying)
2418 {
2419 _engineStatisticsPtr->SetLastError(
2420 VE_ALREADY_PLAYING, kTraceError,
2421 "StartPlayingFileLocally() is already playing");
2422 return -1;
2423 }
2424
niklase@google.com470e71d2011-07-07 08:21:25 +00002425 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002426 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002427
2428 // Destroy the old instance
2429 if (_outputFilePlayerPtr)
2430 {
2431 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2432 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2433 _outputFilePlayerPtr = NULL;
2434 }
2435
2436 // Create the instance
2437 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2438 _outputFilePlayerId,
2439 (const FileFormats)format);
2440
2441 if (_outputFilePlayerPtr == NULL)
2442 {
2443 _engineStatisticsPtr->SetLastError(
2444 VE_INVALID_ARGUMENT, kTraceError,
2445 "StartPlayingFileLocally() filePlayer format isnot correct");
2446 return -1;
2447 }
2448
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002449 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002450
2451 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2452 volumeScaling,
2453 notificationTime,
2454 stopPosition, codecInst) != 0)
2455 {
2456 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2457 "StartPlayingFile() failed to "
2458 "start file playout");
2459 _outputFilePlayerPtr->StopPlayingFile();
2460 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2461 _outputFilePlayerPtr = NULL;
2462 return -1;
2463 }
2464 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2465 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002466 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002467
2468 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002469 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002470
niklase@google.com470e71d2011-07-07 08:21:25 +00002471 return 0;
2472}
2473
2474int Channel::StopPlayingFileLocally()
2475{
2476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2477 "Channel::StopPlayingFileLocally()");
2478
2479 if (!_outputFilePlaying)
2480 {
2481 _engineStatisticsPtr->SetLastError(
2482 VE_INVALID_OPERATION, kTraceWarning,
2483 "StopPlayingFileLocally() isnot playing");
2484 return 0;
2485 }
2486
niklase@google.com470e71d2011-07-07 08:21:25 +00002487 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002488 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002489
2490 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2491 {
2492 _engineStatisticsPtr->SetLastError(
2493 VE_STOP_RECORDING_FAILED, kTraceError,
2494 "StopPlayingFile() could not stop playing");
2495 return -1;
2496 }
2497 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2498 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2499 _outputFilePlayerPtr = NULL;
2500 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002501 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002502 // _fileCritSect cannot be taken while calling
2503 // SetAnonymousMixibilityStatus. Refer to comments in
2504 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002505 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2506 {
2507 _engineStatisticsPtr->SetLastError(
2508 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002509 "StopPlayingFile() failed to stop participant from playing as"
2510 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002511 return -1;
2512 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002513
2514 return 0;
2515}
2516
2517int Channel::IsPlayingFileLocally() const
2518{
2519 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2520 "Channel::IsPlayingFileLocally()");
2521
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002522 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002523}
2524
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002525int Channel::RegisterFilePlayingToMixer()
2526{
2527 // Return success for not registering for file playing to mixer if:
2528 // 1. playing file before playout is started on that channel.
2529 // 2. starting playout without file playing on that channel.
2530 if (!_playing || !_outputFilePlaying)
2531 {
2532 return 0;
2533 }
2534
2535 // |_fileCritSect| cannot be taken while calling
2536 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2537 // frames can be pulled by the mixer. Since the frames are generated from
2538 // the file, _fileCritSect will be taken. This would result in a deadlock.
2539 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2540 {
2541 CriticalSectionScoped cs(&_fileCritSect);
2542 _outputFilePlaying = false;
2543 _engineStatisticsPtr->SetLastError(
2544 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2545 "StartPlayingFile() failed to add participant as file to mixer");
2546 _outputFilePlayerPtr->StopPlayingFile();
2547 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2548 _outputFilePlayerPtr = NULL;
2549 return -1;
2550 }
2551
2552 return 0;
2553}
2554
pbos@webrtc.org92135212013-05-14 08:31:39 +00002555int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002556{
2557 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2558 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2559
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002560 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002561
2562 if (!_outputFilePlaying)
2563 {
2564 _engineStatisticsPtr->SetLastError(
2565 VE_INVALID_OPERATION, kTraceError,
2566 "ScaleLocalFilePlayout() isnot playing");
2567 return -1;
2568 }
2569 if ((_outputFilePlayerPtr == NULL) ||
2570 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2571 {
2572 _engineStatisticsPtr->SetLastError(
2573 VE_BAD_ARGUMENT, kTraceError,
2574 "SetAudioScaling() failed to scale the playout");
2575 return -1;
2576 }
2577
2578 return 0;
2579}
2580
2581int Channel::GetLocalPlayoutPosition(int& positionMs)
2582{
2583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2584 "Channel::GetLocalPlayoutPosition(position=?)");
2585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002586 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002587
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002588 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002589
2590 if (_outputFilePlayerPtr == NULL)
2591 {
2592 _engineStatisticsPtr->SetLastError(
2593 VE_INVALID_OPERATION, kTraceError,
2594 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2595 return -1;
2596 }
2597
2598 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2599 {
2600 _engineStatisticsPtr->SetLastError(
2601 VE_BAD_FILE, kTraceError,
2602 "GetLocalPlayoutPosition() failed");
2603 return -1;
2604 }
2605 positionMs = position;
2606
2607 return 0;
2608}
2609
2610int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002611 bool loop,
2612 FileFormats format,
2613 int startPosition,
2614 float volumeScaling,
2615 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 const CodecInst* codecInst)
2617{
2618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2619 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2620 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2621 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2622 startPosition, stopPosition);
2623
2624 if (_inputFilePlaying)
2625 {
2626 _engineStatisticsPtr->SetLastError(
2627 VE_ALREADY_PLAYING, kTraceWarning,
2628 "StartPlayingFileAsMicrophone() filePlayer is playing");
2629 return 0;
2630 }
2631
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002632 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002633
2634 // Destroy the old instance
2635 if (_inputFilePlayerPtr)
2636 {
2637 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2638 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2639 _inputFilePlayerPtr = NULL;
2640 }
2641
2642 // Create the instance
2643 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2644 _inputFilePlayerId, (const FileFormats)format);
2645
2646 if (_inputFilePlayerPtr == NULL)
2647 {
2648 _engineStatisticsPtr->SetLastError(
2649 VE_INVALID_ARGUMENT, kTraceError,
2650 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2651 return -1;
2652 }
2653
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002654 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002655
2656 if (_inputFilePlayerPtr->StartPlayingFile(
2657 fileName,
2658 loop,
2659 startPosition,
2660 volumeScaling,
2661 notificationTime,
2662 stopPosition,
2663 (const CodecInst*)codecInst) != 0)
2664 {
2665 _engineStatisticsPtr->SetLastError(
2666 VE_BAD_FILE, kTraceError,
2667 "StartPlayingFile() failed to start file playout");
2668 _inputFilePlayerPtr->StopPlayingFile();
2669 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2670 _inputFilePlayerPtr = NULL;
2671 return -1;
2672 }
2673 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2674 _inputFilePlaying = true;
2675
2676 return 0;
2677}
2678
2679int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002680 FileFormats format,
2681 int startPosition,
2682 float volumeScaling,
2683 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002684 const CodecInst* codecInst)
2685{
2686 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2687 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2688 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2689 format, volumeScaling, startPosition, stopPosition);
2690
2691 if(stream == NULL)
2692 {
2693 _engineStatisticsPtr->SetLastError(
2694 VE_BAD_FILE, kTraceError,
2695 "StartPlayingFileAsMicrophone NULL as input stream");
2696 return -1;
2697 }
2698
2699 if (_inputFilePlaying)
2700 {
2701 _engineStatisticsPtr->SetLastError(
2702 VE_ALREADY_PLAYING, kTraceWarning,
2703 "StartPlayingFileAsMicrophone() is playing");
2704 return 0;
2705 }
2706
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002707 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002708
2709 // Destroy the old instance
2710 if (_inputFilePlayerPtr)
2711 {
2712 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2713 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2714 _inputFilePlayerPtr = NULL;
2715 }
2716
2717 // Create the instance
2718 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2719 _inputFilePlayerId, (const FileFormats)format);
2720
2721 if (_inputFilePlayerPtr == NULL)
2722 {
2723 _engineStatisticsPtr->SetLastError(
2724 VE_INVALID_ARGUMENT, kTraceError,
2725 "StartPlayingInputFile() filePlayer format isnot correct");
2726 return -1;
2727 }
2728
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002729 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002730
2731 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2732 volumeScaling, notificationTime,
2733 stopPosition, codecInst) != 0)
2734 {
2735 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2736 "StartPlayingFile() failed to start "
2737 "file playout");
2738 _inputFilePlayerPtr->StopPlayingFile();
2739 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2740 _inputFilePlayerPtr = NULL;
2741 return -1;
2742 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002743
niklase@google.com470e71d2011-07-07 08:21:25 +00002744 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2745 _inputFilePlaying = true;
2746
2747 return 0;
2748}
2749
2750int Channel::StopPlayingFileAsMicrophone()
2751{
2752 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2753 "Channel::StopPlayingFileAsMicrophone()");
2754
2755 if (!_inputFilePlaying)
2756 {
2757 _engineStatisticsPtr->SetLastError(
2758 VE_INVALID_OPERATION, kTraceWarning,
2759 "StopPlayingFileAsMicrophone() isnot playing");
2760 return 0;
2761 }
2762
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002763 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2765 {
2766 _engineStatisticsPtr->SetLastError(
2767 VE_STOP_RECORDING_FAILED, kTraceError,
2768 "StopPlayingFile() could not stop playing");
2769 return -1;
2770 }
2771 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2772 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2773 _inputFilePlayerPtr = NULL;
2774 _inputFilePlaying = false;
2775
2776 return 0;
2777}
2778
2779int Channel::IsPlayingFileAsMicrophone() const
2780{
2781 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2782 "Channel::IsPlayingFileAsMicrophone()");
2783
2784 return _inputFilePlaying;
2785}
2786
pbos@webrtc.org92135212013-05-14 08:31:39 +00002787int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002788{
2789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2790 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2791
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002792 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002793
2794 if (!_inputFilePlaying)
2795 {
2796 _engineStatisticsPtr->SetLastError(
2797 VE_INVALID_OPERATION, kTraceError,
2798 "ScaleFileAsMicrophonePlayout() isnot playing");
2799 return -1;
2800 }
2801
2802 if ((_inputFilePlayerPtr == NULL) ||
2803 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2804 {
2805 _engineStatisticsPtr->SetLastError(
2806 VE_BAD_ARGUMENT, kTraceError,
2807 "SetAudioScaling() failed to scale playout");
2808 return -1;
2809 }
2810
2811 return 0;
2812}
2813
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002814int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002815 const CodecInst* codecInst)
2816{
2817 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2818 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2819
2820 if (_outputFileRecording)
2821 {
2822 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2823 "StartRecordingPlayout() is already recording");
2824 return 0;
2825 }
2826
2827 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002828 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002829 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2830
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002831 if ((codecInst != NULL) &&
2832 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002833 {
2834 _engineStatisticsPtr->SetLastError(
2835 VE_BAD_ARGUMENT, kTraceError,
2836 "StartRecordingPlayout() invalid compression");
2837 return(-1);
2838 }
2839 if(codecInst == NULL)
2840 {
2841 format = kFileFormatPcm16kHzFile;
2842 codecInst=&dummyCodec;
2843 }
2844 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2845 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2846 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2847 {
2848 format = kFileFormatWavFile;
2849 }
2850 else
2851 {
2852 format = kFileFormatCompressedFile;
2853 }
2854
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002855 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002856
2857 // Destroy the old instance
2858 if (_outputFileRecorderPtr)
2859 {
2860 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2861 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2862 _outputFileRecorderPtr = NULL;
2863 }
2864
2865 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2866 _outputFileRecorderId, (const FileFormats)format);
2867 if (_outputFileRecorderPtr == NULL)
2868 {
2869 _engineStatisticsPtr->SetLastError(
2870 VE_INVALID_ARGUMENT, kTraceError,
2871 "StartRecordingPlayout() fileRecorder format isnot correct");
2872 return -1;
2873 }
2874
2875 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2876 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2877 {
2878 _engineStatisticsPtr->SetLastError(
2879 VE_BAD_FILE, kTraceError,
2880 "StartRecordingAudioFile() failed to start file recording");
2881 _outputFileRecorderPtr->StopRecording();
2882 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2883 _outputFileRecorderPtr = NULL;
2884 return -1;
2885 }
2886 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2887 _outputFileRecording = true;
2888
2889 return 0;
2890}
2891
2892int Channel::StartRecordingPlayout(OutStream* stream,
2893 const CodecInst* codecInst)
2894{
2895 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2896 "Channel::StartRecordingPlayout()");
2897
2898 if (_outputFileRecording)
2899 {
2900 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2901 "StartRecordingPlayout() is already recording");
2902 return 0;
2903 }
2904
2905 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002906 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002907 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2908
2909 if (codecInst != NULL && codecInst->channels != 1)
2910 {
2911 _engineStatisticsPtr->SetLastError(
2912 VE_BAD_ARGUMENT, kTraceError,
2913 "StartRecordingPlayout() invalid compression");
2914 return(-1);
2915 }
2916 if(codecInst == NULL)
2917 {
2918 format = kFileFormatPcm16kHzFile;
2919 codecInst=&dummyCodec;
2920 }
2921 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2922 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2923 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2924 {
2925 format = kFileFormatWavFile;
2926 }
2927 else
2928 {
2929 format = kFileFormatCompressedFile;
2930 }
2931
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002932 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002933
2934 // Destroy the old instance
2935 if (_outputFileRecorderPtr)
2936 {
2937 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2938 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2939 _outputFileRecorderPtr = NULL;
2940 }
2941
2942 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2943 _outputFileRecorderId, (const FileFormats)format);
2944 if (_outputFileRecorderPtr == NULL)
2945 {
2946 _engineStatisticsPtr->SetLastError(
2947 VE_INVALID_ARGUMENT, kTraceError,
2948 "StartRecordingPlayout() fileRecorder format isnot correct");
2949 return -1;
2950 }
2951
2952 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2953 notificationTime) != 0)
2954 {
2955 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2956 "StartRecordingPlayout() failed to "
2957 "start file recording");
2958 _outputFileRecorderPtr->StopRecording();
2959 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2960 _outputFileRecorderPtr = NULL;
2961 return -1;
2962 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002963
niklase@google.com470e71d2011-07-07 08:21:25 +00002964 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2965 _outputFileRecording = true;
2966
2967 return 0;
2968}
2969
2970int Channel::StopRecordingPlayout()
2971{
2972 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2973 "Channel::StopRecordingPlayout()");
2974
2975 if (!_outputFileRecording)
2976 {
2977 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2978 "StopRecordingPlayout() isnot recording");
2979 return -1;
2980 }
2981
2982
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002983 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002984
2985 if (_outputFileRecorderPtr->StopRecording() != 0)
2986 {
2987 _engineStatisticsPtr->SetLastError(
2988 VE_STOP_RECORDING_FAILED, kTraceError,
2989 "StopRecording() could not stop recording");
2990 return(-1);
2991 }
2992 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2993 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2994 _outputFileRecorderPtr = NULL;
2995 _outputFileRecording = false;
2996
2997 return 0;
2998}
2999
3000void
3001Channel::SetMixWithMicStatus(bool mix)
3002{
3003 _mixFileWithMicrophone=mix;
3004}
3005
3006int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003007Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003008{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003009 int8_t currentLevel = _outputAudioLevel.Level();
3010 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003011 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3012 VoEId(_instanceId,_channelId),
3013 "GetSpeechOutputLevel() => level=%u", level);
3014 return 0;
3015}
3016
3017int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003018Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003019{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003020 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
3021 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003022 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3023 VoEId(_instanceId,_channelId),
3024 "GetSpeechOutputLevelFullRange() => level=%u", level);
3025 return 0;
3026}
3027
3028int
3029Channel::SetMute(bool enable)
3030{
3031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3032 "Channel::SetMute(enable=%d)", enable);
3033 _mute = enable;
3034 return 0;
3035}
3036
3037bool
3038Channel::Mute() const
3039{
3040 return _mute;
3041}
3042
3043int
3044Channel::SetOutputVolumePan(float left, float right)
3045{
3046 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3047 "Channel::SetOutputVolumePan()");
3048 _panLeft = left;
3049 _panRight = right;
3050 return 0;
3051}
3052
3053int
3054Channel::GetOutputVolumePan(float& left, float& right) const
3055{
3056 left = _panLeft;
3057 right = _panRight;
3058 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3059 VoEId(_instanceId,_channelId),
3060 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3061 return 0;
3062}
3063
3064int
3065Channel::SetChannelOutputVolumeScaling(float scaling)
3066{
3067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3068 "Channel::SetChannelOutputVolumeScaling()");
3069 _outputGain = scaling;
3070 return 0;
3071}
3072
3073int
3074Channel::GetChannelOutputVolumeScaling(float& scaling) const
3075{
3076 scaling = _outputGain;
3077 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3078 VoEId(_instanceId,_channelId),
3079 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3080 return 0;
3081}
3082
niklase@google.com470e71d2011-07-07 08:21:25 +00003083int
3084Channel::RegisterExternalEncryption(Encryption& encryption)
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3087 "Channel::RegisterExternalEncryption()");
3088
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003089 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003090
3091 if (_encryptionPtr)
3092 {
3093 _engineStatisticsPtr->SetLastError(
3094 VE_INVALID_OPERATION, kTraceError,
3095 "RegisterExternalEncryption() encryption already enabled");
3096 return -1;
3097 }
3098
3099 _encryptionPtr = &encryption;
3100
3101 _decrypting = true;
3102 _encrypting = true;
3103
3104 return 0;
3105}
3106
3107int
3108Channel::DeRegisterExternalEncryption()
3109{
3110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3111 "Channel::DeRegisterExternalEncryption()");
3112
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003113 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003114
3115 if (!_encryptionPtr)
3116 {
3117 _engineStatisticsPtr->SetLastError(
3118 VE_INVALID_OPERATION, kTraceWarning,
3119 "DeRegisterExternalEncryption() encryption already disabled");
3120 return 0;
3121 }
3122
3123 _decrypting = false;
3124 _encrypting = false;
3125
3126 _encryptionPtr = NULL;
3127
3128 return 0;
3129}
3130
3131int Channel::SendTelephoneEventOutband(unsigned char eventCode,
3132 int lengthMs, int attenuationDb,
3133 bool playDtmfEvent)
3134{
3135 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3136 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3137 playDtmfEvent);
3138
3139 _playOutbandDtmfEvent = playDtmfEvent;
3140
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003141 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003142 attenuationDb) != 0)
3143 {
3144 _engineStatisticsPtr->SetLastError(
3145 VE_SEND_DTMF_FAILED,
3146 kTraceWarning,
3147 "SendTelephoneEventOutband() failed to send event");
3148 return -1;
3149 }
3150 return 0;
3151}
3152
3153int Channel::SendTelephoneEventInband(unsigned char eventCode,
3154 int lengthMs,
3155 int attenuationDb,
3156 bool playDtmfEvent)
3157{
3158 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3159 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3160 playDtmfEvent);
3161
3162 _playInbandDtmfEvent = playDtmfEvent;
3163 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3164
3165 return 0;
3166}
3167
3168int
3169Channel::SetDtmfPlayoutStatus(bool enable)
3170{
3171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3172 "Channel::SetDtmfPlayoutStatus()");
3173 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3174 {
3175 _engineStatisticsPtr->SetLastError(
3176 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3177 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3178 return -1;
3179 }
3180 return 0;
3181}
3182
3183bool
3184Channel::DtmfPlayoutStatus() const
3185{
3186 return _audioCodingModule.DtmfPlayoutStatus();
3187}
3188
3189int
3190Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3191{
3192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3193 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003194 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003195 {
3196 _engineStatisticsPtr->SetLastError(
3197 VE_INVALID_ARGUMENT, kTraceError,
3198 "SetSendTelephoneEventPayloadType() invalid type");
3199 return -1;
3200 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003201 CodecInst codec;
3202 codec.plfreq = 8000;
3203 codec.pltype = type;
3204 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003205 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003206 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003207 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3208 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3209 _engineStatisticsPtr->SetLastError(
3210 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3211 "SetSendTelephoneEventPayloadType() failed to register send"
3212 "payload type");
3213 return -1;
3214 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003215 }
3216 _sendTelephoneEventPayloadType = type;
3217 return 0;
3218}
3219
3220int
3221Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3222{
3223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3224 "Channel::GetSendTelephoneEventPayloadType()");
3225 type = _sendTelephoneEventPayloadType;
3226 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3227 VoEId(_instanceId,_channelId),
3228 "GetSendTelephoneEventPayloadType() => type=%u", type);
3229 return 0;
3230}
3231
niklase@google.com470e71d2011-07-07 08:21:25 +00003232int
3233Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3234{
3235 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3236 "Channel::UpdateRxVadDetection()");
3237
3238 int vadDecision = 1;
3239
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003240 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003241
3242 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3243 {
3244 OnRxVadDetected(vadDecision);
3245 _oldVadDecision = vadDecision;
3246 }
3247
3248 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3249 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3250 vadDecision);
3251 return 0;
3252}
3253
3254int
3255Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3256{
3257 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3258 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003259 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003260
3261 if (_rxVadObserverPtr)
3262 {
3263 _engineStatisticsPtr->SetLastError(
3264 VE_INVALID_OPERATION, kTraceError,
3265 "RegisterRxVadObserver() observer already enabled");
3266 return -1;
3267 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003268 _rxVadObserverPtr = &observer;
3269 _RxVadDetection = true;
3270 return 0;
3271}
3272
3273int
3274Channel::DeRegisterRxVadObserver()
3275{
3276 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3277 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003278 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003279
3280 if (!_rxVadObserverPtr)
3281 {
3282 _engineStatisticsPtr->SetLastError(
3283 VE_INVALID_OPERATION, kTraceWarning,
3284 "DeRegisterRxVadObserver() observer already disabled");
3285 return 0;
3286 }
3287 _rxVadObserverPtr = NULL;
3288 _RxVadDetection = false;
3289 return 0;
3290}
3291
3292int
3293Channel::VoiceActivityIndicator(int &activity)
3294{
3295 activity = _sendFrameType;
3296
3297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3298 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3299 return 0;
3300}
3301
3302#ifdef WEBRTC_VOICE_ENGINE_AGC
3303
3304int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003305Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003306{
3307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3308 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3309 (int)enable, (int)mode);
3310
3311 GainControl::Mode agcMode(GainControl::kFixedDigital);
3312 switch (mode)
3313 {
3314 case kAgcDefault:
3315 agcMode = GainControl::kAdaptiveDigital;
3316 break;
3317 case kAgcUnchanged:
3318 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3319 break;
3320 case kAgcFixedDigital:
3321 agcMode = GainControl::kFixedDigital;
3322 break;
3323 case kAgcAdaptiveDigital:
3324 agcMode =GainControl::kAdaptiveDigital;
3325 break;
3326 default:
3327 _engineStatisticsPtr->SetLastError(
3328 VE_INVALID_ARGUMENT, kTraceError,
3329 "SetRxAgcStatus() invalid Agc mode");
3330 return -1;
3331 }
3332
3333 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3334 {
3335 _engineStatisticsPtr->SetLastError(
3336 VE_APM_ERROR, kTraceError,
3337 "SetRxAgcStatus() failed to set Agc mode");
3338 return -1;
3339 }
3340 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3341 {
3342 _engineStatisticsPtr->SetLastError(
3343 VE_APM_ERROR, kTraceError,
3344 "SetRxAgcStatus() failed to set Agc state");
3345 return -1;
3346 }
3347
3348 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003349 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3350
3351 return 0;
3352}
3353
3354int
3355Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3356{
3357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3358 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3359
3360 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3361 GainControl::Mode agcMode =
3362 _rxAudioProcessingModulePtr->gain_control()->mode();
3363
3364 enabled = enable;
3365
3366 switch (agcMode)
3367 {
3368 case GainControl::kFixedDigital:
3369 mode = kAgcFixedDigital;
3370 break;
3371 case GainControl::kAdaptiveDigital:
3372 mode = kAgcAdaptiveDigital;
3373 break;
3374 default:
3375 _engineStatisticsPtr->SetLastError(
3376 VE_APM_ERROR, kTraceError,
3377 "GetRxAgcStatus() invalid Agc mode");
3378 return -1;
3379 }
3380
3381 return 0;
3382}
3383
3384int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003385Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003386{
3387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3388 "Channel::SetRxAgcConfig()");
3389
3390 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3391 config.targetLeveldBOv) != 0)
3392 {
3393 _engineStatisticsPtr->SetLastError(
3394 VE_APM_ERROR, kTraceError,
3395 "SetRxAgcConfig() failed to set target peak |level|"
3396 "(or envelope) of the Agc");
3397 return -1;
3398 }
3399 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3400 config.digitalCompressionGaindB) != 0)
3401 {
3402 _engineStatisticsPtr->SetLastError(
3403 VE_APM_ERROR, kTraceError,
3404 "SetRxAgcConfig() failed to set the range in |gain| the"
3405 " digital compression stage may apply");
3406 return -1;
3407 }
3408 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3409 config.limiterEnable) != 0)
3410 {
3411 _engineStatisticsPtr->SetLastError(
3412 VE_APM_ERROR, kTraceError,
3413 "SetRxAgcConfig() failed to set hard limiter to the signal");
3414 return -1;
3415 }
3416
3417 return 0;
3418}
3419
3420int
3421Channel::GetRxAgcConfig(AgcConfig& config)
3422{
3423 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3424 "Channel::GetRxAgcConfig(config=%?)");
3425
3426 config.targetLeveldBOv =
3427 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3428 config.digitalCompressionGaindB =
3429 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3430 config.limiterEnable =
3431 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3432
3433 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3434 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3435 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3436 " limiterEnable=%d",
3437 config.targetLeveldBOv,
3438 config.digitalCompressionGaindB,
3439 config.limiterEnable);
3440
3441 return 0;
3442}
3443
3444#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3445
3446#ifdef WEBRTC_VOICE_ENGINE_NR
3447
3448int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003449Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003450{
3451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3452 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3453 (int)enable, (int)mode);
3454
3455 NoiseSuppression::Level nsLevel(
3456 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3457 switch (mode)
3458 {
3459
3460 case kNsDefault:
3461 nsLevel = (NoiseSuppression::Level)
3462 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3463 break;
3464 case kNsUnchanged:
3465 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3466 break;
3467 case kNsConference:
3468 nsLevel = NoiseSuppression::kHigh;
3469 break;
3470 case kNsLowSuppression:
3471 nsLevel = NoiseSuppression::kLow;
3472 break;
3473 case kNsModerateSuppression:
3474 nsLevel = NoiseSuppression::kModerate;
3475 break;
3476 case kNsHighSuppression:
3477 nsLevel = NoiseSuppression::kHigh;
3478 break;
3479 case kNsVeryHighSuppression:
3480 nsLevel = NoiseSuppression::kVeryHigh;
3481 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003482 }
3483
3484 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3485 != 0)
3486 {
3487 _engineStatisticsPtr->SetLastError(
3488 VE_APM_ERROR, kTraceError,
3489 "SetRxAgcStatus() failed to set Ns level");
3490 return -1;
3491 }
3492 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3493 {
3494 _engineStatisticsPtr->SetLastError(
3495 VE_APM_ERROR, kTraceError,
3496 "SetRxAgcStatus() failed to set Agc state");
3497 return -1;
3498 }
3499
3500 _rxNsIsEnabled = enable;
3501 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3502
3503 return 0;
3504}
3505
3506int
3507Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3508{
3509 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3510 "Channel::GetRxNsStatus(enable=?, mode=?)");
3511
3512 bool enable =
3513 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3514 NoiseSuppression::Level ncLevel =
3515 _rxAudioProcessingModulePtr->noise_suppression()->level();
3516
3517 enabled = enable;
3518
3519 switch (ncLevel)
3520 {
3521 case NoiseSuppression::kLow:
3522 mode = kNsLowSuppression;
3523 break;
3524 case NoiseSuppression::kModerate:
3525 mode = kNsModerateSuppression;
3526 break;
3527 case NoiseSuppression::kHigh:
3528 mode = kNsHighSuppression;
3529 break;
3530 case NoiseSuppression::kVeryHigh:
3531 mode = kNsVeryHighSuppression;
3532 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003533 }
3534
3535 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3536 VoEId(_instanceId,_channelId),
3537 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3538 return 0;
3539}
3540
3541#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3542
3543int
3544Channel::RegisterRTPObserver(VoERTPObserver& observer)
3545{
3546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3547 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003548 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003549
3550 if (_rtpObserverPtr)
3551 {
3552 _engineStatisticsPtr->SetLastError(
3553 VE_INVALID_OPERATION, kTraceError,
3554 "RegisterRTPObserver() observer already enabled");
3555 return -1;
3556 }
3557
3558 _rtpObserverPtr = &observer;
3559 _rtpObserver = true;
3560
3561 return 0;
3562}
3563
3564int
3565Channel::DeRegisterRTPObserver()
3566{
3567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3568 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003569 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003570
3571 if (!_rtpObserverPtr)
3572 {
3573 _engineStatisticsPtr->SetLastError(
3574 VE_INVALID_OPERATION, kTraceWarning,
3575 "DeRegisterRTPObserver() observer already disabled");
3576 return 0;
3577 }
3578
3579 _rtpObserver = false;
3580 _rtpObserverPtr = NULL;
3581
3582 return 0;
3583}
3584
3585int
3586Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3587{
3588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3589 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003590 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003591
3592 if (_rtcpObserverPtr)
3593 {
3594 _engineStatisticsPtr->SetLastError(
3595 VE_INVALID_OPERATION, kTraceError,
3596 "RegisterRTCPObserver() observer already enabled");
3597 return -1;
3598 }
3599
3600 _rtcpObserverPtr = &observer;
3601 _rtcpObserver = true;
3602
3603 return 0;
3604}
3605
3606int
3607Channel::DeRegisterRTCPObserver()
3608{
3609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3610 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003611 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003612
3613 if (!_rtcpObserverPtr)
3614 {
3615 _engineStatisticsPtr->SetLastError(
3616 VE_INVALID_OPERATION, kTraceWarning,
3617 "DeRegisterRTCPObserver() observer already disabled");
3618 return 0;
3619 }
3620
3621 _rtcpObserver = false;
3622 _rtcpObserverPtr = NULL;
3623
3624 return 0;
3625}
3626
3627int
3628Channel::SetLocalSSRC(unsigned int ssrc)
3629{
3630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3631 "Channel::SetLocalSSRC()");
3632 if (_sending)
3633 {
3634 _engineStatisticsPtr->SetLastError(
3635 VE_ALREADY_SENDING, kTraceError,
3636 "SetLocalSSRC() already sending");
3637 return -1;
3638 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003639 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003640 {
3641 _engineStatisticsPtr->SetLastError(
3642 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3643 "SetLocalSSRC() failed to set SSRC");
3644 return -1;
3645 }
3646 return 0;
3647}
3648
3649int
3650Channel::GetLocalSSRC(unsigned int& ssrc)
3651{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003652 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003653 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3654 VoEId(_instanceId,_channelId),
3655 "GetLocalSSRC() => ssrc=%lu", ssrc);
3656 return 0;
3657}
3658
3659int
3660Channel::GetRemoteSSRC(unsigned int& ssrc)
3661{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003662 ssrc = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003663 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3664 VoEId(_instanceId,_channelId),
3665 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3666 return 0;
3667}
3668
3669int
3670Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3671{
3672 if (arrCSRC == NULL)
3673 {
3674 _engineStatisticsPtr->SetLastError(
3675 VE_INVALID_ARGUMENT, kTraceError,
3676 "GetRemoteCSRCs() invalid array argument");
3677 return -1;
3678 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003679 uint32_t arrOfCSRC[kRtpCsrcSize];
3680 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003681 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003682 if (CSRCs > 0)
3683 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003684 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003685 for (int i = 0; i < (int) CSRCs; i++)
3686 {
3687 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3688 VoEId(_instanceId, _channelId),
3689 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3690 }
3691 } else
3692 {
3693 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3694 VoEId(_instanceId, _channelId),
3695 "GetRemoteCSRCs() => list is empty!");
3696 }
3697 return CSRCs;
3698}
3699
3700int
3701Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3702{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003703 if (_rtpAudioProc.get() == NULL)
3704 {
3705 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3706 _channelId)));
3707 if (_rtpAudioProc.get() == NULL)
3708 {
3709 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3710 "Failed to create AudioProcessing");
3711 return -1;
3712 }
3713 }
3714
3715 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3716 AudioProcessing::kNoError)
3717 {
3718 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3719 "Failed to enable AudioProcessing::level_estimator()");
3720 }
3721
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 _includeAudioLevelIndication = enable;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00003723 if (enable) {
3724 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3725 ID);
3726 } else {
3727 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3728 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003729 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003730}
3731int
3732Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3733{
3734 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3735 VoEId(_instanceId,_channelId),
3736 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3737 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003738 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003739}
3740
3741int
3742Channel::SetRTCPStatus(bool enable)
3743{
3744 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3745 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003746 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003747 kRtcpCompound : kRtcpOff) != 0)
3748 {
3749 _engineStatisticsPtr->SetLastError(
3750 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3751 "SetRTCPStatus() failed to set RTCP status");
3752 return -1;
3753 }
3754 return 0;
3755}
3756
3757int
3758Channel::GetRTCPStatus(bool& enabled)
3759{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003760 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003761 enabled = (method != kRtcpOff);
3762 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3763 VoEId(_instanceId,_channelId),
3764 "GetRTCPStatus() => enabled=%d", enabled);
3765 return 0;
3766}
3767
3768int
3769Channel::SetRTCP_CNAME(const char cName[256])
3770{
3771 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3772 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003773 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003774 {
3775 _engineStatisticsPtr->SetLastError(
3776 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3777 "SetRTCP_CNAME() failed to set RTCP CNAME");
3778 return -1;
3779 }
3780 return 0;
3781}
3782
3783int
3784Channel::GetRTCP_CNAME(char cName[256])
3785{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003786 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003787 {
3788 _engineStatisticsPtr->SetLastError(
3789 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3790 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3791 return -1;
3792 }
3793 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3794 VoEId(_instanceId, _channelId),
3795 "GetRTCP_CNAME() => cName=%s", cName);
3796 return 0;
3797}
3798
3799int
3800Channel::GetRemoteRTCP_CNAME(char cName[256])
3801{
3802 if (cName == NULL)
3803 {
3804 _engineStatisticsPtr->SetLastError(
3805 VE_INVALID_ARGUMENT, kTraceError,
3806 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3807 return -1;
3808 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003809 char cname[RTCP_CNAME_SIZE];
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003810 const uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003811 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003812 {
3813 _engineStatisticsPtr->SetLastError(
3814 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3815 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3816 return -1;
3817 }
3818 strcpy(cName, cname);
3819 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3820 VoEId(_instanceId, _channelId),
3821 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3822 return 0;
3823}
3824
3825int
3826Channel::GetRemoteRTCPData(
3827 unsigned int& NTPHigh,
3828 unsigned int& NTPLow,
3829 unsigned int& timestamp,
3830 unsigned int& playoutTimestamp,
3831 unsigned int* jitter,
3832 unsigned short* fractionLost)
3833{
3834 // --- Information from sender info in received Sender Reports
3835
3836 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003837 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003838 {
3839 _engineStatisticsPtr->SetLastError(
3840 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003841 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003842 "side");
3843 return -1;
3844 }
3845
3846 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3847 // and octet count)
3848 NTPHigh = senderInfo.NTPseconds;
3849 NTPLow = senderInfo.NTPfraction;
3850 timestamp = senderInfo.RTPtimeStamp;
3851
3852 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3853 VoEId(_instanceId, _channelId),
3854 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3855 "timestamp=%lu",
3856 NTPHigh, NTPLow, timestamp);
3857
3858 // --- Locally derived information
3859
3860 // This value is updated on each incoming RTCP packet (0 when no packet
3861 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003862 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003863
3864 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3865 VoEId(_instanceId, _channelId),
3866 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003867 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003868
3869 if (NULL != jitter || NULL != fractionLost)
3870 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003871 // Get all RTCP receiver report blocks that have been received on this
3872 // channel. If we receive RTP packets from a remote source we know the
3873 // remote SSRC and use the report block from him.
3874 // Otherwise use the first report block.
3875 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003876 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003877 remote_stats.empty()) {
3878 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3879 VoEId(_instanceId, _channelId),
3880 "GetRemoteRTCPData() failed to measure statistics due"
3881 " to lack of received RTP and/or RTCP packets");
3882 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003883 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003884
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003885 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003886 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3887 for (; it != remote_stats.end(); ++it) {
3888 if (it->remoteSSRC == remoteSSRC)
3889 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003891
3892 if (it == remote_stats.end()) {
3893 // If we have not received any RTCP packets from this SSRC it probably
3894 // means that we have not received any RTP packets.
3895 // Use the first received report block instead.
3896 it = remote_stats.begin();
3897 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003898 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003899
xians@webrtc.org79af7342012-01-31 12:22:14 +00003900 if (jitter) {
3901 *jitter = it->jitter;
3902 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3903 VoEId(_instanceId, _channelId),
3904 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3905 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003906
xians@webrtc.org79af7342012-01-31 12:22:14 +00003907 if (fractionLost) {
3908 *fractionLost = it->fractionLost;
3909 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3910 VoEId(_instanceId, _channelId),
3911 "GetRemoteRTCPData() => fractionLost = %lu",
3912 *fractionLost);
3913 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 }
3915 return 0;
3916}
3917
3918int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003919Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003920 unsigned int name,
3921 const char* data,
3922 unsigned short dataLengthInBytes)
3923{
3924 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3925 "Channel::SendApplicationDefinedRTCPPacket()");
3926 if (!_sending)
3927 {
3928 _engineStatisticsPtr->SetLastError(
3929 VE_NOT_SENDING, kTraceError,
3930 "SendApplicationDefinedRTCPPacket() not sending");
3931 return -1;
3932 }
3933 if (NULL == data)
3934 {
3935 _engineStatisticsPtr->SetLastError(
3936 VE_INVALID_ARGUMENT, kTraceError,
3937 "SendApplicationDefinedRTCPPacket() invalid data value");
3938 return -1;
3939 }
3940 if (dataLengthInBytes % 4 != 0)
3941 {
3942 _engineStatisticsPtr->SetLastError(
3943 VE_INVALID_ARGUMENT, kTraceError,
3944 "SendApplicationDefinedRTCPPacket() invalid length value");
3945 return -1;
3946 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003947 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003948 if (status == kRtcpOff)
3949 {
3950 _engineStatisticsPtr->SetLastError(
3951 VE_RTCP_ERROR, kTraceError,
3952 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3953 return -1;
3954 }
3955
3956 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003957 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003958 subType,
3959 name,
3960 (const unsigned char*) data,
3961 dataLengthInBytes) != 0)
3962 {
3963 _engineStatisticsPtr->SetLastError(
3964 VE_SEND_ERROR, kTraceError,
3965 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3966 return -1;
3967 }
3968 return 0;
3969}
3970
3971int
3972Channel::GetRTPStatistics(
3973 unsigned int& averageJitterMs,
3974 unsigned int& maxJitterMs,
3975 unsigned int& discardedPackets)
3976{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003977 uint8_t fraction_lost(0);
3978 uint32_t cum_lost(0);
3979 uint32_t ext_max(0);
3980 uint32_t jitter(0);
3981 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003982
3983 // The jitter statistics is updated for each received RTP packet and is
3984 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003985 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00003986 &cum_lost,
3987 &ext_max,
3988 &jitter,
3989 &max_jitter) != 0)
3990 {
3991 _engineStatisticsPtr->SetLastError(
3992 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003993 "GetRTPStatistics() failed to read RTP statistics from the "
niklase@google.com470e71d2011-07-07 08:21:25 +00003994 "RTP/RTCP module");
3995 }
3996
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003997 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00003998 _audioCodingModule.PlayoutFrequency();
3999 if (playoutFrequency > 0)
4000 {
4001 // Scale RTP statistics given the current playout frequency
4002 maxJitterMs = max_jitter / (playoutFrequency / 1000);
4003 averageJitterMs = jitter / (playoutFrequency / 1000);
4004 }
4005
4006 discardedPackets = _numberOfDiscardedPackets;
4007
4008 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4009 VoEId(_instanceId, _channelId),
4010 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004011 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004012 averageJitterMs, maxJitterMs, discardedPackets);
4013 return 0;
4014}
4015
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00004016int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
4017 if (sender_info == NULL) {
4018 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4019 "GetRemoteRTCPSenderInfo() invalid sender_info.");
4020 return -1;
4021 }
4022
4023 // Get the sender info from the latest received RTCP Sender Report.
4024 RTCPSenderInfo rtcp_sender_info;
4025 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
4026 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4027 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
4028 return -1;
4029 }
4030
4031 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
4032 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
4033 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
4034 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
4035 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
4036 return 0;
4037}
4038
4039int Channel::GetRemoteRTCPReportBlocks(
4040 std::vector<ReportBlock>* report_blocks) {
4041 if (report_blocks == NULL) {
4042 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4043 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4044 return -1;
4045 }
4046
4047 // Get the report blocks from the latest received RTCP Sender or Receiver
4048 // Report. Each element in the vector contains the sender's SSRC and a
4049 // report block according to RFC 3550.
4050 std::vector<RTCPReportBlock> rtcp_report_blocks;
4051 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4052 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4053 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4054 return -1;
4055 }
4056
4057 if (rtcp_report_blocks.empty())
4058 return 0;
4059
4060 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4061 for (; it != rtcp_report_blocks.end(); ++it) {
4062 ReportBlock report_block;
4063 report_block.sender_SSRC = it->remoteSSRC;
4064 report_block.source_SSRC = it->sourceSSRC;
4065 report_block.fraction_lost = it->fractionLost;
4066 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4067 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4068 report_block.interarrival_jitter = it->jitter;
4069 report_block.last_SR_timestamp = it->lastSR;
4070 report_block.delay_since_last_SR = it->delaySinceLastSR;
4071 report_blocks->push_back(report_block);
4072 }
4073 return 0;
4074}
4075
niklase@google.com470e71d2011-07-07 08:21:25 +00004076int
4077Channel::GetRTPStatistics(CallStatistics& stats)
4078{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004079 uint8_t fraction_lost(0);
4080 uint32_t cum_lost(0);
4081 uint32_t ext_max(0);
4082 uint32_t jitter(0);
4083 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004084
4085 // --- Part one of the final structure (four values)
4086
4087 // The jitter statistics is updated for each received RTP packet and is
4088 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004089 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00004090 &cum_lost,
4091 &ext_max,
4092 &jitter,
4093 &max_jitter) != 0)
4094 {
4095 _engineStatisticsPtr->SetLastError(
4096 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4097 "GetRTPStatistics() failed to read RTP statistics from the "
4098 "RTP/RTCP module");
4099 }
4100
4101 stats.fractionLost = fraction_lost;
4102 stats.cumulativeLost = cum_lost;
4103 stats.extendedMax = ext_max;
4104 stats.jitterSamples = jitter;
4105
4106 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4107 VoEId(_instanceId, _channelId),
4108 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004109 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004110 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4111 stats.jitterSamples);
4112
4113 // --- Part two of the final structure (one value)
4114
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004115 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004116 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004117 if (method == kRtcpOff)
4118 {
4119 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4120 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004121 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004122 "measurements cannot be retrieved");
4123 } else
4124 {
4125 // The remote SSRC will be zero if no RTP packet has been received.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004126 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004127 if (remoteSSRC > 0)
4128 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004129 uint16_t avgRTT(0);
4130 uint16_t maxRTT(0);
4131 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004132
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004133 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004134 != 0)
4135 {
4136 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4137 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004138 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004139 "the RTP/RTCP module");
4140 }
4141 } else
4142 {
4143 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4144 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004145 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004146 "RTP packets have been received yet");
4147 }
4148 }
4149
4150 stats.rttMs = static_cast<int> (RTT);
4151
4152 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4153 VoEId(_instanceId, _channelId),
4154 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4155
4156 // --- Part three of the final structure (four values)
4157
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004158 uint32_t bytesSent(0);
4159 uint32_t packetsSent(0);
4160 uint32_t bytesReceived(0);
4161 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004162
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004163 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
niklase@google.com470e71d2011-07-07 08:21:25 +00004164 &packetsSent,
4165 &bytesReceived,
4166 &packetsReceived) != 0)
4167 {
4168 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4169 VoEId(_instanceId, _channelId),
4170 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004171 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004172 }
4173
4174 stats.bytesSent = bytesSent;
4175 stats.packetsSent = packetsSent;
4176 stats.bytesReceived = bytesReceived;
4177 stats.packetsReceived = packetsReceived;
4178
4179 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4180 VoEId(_instanceId, _channelId),
4181 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004182 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004183 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4184 stats.packetsReceived);
4185
4186 return 0;
4187}
4188
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004189int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4190 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4191 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004192
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004193 if (enable) {
4194 if (redPayloadtype < 0 || redPayloadtype > 127) {
4195 _engineStatisticsPtr->SetLastError(
4196 VE_PLTYPE_ERROR, kTraceError,
4197 "SetFECStatus() invalid RED payload type");
4198 return -1;
4199 }
4200
4201 if (SetRedPayloadType(redPayloadtype) < 0) {
4202 _engineStatisticsPtr->SetLastError(
4203 VE_CODEC_ERROR, kTraceError,
4204 "SetSecondarySendCodec() Failed to register RED ACM");
4205 return -1;
4206 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004207 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004208
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004209 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4210 _engineStatisticsPtr->SetLastError(
4211 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4212 "SetFECStatus() failed to set FEC state in the ACM");
4213 return -1;
4214 }
4215 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004216}
4217
4218int
4219Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4220{
4221 enabled = _audioCodingModule.FECStatus();
4222 if (enabled)
4223 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004224 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004225 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004226 {
4227 _engineStatisticsPtr->SetLastError(
4228 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4229 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4230 "module");
4231 return -1;
4232 }
4233 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4234 VoEId(_instanceId, _channelId),
4235 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4236 enabled, redPayloadtype);
4237 return 0;
4238 }
4239 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4240 VoEId(_instanceId, _channelId),
4241 "GetFECStatus() => enabled=%d", enabled);
4242 return 0;
4243}
4244
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004245void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4246 // None of these functions can fail.
4247 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
4248 _rtpRtcpModule->SetNACKStatus(enable ? kNackRtcp : kNackOff,
4249 maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004250 if (enable)
4251 _audioCodingModule.EnableNack(maxNumberOfPackets);
4252 else
4253 _audioCodingModule.DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004254}
4255
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004256// Called when we are missing one or more packets.
4257int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004258 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4259}
4260
niklase@google.com470e71d2011-07-07 08:21:25 +00004261int
niklase@google.com470e71d2011-07-07 08:21:25 +00004262Channel::StartRTPDump(const char fileNameUTF8[1024],
4263 RTPDirections direction)
4264{
4265 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4266 "Channel::StartRTPDump()");
4267 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4268 {
4269 _engineStatisticsPtr->SetLastError(
4270 VE_INVALID_ARGUMENT, kTraceError,
4271 "StartRTPDump() invalid RTP direction");
4272 return -1;
4273 }
4274 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4275 &_rtpDumpIn : &_rtpDumpOut;
4276 if (rtpDumpPtr == NULL)
4277 {
4278 assert(false);
4279 return -1;
4280 }
4281 if (rtpDumpPtr->IsActive())
4282 {
4283 rtpDumpPtr->Stop();
4284 }
4285 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4286 {
4287 _engineStatisticsPtr->SetLastError(
4288 VE_BAD_FILE, kTraceError,
4289 "StartRTPDump() failed to create file");
4290 return -1;
4291 }
4292 return 0;
4293}
4294
4295int
4296Channel::StopRTPDump(RTPDirections direction)
4297{
4298 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4299 "Channel::StopRTPDump()");
4300 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4301 {
4302 _engineStatisticsPtr->SetLastError(
4303 VE_INVALID_ARGUMENT, kTraceError,
4304 "StopRTPDump() invalid RTP direction");
4305 return -1;
4306 }
4307 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4308 &_rtpDumpIn : &_rtpDumpOut;
4309 if (rtpDumpPtr == NULL)
4310 {
4311 assert(false);
4312 return -1;
4313 }
4314 if (!rtpDumpPtr->IsActive())
4315 {
4316 return 0;
4317 }
4318 return rtpDumpPtr->Stop();
4319}
4320
4321bool
4322Channel::RTPDumpIsActive(RTPDirections direction)
4323{
4324 if ((direction != kRtpIncoming) &&
4325 (direction != kRtpOutgoing))
4326 {
4327 _engineStatisticsPtr->SetLastError(
4328 VE_INVALID_ARGUMENT, kTraceError,
4329 "RTPDumpIsActive() invalid RTP direction");
4330 return false;
4331 }
4332 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4333 &_rtpDumpIn : &_rtpDumpOut;
4334 return rtpDumpPtr->IsActive();
4335}
4336
4337int
4338Channel::InsertExtraRTPPacket(unsigned char payloadType,
4339 bool markerBit,
4340 const char* payloadData,
4341 unsigned short payloadSize)
4342{
4343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4344 "Channel::InsertExtraRTPPacket()");
4345 if (payloadType > 127)
4346 {
4347 _engineStatisticsPtr->SetLastError(
4348 VE_INVALID_PLTYPE, kTraceError,
4349 "InsertExtraRTPPacket() invalid payload type");
4350 return -1;
4351 }
4352 if (payloadData == NULL)
4353 {
4354 _engineStatisticsPtr->SetLastError(
4355 VE_INVALID_ARGUMENT, kTraceError,
4356 "InsertExtraRTPPacket() invalid payload data");
4357 return -1;
4358 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004359 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004360 {
4361 _engineStatisticsPtr->SetLastError(
4362 VE_INVALID_ARGUMENT, kTraceError,
4363 "InsertExtraRTPPacket() invalid payload size");
4364 return -1;
4365 }
4366 if (!_sending)
4367 {
4368 _engineStatisticsPtr->SetLastError(
4369 VE_NOT_SENDING, kTraceError,
4370 "InsertExtraRTPPacket() not sending");
4371 return -1;
4372 }
4373
4374 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4375 // Transport::SendPacket() will be called by the module when the RTP packet
4376 // is created.
4377 // The call to SendOutgoingData() does *not* modify the timestamp and
4378 // payloadtype to ensure that the RTP module generates a valid RTP packet
4379 // (user might utilize a non-registered payload type).
4380 // The marker bit and payload type will be replaced just before the actual
4381 // transmission, i.e., the actual modification is done *after* the RTP
4382 // module has delivered its RTP packet back to the VoE.
4383 // We will use the stored values above when the packet is modified
4384 // (see Channel::SendPacket()).
4385
4386 _extraPayloadType = payloadType;
4387 _extraMarkerBit = markerBit;
4388 _insertExtraRTPPacket = true;
4389
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004390 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004391 _lastPayloadType,
4392 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004393 // Leaving the time when this frame was
4394 // received from the capture device as
4395 // undefined for voice for now.
4396 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004397 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004398 payloadSize) != 0)
4399 {
4400 _engineStatisticsPtr->SetLastError(
4401 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4402 "InsertExtraRTPPacket() failed to send extra RTP packet");
4403 return -1;
4404 }
4405
4406 return 0;
4407}
4408
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004409uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004410Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004411{
4412 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004413 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004414 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004415 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004416 return 0;
4417}
4418
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004419uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004420Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004421{
4422 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4423 "Channel::PrepareEncodeAndSend()");
4424
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004425 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004426 {
4427 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4428 "Channel::PrepareEncodeAndSend() invalid audio frame");
4429 return -1;
4430 }
4431
4432 if (_inputFilePlaying)
4433 {
4434 MixOrReplaceAudioWithFile(mixingFrequency);
4435 }
4436
4437 if (_mute)
4438 {
4439 AudioFrameOperations::Mute(_audioFrame);
4440 }
4441
4442 if (_inputExternalMedia)
4443 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004444 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004445 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004446 if (_inputExternalMediaCallbackPtr)
4447 {
4448 _inputExternalMediaCallbackPtr->Process(
4449 _channelId,
4450 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004451 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004452 _audioFrame.samples_per_channel_,
4453 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004454 isStereo);
4455 }
4456 }
4457
4458 InsertInbandDtmfTone();
4459
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004460 if (_includeAudioLevelIndication)
4461 {
4462 assert(_rtpAudioProc.get() != NULL);
4463
4464 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004465 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004466 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004467 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004468 AudioProcessing::kNoError)
4469 {
4470 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4471 VoEId(_instanceId, _channelId),
4472 "Error setting AudioProcessing sample rate");
4473 return -1;
4474 }
4475 }
4476
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004477 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004478 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004479 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4480 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004481 != AudioProcessing::kNoError)
4482 {
4483 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4484 VoEId(_instanceId, _channelId),
4485 "Error setting AudioProcessing channels");
4486 return -1;
4487 }
4488 }
4489
4490 // Performs level analysis only; does not affect the signal.
4491 _rtpAudioProc->ProcessStream(&_audioFrame);
4492 }
4493
niklase@google.com470e71d2011-07-07 08:21:25 +00004494 return 0;
4495}
4496
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004497uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004498Channel::EncodeAndSend()
4499{
4500 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4501 "Channel::EncodeAndSend()");
4502
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004503 assert(_audioFrame.num_channels_ <= 2);
4504 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004505 {
4506 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4507 "Channel::EncodeAndSend() invalid audio frame");
4508 return -1;
4509 }
4510
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004511 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004512
4513 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4514
4515 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004516 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004517 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4518 {
4519 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4520 "Channel::EncodeAndSend() ACM encoding failed");
4521 return -1;
4522 }
4523
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004524 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004525
4526 // --- Encode if complete frame is ready
4527
4528 // This call will trigger AudioPacketizationCallback::SendData if encoding
4529 // is done and payload is ready for packetization and transmission.
4530 return _audioCodingModule.Process();
4531}
4532
4533int Channel::RegisterExternalMediaProcessing(
4534 ProcessingTypes type,
4535 VoEMediaProcess& processObject)
4536{
4537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4538 "Channel::RegisterExternalMediaProcessing()");
4539
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004540 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004541
4542 if (kPlaybackPerChannel == type)
4543 {
4544 if (_outputExternalMediaCallbackPtr)
4545 {
4546 _engineStatisticsPtr->SetLastError(
4547 VE_INVALID_OPERATION, kTraceError,
4548 "Channel::RegisterExternalMediaProcessing() "
4549 "output external media already enabled");
4550 return -1;
4551 }
4552 _outputExternalMediaCallbackPtr = &processObject;
4553 _outputExternalMedia = true;
4554 }
4555 else if (kRecordingPerChannel == type)
4556 {
4557 if (_inputExternalMediaCallbackPtr)
4558 {
4559 _engineStatisticsPtr->SetLastError(
4560 VE_INVALID_OPERATION, kTraceError,
4561 "Channel::RegisterExternalMediaProcessing() "
4562 "output external media already enabled");
4563 return -1;
4564 }
4565 _inputExternalMediaCallbackPtr = &processObject;
4566 _inputExternalMedia = true;
4567 }
4568 return 0;
4569}
4570
4571int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4572{
4573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4574 "Channel::DeRegisterExternalMediaProcessing()");
4575
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004576 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004577
4578 if (kPlaybackPerChannel == type)
4579 {
4580 if (!_outputExternalMediaCallbackPtr)
4581 {
4582 _engineStatisticsPtr->SetLastError(
4583 VE_INVALID_OPERATION, kTraceWarning,
4584 "Channel::DeRegisterExternalMediaProcessing() "
4585 "output external media already disabled");
4586 return 0;
4587 }
4588 _outputExternalMedia = false;
4589 _outputExternalMediaCallbackPtr = NULL;
4590 }
4591 else if (kRecordingPerChannel == type)
4592 {
4593 if (!_inputExternalMediaCallbackPtr)
4594 {
4595 _engineStatisticsPtr->SetLastError(
4596 VE_INVALID_OPERATION, kTraceWarning,
4597 "Channel::DeRegisterExternalMediaProcessing() "
4598 "input external media already disabled");
4599 return 0;
4600 }
4601 _inputExternalMedia = false;
4602 _inputExternalMediaCallbackPtr = NULL;
4603 }
4604
4605 return 0;
4606}
4607
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004608int Channel::SetExternalMixing(bool enabled) {
4609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4610 "Channel::SetExternalMixing(enabled=%d)", enabled);
4611
4612 if (_playing)
4613 {
4614 _engineStatisticsPtr->SetLastError(
4615 VE_INVALID_OPERATION, kTraceError,
4616 "Channel::SetExternalMixing() "
4617 "external mixing cannot be changed while playing.");
4618 return -1;
4619 }
4620
4621 _externalMixing = enabled;
4622
4623 return 0;
4624}
4625
niklase@google.com470e71d2011-07-07 08:21:25 +00004626int
4627Channel::ResetRTCPStatistics()
4628{
4629 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4630 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004631 uint32_t remoteSSRC(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004632 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4633 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004634}
4635
4636int
4637Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4638{
4639 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4640 "Channel::GetRoundTripTimeSummary()");
4641 // Override default module outputs for the case when RTCP is disabled.
4642 // This is done to ensure that we are backward compatible with the
4643 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004644 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004645 {
4646 delaysMs.min = -1;
4647 delaysMs.max = -1;
4648 delaysMs.average = -1;
4649 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4650 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4651 " valid RTT measurements cannot be retrieved");
4652 return 0;
4653 }
4654
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004655 uint32_t remoteSSRC;
4656 uint16_t RTT;
4657 uint16_t avgRTT;
4658 uint16_t maxRTT;
4659 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004660 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004661 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004662 if (remoteSSRC == 0)
4663 {
4664 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4665 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4666 " since no RTP packet has been received yet");
4667 }
4668
4669 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4670 // channel and SSRC. The SSRC is required to parse out the correct source
4671 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004672 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004673 {
4674 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4675 "GetRoundTripTimeSummary unable to retrieve RTT values"
4676 " from the RTCP layer");
4677 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4678 }
4679 else
4680 {
4681 delaysMs.min = minRTT;
4682 delaysMs.max = maxRTT;
4683 delaysMs.average = avgRTT;
4684 }
4685 return 0;
4686}
4687
4688int
4689Channel::GetNetworkStatistics(NetworkStatistics& stats)
4690{
4691 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4692 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004693 ACMNetworkStatistics acm_stats;
4694 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4695 if (return_value >= 0) {
4696 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4697 }
4698 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004699}
4700
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004701bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4702 int* playout_buffer_delay_ms) const {
4703 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004704 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004705 "Channel::GetDelayEstimate() no valid estimate.");
4706 return false;
4707 }
4708 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4709 _recPacketDelayMs;
4710 *playout_buffer_delay_ms = playout_delay_ms_;
4711 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4712 "Channel::GetDelayEstimate()");
4713 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004714}
4715
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004716int Channel::SetInitialPlayoutDelay(int delay_ms)
4717{
4718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4719 "Channel::SetInitialPlayoutDelay()");
4720 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4721 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4722 {
4723 _engineStatisticsPtr->SetLastError(
4724 VE_INVALID_ARGUMENT, kTraceError,
4725 "SetInitialPlayoutDelay() invalid min delay");
4726 return -1;
4727 }
4728 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4729 {
4730 _engineStatisticsPtr->SetLastError(
4731 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4732 "SetInitialPlayoutDelay() failed to set min playout delay");
4733 return -1;
4734 }
4735 return 0;
4736}
4737
4738
niklase@google.com470e71d2011-07-07 08:21:25 +00004739int
4740Channel::SetMinimumPlayoutDelay(int delayMs)
4741{
4742 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4743 "Channel::SetMinimumPlayoutDelay()");
4744 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4745 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4746 {
4747 _engineStatisticsPtr->SetLastError(
4748 VE_INVALID_ARGUMENT, kTraceError,
4749 "SetMinimumPlayoutDelay() invalid min delay");
4750 return -1;
4751 }
4752 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4753 {
4754 _engineStatisticsPtr->SetLastError(
4755 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4756 "SetMinimumPlayoutDelay() failed to set min playout delay");
4757 return -1;
4758 }
4759 return 0;
4760}
4761
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004762void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4763 uint32_t playout_timestamp = 0;
4764
4765 if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1) {
4766 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4767 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4768 " timestamp from the ACM");
4769 _engineStatisticsPtr->SetLastError(
4770 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4771 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4772 return;
4773 }
4774
4775 uint16_t delay_ms = 0;
4776 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4777 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4778 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4779 " delay from the ADM");
4780 _engineStatisticsPtr->SetLastError(
4781 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4782 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4783 return;
4784 }
4785
4786 int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
4787 CodecInst current_recive_codec;
4788 if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
4789 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4790 playout_frequency = 8000;
4791 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4792 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004793 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004794 }
4795
4796 // Remove the playout delay.
4797 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4798
4799 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4800 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4801 playout_timestamp);
4802
4803 if (rtcp) {
4804 playout_timestamp_rtcp_ = playout_timestamp;
4805 } else {
4806 playout_timestamp_rtp_ = playout_timestamp;
4807 }
4808 playout_delay_ms_ = delay_ms;
4809}
4810
4811int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4812 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4813 "Channel::GetPlayoutTimestamp()");
4814 if (playout_timestamp_rtp_ == 0) {
4815 _engineStatisticsPtr->SetLastError(
4816 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4817 "GetPlayoutTimestamp() failed to retrieve timestamp");
4818 return -1;
4819 }
4820 timestamp = playout_timestamp_rtp_;
4821 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4822 VoEId(_instanceId,_channelId),
4823 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4824 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004825}
4826
4827int
4828Channel::SetInitTimestamp(unsigned int timestamp)
4829{
4830 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4831 "Channel::SetInitTimestamp()");
4832 if (_sending)
4833 {
4834 _engineStatisticsPtr->SetLastError(
4835 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4836 return -1;
4837 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004838 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004839 {
4840 _engineStatisticsPtr->SetLastError(
4841 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4842 "SetInitTimestamp() failed to set timestamp");
4843 return -1;
4844 }
4845 return 0;
4846}
4847
4848int
4849Channel::SetInitSequenceNumber(short sequenceNumber)
4850{
4851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4852 "Channel::SetInitSequenceNumber()");
4853 if (_sending)
4854 {
4855 _engineStatisticsPtr->SetLastError(
4856 VE_SENDING, kTraceError,
4857 "SetInitSequenceNumber() already sending");
4858 return -1;
4859 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004860 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004861 {
4862 _engineStatisticsPtr->SetLastError(
4863 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4864 "SetInitSequenceNumber() failed to set sequence number");
4865 return -1;
4866 }
4867 return 0;
4868}
4869
4870int
4871Channel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
4872{
4873 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4874 "Channel::GetRtpRtcp()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004875 rtpRtcpModule = _rtpRtcpModule.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004876 return 0;
4877}
4878
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004879// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4880// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004881int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004882Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004883{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004884 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004885 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004886
4887 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004888 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004889
4890 if (_inputFilePlayerPtr == NULL)
4891 {
4892 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4893 VoEId(_instanceId, _channelId),
4894 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4895 " doesnt exist");
4896 return -1;
4897 }
4898
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004899 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004900 fileSamples,
4901 mixingFrequency) == -1)
4902 {
4903 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4904 VoEId(_instanceId, _channelId),
4905 "Channel::MixOrReplaceAudioWithFile() file mixing "
4906 "failed");
4907 return -1;
4908 }
4909 if (fileSamples == 0)
4910 {
4911 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4912 VoEId(_instanceId, _channelId),
4913 "Channel::MixOrReplaceAudioWithFile() file is ended");
4914 return 0;
4915 }
4916 }
4917
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004918 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004919
4920 if (_mixFileWithMicrophone)
4921 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004922 // Currently file stream is always mono.
4923 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004924 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004925 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004926 fileBuffer.get(),
4927 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004928 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004929 }
4930 else
4931 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004932 // Replace ACM audio with file.
4933 // Currently file stream is always mono.
4934 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004935 _audioFrame.UpdateFrame(_channelId,
4936 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004937 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004938 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004939 mixingFrequency,
4940 AudioFrame::kNormalSpeech,
4941 AudioFrame::kVadUnknown,
4942 1);
4943
4944 }
4945 return 0;
4946}
4947
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004948int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004949Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004950 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004951{
4952 assert(mixingFrequency <= 32000);
4953
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004954 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004955 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004956
4957 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004958 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004959
4960 if (_outputFilePlayerPtr == NULL)
4961 {
4962 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4963 VoEId(_instanceId, _channelId),
4964 "Channel::MixAudioWithFile() file mixing failed");
4965 return -1;
4966 }
4967
4968 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004969 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004970 fileSamples,
4971 mixingFrequency) == -1)
4972 {
4973 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4974 VoEId(_instanceId, _channelId),
4975 "Channel::MixAudioWithFile() file mixing failed");
4976 return -1;
4977 }
4978 }
4979
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004980 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004981 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004982 // Currently file stream is always mono.
4983 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004984 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004985 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004986 fileBuffer.get(),
4987 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004988 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004989 }
4990 else
4991 {
4992 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004993 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004994 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004995 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004996 return -1;
4997 }
4998
4999 return 0;
5000}
5001
5002int
5003Channel::InsertInbandDtmfTone()
5004{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005005 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00005006 if (_inbandDtmfQueue.PendingDtmf() &&
5007 !_inbandDtmfGenerator.IsAddingTone() &&
5008 _inbandDtmfGenerator.DelaySinceLastTone() >
5009 kMinTelephoneEventSeparationMs)
5010 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005011 int8_t eventCode(0);
5012 uint16_t lengthMs(0);
5013 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005014
5015 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
5016 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
5017 if (_playInbandDtmfEvent)
5018 {
5019 // Add tone to output mixer using a reduced length to minimize
5020 // risk of echo.
5021 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
5022 attenuationDb);
5023 }
5024 }
5025
5026 if (_inbandDtmfGenerator.IsAddingTone())
5027 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005028 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005029 _inbandDtmfGenerator.GetSampleRate(frequency);
5030
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005031 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005032 {
5033 // Update sample rate of Dtmf tone since the mixing frequency
5034 // has changed.
5035 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005036 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005037 // Reset the tone to be added taking the new sample rate into
5038 // account.
5039 _inbandDtmfGenerator.ResetTone();
5040 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005041
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005042 int16_t toneBuffer[320];
5043 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005044 // Get 10ms tone segment and set time since last tone to zero
5045 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5046 {
5047 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5048 VoEId(_instanceId, _channelId),
5049 "Channel::EncodeAndSend() inserting Dtmf failed");
5050 return -1;
5051 }
5052
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005053 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005054 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005055 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005056 sample++)
5057 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005058 for (int channel = 0;
5059 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005060 channel++)
5061 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005062 const int index = sample * _audioFrame.num_channels_ + channel;
5063 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005064 }
5065 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005066
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005067 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005068 } else
5069 {
5070 // Add 10ms to "delay-since-last-tone" counter
5071 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5072 }
5073 return 0;
5074}
5075
niklase@google.com470e71d2011-07-07 08:21:25 +00005076void
5077Channel::ResetDeadOrAliveCounters()
5078{
5079 _countDeadDetections = 0;
5080 _countAliveDetections = 0;
5081}
5082
5083void
5084Channel::UpdateDeadOrAliveCounters(bool alive)
5085{
5086 if (alive)
5087 _countAliveDetections++;
5088 else
5089 _countDeadDetections++;
5090}
5091
5092int
5093Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5094{
5095 bool enabled;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005096 uint8_t timeSec;
niklase@google.com470e71d2011-07-07 08:21:25 +00005097
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005098 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00005099 if (!enabled)
5100 return (-1);
5101
5102 countDead = static_cast<int> (_countDeadDetections);
5103 countAlive = static_cast<int> (_countAliveDetections);
5104 return 0;
5105}
5106
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005107int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005108Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5109{
5110 if (_transportPtr == NULL)
5111 {
5112 return -1;
5113 }
5114 if (!RTCP)
5115 {
5116 return _transportPtr->SendPacket(_channelId, data, len);
5117 }
5118 else
5119 {
5120 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5121 }
5122}
5123
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005124// Called for incoming RTP packets after successful RTP header parsing.
5125void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5126 uint16_t sequence_number) {
5127 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5128 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5129 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005130
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005131 // Get frequency of last received payload
5132 int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005133
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005134 CodecInst current_receive_codec;
5135 if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
5136 return;
5137 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005138
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005139 // Update the least required delay.
5140 least_required_delay_ms_ = _audioCodingModule.LeastRequiredDelayMs();
5141
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005142 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5143 // Even though the actual sampling rate for G.722 audio is
5144 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5145 // 8,000 Hz because that value was erroneously assigned in
5146 // RFC 1890 and must remain unchanged for backward compatibility.
5147 rtp_receive_frequency = 8000;
5148 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5149 // We are resampling Opus internally to 32,000 Hz until all our
5150 // DSP routines can operate at 48,000 Hz, but the RTP clock
5151 // rate for the Opus payload format is standardized to 48,000 Hz,
5152 // because that is the maximum supported decoding sampling rate.
5153 rtp_receive_frequency = 48000;
5154 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005155
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005156 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5157 // packet.
5158 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5159 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005160
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005161 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5162 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005163
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005164 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005165
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005166 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5167 timestamp_diff_ms = 0;
5168 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005169
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005170 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005171
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005172 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5173 _recPacketDelayMs = packet_delay_ms;
5174 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005175
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005176 if (_average_jitter_buffer_delay_us == 0) {
5177 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5178 return;
5179 }
5180
5181 // Filter average delay value using exponential filter (alpha is
5182 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5183 // risk of rounding error) and compensate for it in GetDelayEstimate()
5184 // later.
5185 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5186 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005187}
5188
5189void
5190Channel::RegisterReceiveCodecsToRTPModule()
5191{
5192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5193 "Channel::RegisterReceiveCodecsToRTPModule()");
5194
5195
5196 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005197 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005198
5199 for (int idx = 0; idx < nSupportedCodecs; idx++)
5200 {
5201 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005202 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005203 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005204 {
5205 WEBRTC_TRACE(
5206 kTraceWarning,
5207 kTraceVoice,
5208 VoEId(_instanceId, _channelId),
5209 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5210 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5211 codec.plname, codec.pltype, codec.plfreq,
5212 codec.channels, codec.rate);
5213 }
5214 else
5215 {
5216 WEBRTC_TRACE(
5217 kTraceInfo,
5218 kTraceVoice,
5219 VoEId(_instanceId, _channelId),
5220 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005221 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005222 "receiver",
5223 codec.plname, codec.pltype, codec.plfreq,
5224 codec.channels, codec.rate);
5225 }
5226 }
5227}
5228
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005229int Channel::ApmProcessRx(AudioFrame& frame) {
5230 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5231 // Register the (possibly new) frame parameters.
5232 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005233 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005234 }
5235 if (audioproc->set_num_channels(frame.num_channels_,
5236 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005237 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005238 }
5239 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005240 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005241 }
5242 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005243}
5244
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005245int Channel::SetSecondarySendCodec(const CodecInst& codec,
5246 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005247 // Sanity check for payload type.
5248 if (red_payload_type < 0 || red_payload_type > 127) {
5249 _engineStatisticsPtr->SetLastError(
5250 VE_PLTYPE_ERROR, kTraceError,
5251 "SetRedPayloadType() invalid RED payload type");
5252 return -1;
5253 }
5254
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005255 if (SetRedPayloadType(red_payload_type) < 0) {
5256 _engineStatisticsPtr->SetLastError(
5257 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5258 "SetSecondarySendCodec() Failed to register RED ACM");
5259 return -1;
5260 }
5261 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5262 _engineStatisticsPtr->SetLastError(
5263 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5264 "SetSecondarySendCodec() Failed to register secondary send codec in "
5265 "ACM");
5266 return -1;
5267 }
5268
5269 return 0;
5270}
5271
5272void Channel::RemoveSecondarySendCodec() {
5273 _audioCodingModule.UnregisterSecondarySendCodec();
5274}
5275
5276int Channel::GetSecondarySendCodec(CodecInst* codec) {
5277 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5278 _engineStatisticsPtr->SetLastError(
5279 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5280 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5281 return -1;
5282 }
5283 return 0;
5284}
5285
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005286// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005287int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005288 CodecInst codec;
5289 bool found_red = false;
5290
5291 // Get default RED settings from the ACM database
5292 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5293 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005294 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005295 if (!STR_CASE_CMP(codec.plname, "RED")) {
5296 found_red = true;
5297 break;
5298 }
5299 }
5300
5301 if (!found_red) {
5302 _engineStatisticsPtr->SetLastError(
5303 VE_CODEC_ERROR, kTraceError,
5304 "SetRedPayloadType() RED is not supported");
5305 return -1;
5306 }
5307
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005308 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005309 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5310 _engineStatisticsPtr->SetLastError(
5311 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5312 "SetRedPayloadType() RED registration in ACM module failed");
5313 return -1;
5314 }
5315
5316 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5317 _engineStatisticsPtr->SetLastError(
5318 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5319 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5320 return -1;
5321 }
5322 return 0;
5323}
5324
niklase@google.com470e71d2011-07-07 08:21:25 +00005325} // namespace voe
niklase@google.com470e71d2011-07-07 08:21:25 +00005326} // namespace webrtc