blob: 310e3ed588f7d055ad030cdb74563c8e1f3204f1 [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()) {
pwestin@webrtc.org8d80fa82013-06-06 21:33:06 +0000640 // Can't use nack_list.data() since it's not supported by all
641 // compilers.
642 ResendPackets(&(nack_list[0]), nack_list.size());
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000643 }
644 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 return 0;
646}
647
pbos@webrtc.org92135212013-05-14 08:31:39 +0000648int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000649{
650 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
651 "Channel::GetAudioFrame(id=%d)", id);
652
653 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000654 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000655 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 {
657 WEBRTC_TRACE(kTraceError, kTraceVoice,
658 VoEId(_instanceId,_channelId),
659 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000660 // In all likelihood, the audio in this frame is garbage. We return an
661 // error so that the audio mixer module doesn't add it to the mix. As
662 // a result, it won't be played out and the actions skipped here are
663 // irrelevant.
664 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000665 }
666
667 if (_RxVadDetection)
668 {
669 UpdateRxVadDetection(audioFrame);
670 }
671
672 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000673 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000674 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000675 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000676
677 // Perform far-end AudioProcessing module processing on the received signal
678 if (_rxApmIsEnabled)
679 {
680 ApmProcessRx(audioFrame);
681 }
682
683 // Output volume scaling
684 if (_outputGain < 0.99f || _outputGain > 1.01f)
685 {
686 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
687 }
688
689 // Scale left and/or right channel(s) if stereo and master balance is
690 // active
691
692 if (_panLeft != 1.0f || _panRight != 1.0f)
693 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000694 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 {
696 // Emulate stereo mode since panning is active.
697 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000698 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 }
700 // For true stereo mode (when we are receiving a stereo signal), no
701 // action is needed.
702
703 // Do the panning operation (the audio frame contains stereo at this
704 // stage)
705 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
706 }
707
708 // Mix decoded PCM output with file if file mixing is enabled
709 if (_outputFilePlaying)
710 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000711 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 }
713
714 // Place channel in on-hold state (~muted) if on-hold is activated
715 if (_outputIsOnHold)
716 {
717 AudioFrameOperations::Mute(audioFrame);
718 }
719
720 // External media
721 if (_outputExternalMedia)
722 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000723 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000724 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 if (_outputExternalMediaCallbackPtr)
726 {
727 _outputExternalMediaCallbackPtr->Process(
728 _channelId,
729 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000730 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000731 audioFrame.samples_per_channel_,
732 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 isStereo);
734 }
735 }
736
737 // Record playout if enabled
738 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000739 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000740
741 if (_outputFileRecording && _outputFileRecorderPtr)
742 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000743 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 }
745 }
746
747 // Measure audio level (0-9)
748 _outputAudioLevel.ComputeLevel(audioFrame);
749
750 return 0;
751}
752
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000753int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000754Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000755{
756 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
757 "Channel::NeededFrequency(id=%d)", id);
758
759 int highestNeeded = 0;
760
761 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000762 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000763
764 // Return the bigger of playout and receive frequency in the ACM.
765 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
766 {
767 highestNeeded = _audioCodingModule.PlayoutFrequency();
768 }
769 else
770 {
771 highestNeeded = receiveFrequency;
772 }
773
774 // Special case, if we're playing a file on the playout side
775 // we take that frequency into consideration as well
776 // This is not needed on sending side, since the codec will
777 // limit the spectrum anyway.
778 if (_outputFilePlaying)
779 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000780 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000781 if (_outputFilePlayerPtr && _outputFilePlaying)
782 {
783 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
784 {
785 highestNeeded=_outputFilePlayerPtr->Frequency();
786 }
787 }
788 }
789
790 return(highestNeeded);
791}
792
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000793int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000794Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000795 int32_t channelId,
796 uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000797{
798 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
799 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
800 channelId, instanceId);
801
802 channel = new Channel(channelId, instanceId);
803 if (channel == NULL)
804 {
805 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
806 VoEId(instanceId,channelId),
807 "Channel::CreateChannel() unable to allocate memory for"
808 " channel");
809 return -1;
810 }
811 return 0;
812}
813
814void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000815Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000816{
817 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
818 "Channel::PlayNotification(id=%d, durationMs=%d)",
819 id, durationMs);
820
821 // Not implement yet
822}
823
824void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000825Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000826{
827 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
828 "Channel::RecordNotification(id=%d, durationMs=%d)",
829 id, durationMs);
830
831 // Not implement yet
832}
833
834void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000835Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000836{
837 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
838 "Channel::PlayFileEnded(id=%d)", id);
839
840 if (id == _inputFilePlayerId)
841 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000842 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000843
844 _inputFilePlaying = false;
845 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
846 VoEId(_instanceId,_channelId),
847 "Channel::PlayFileEnded() => input file player module is"
848 " shutdown");
849 }
850 else if (id == _outputFilePlayerId)
851 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000852 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000853
854 _outputFilePlaying = false;
855 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
856 VoEId(_instanceId,_channelId),
857 "Channel::PlayFileEnded() => output file player module is"
858 " shutdown");
859 }
860}
861
862void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000863Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000864{
865 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
866 "Channel::RecordFileEnded(id=%d)", id);
867
868 assert(id == _outputFileRecorderId);
869
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000870 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000871
872 _outputFileRecording = false;
873 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
874 VoEId(_instanceId,_channelId),
875 "Channel::RecordFileEnded() => output file recorder module is"
876 " shutdown");
877}
878
pbos@webrtc.org92135212013-05-14 08:31:39 +0000879Channel::Channel(int32_t channelId,
880 uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
882 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000884 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000885 rtp_header_parser_(RtpHeaderParser::Create()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000887 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 _rtpDumpIn(*RtpDump::CreateRtpDump()),
889 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000890 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000891 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 _inputFilePlayerPtr(NULL),
893 _outputFilePlayerPtr(NULL),
894 _outputFileRecorderPtr(NULL),
895 // Avoid conflict with other channels by adding 1024 - 1026,
896 // won't use as much as 1024 channels.
897 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
898 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
899 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
900 _inputFilePlaying(false),
901 _outputFilePlaying(false),
902 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000903 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
904 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000906 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 _inputExternalMediaCallbackPtr(NULL),
908 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000909 _encryptionRTPBufferPtr(NULL),
910 _decryptionRTPBufferPtr(NULL),
911 _encryptionRTCPBufferPtr(NULL),
912 _decryptionRTCPBufferPtr(NULL),
913 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
914 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000915 playout_timestamp_rtp_(0),
916 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000917 _numberOfDiscardedPackets(0),
918 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000919 _outputMixerPtr(NULL),
920 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000921 _moduleProcessThreadPtr(NULL),
922 _audioDeviceModulePtr(NULL),
923 _voiceEngineObserverPtr(NULL),
924 _callbackCritSectPtr(NULL),
925 _transportPtr(NULL),
926 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000927 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000928 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000929 _rxVadObserverPtr(NULL),
930 _oldVadDecision(-1),
931 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 _rtpObserverPtr(NULL),
933 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000934 _outputIsOnHold(false),
935 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000936 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000937 _inputIsOnHold(false),
938 _playing(false),
939 _sending(false),
940 _receiving(false),
941 _mixFileWithMicrophone(false),
942 _rtpObserver(false),
943 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 _mute(false),
945 _panLeft(1.0f),
946 _panRight(1.0f),
947 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000948 _encrypting(false),
949 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 _playOutbandDtmfEvent(false),
951 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 _extraPayloadType(0),
953 _insertExtraRTPPacket(false),
954 _extraMarkerBit(false),
955 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000956 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000958 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 _rtpPacketTimedOut(false),
960 _rtpPacketTimeOutIsEnabled(false),
961 _rtpTimeOutSeconds(0),
962 _connectionObserver(false),
963 _connectionObserverPtr(NULL),
964 _countAliveDetections(0),
965 _countDeadDetections(0),
966 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000967 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000968 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000969 _previousTimestamp(0),
970 _recPacketDelayMs(20),
971 _RxVadDetection(false),
972 _rxApmIsEnabled(false),
973 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000974 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000975{
976 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
977 "Channel::Channel() - ctor");
978 _inbandDtmfQueue.ResetDtmf();
979 _inbandDtmfGenerator.Init();
980 _outputAudioLevel.Clear();
981
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000982 RtpRtcp::Configuration configuration;
983 configuration.id = VoEModuleId(instanceId, channelId);
984 configuration.audio = true;
985 configuration.incoming_data = this;
986 configuration.incoming_messages = this;
987 configuration.outgoing_transport = this;
988 configuration.rtcp_feedback = this;
989 configuration.audio_messages = this;
990
991 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
992
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 // Create far end AudioProcessing Module
994 _rxAudioProcessingModulePtr = AudioProcessing::Create(
995 VoEModuleId(instanceId, channelId));
996}
997
998Channel::~Channel()
999{
1000 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1001 "Channel::~Channel() - dtor");
1002
1003 if (_outputExternalMedia)
1004 {
1005 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1006 }
1007 if (_inputExternalMedia)
1008 {
1009 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1010 }
1011 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 StopPlayout();
1013
1014 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001015 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001016 if (_inputFilePlayerPtr)
1017 {
1018 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1019 _inputFilePlayerPtr->StopPlayingFile();
1020 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1021 _inputFilePlayerPtr = NULL;
1022 }
1023 if (_outputFilePlayerPtr)
1024 {
1025 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1026 _outputFilePlayerPtr->StopPlayingFile();
1027 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1028 _outputFilePlayerPtr = NULL;
1029 }
1030 if (_outputFileRecorderPtr)
1031 {
1032 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1033 _outputFileRecorderPtr->StopRecording();
1034 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1035 _outputFileRecorderPtr = NULL;
1036 }
1037 }
1038
1039 // The order to safely shutdown modules in a channel is:
1040 // 1. De-register callbacks in modules
1041 // 2. De-register modules in process thread
1042 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1044 {
1045 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1046 VoEId(_instanceId,_channelId),
1047 "~Channel() failed to de-register transport callback"
1048 " (Audio coding module)");
1049 }
1050 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1051 {
1052 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1053 VoEId(_instanceId,_channelId),
1054 "~Channel() failed to de-register VAD callback"
1055 " (Audio coding module)");
1056 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001058 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 {
1060 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1061 VoEId(_instanceId,_channelId),
1062 "~Channel() failed to deregister RTP/RTCP module");
1063 }
1064
1065 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 if (_rxAudioProcessingModulePtr != NULL)
1068 {
1069 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1070 _rxAudioProcessingModulePtr = NULL;
1071 }
1072
1073 // End of modules shutdown
1074
1075 // Delete other objects
1076 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1077 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1078 delete [] _encryptionRTPBufferPtr;
1079 delete [] _decryptionRTPBufferPtr;
1080 delete [] _encryptionRTCPBufferPtr;
1081 delete [] _decryptionRTCPBufferPtr;
1082 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 delete &_fileCritSect;
1084}
1085
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001086int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001087Channel::Init()
1088{
1089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1090 "Channel::Init()");
1091
1092 // --- Initial sanity
1093
1094 if ((_engineStatisticsPtr == NULL) ||
1095 (_moduleProcessThreadPtr == NULL))
1096 {
1097 WEBRTC_TRACE(kTraceError, kTraceVoice,
1098 VoEId(_instanceId,_channelId),
1099 "Channel::Init() must call SetEngineInformation() first");
1100 return -1;
1101 }
1102
1103 // --- Add modules to process thread (for periodic schedulation)
1104
1105 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001106 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 if (processThreadFail)
1109 {
1110 _engineStatisticsPtr->SetLastError(
1111 VE_CANNOT_INIT_CHANNEL, kTraceError,
1112 "Channel::Init() modules not registered");
1113 return -1;
1114 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001115 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001116
1117 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1118#ifdef WEBRTC_CODEC_AVT
1119 // out-of-band Dtmf tones are played out by default
1120 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1121#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 (_audioCodingModule.InitializeSender() == -1))
1123 {
1124 _engineStatisticsPtr->SetLastError(
1125 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1126 "Channel::Init() unable to initialize the ACM - 1");
1127 return -1;
1128 }
1129
1130 // --- RTP/RTCP module initialization
1131
1132 // Ensure that RTCP is enabled by default for the created channel.
1133 // Note that, the module will keep generating RTCP until it is explicitly
1134 // disabled by the user.
1135 // After StopListen (when no sockets exists), RTCP packets will no longer
1136 // be transmitted since the Transport object will then be invalid.
1137
1138 const bool rtpRtcpFail =
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001139 ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 // RTCP is enabled by default
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001141 (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 if (rtpRtcpFail)
1143 {
1144 _engineStatisticsPtr->SetLastError(
1145 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1146 "Channel::Init() RTP/RTCP module not initialized");
1147 return -1;
1148 }
1149
1150 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001151 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001152 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1153 (_audioCodingModule.RegisterVADCallback(this) == -1);
1154
1155 if (fail)
1156 {
1157 _engineStatisticsPtr->SetLastError(
1158 VE_CANNOT_INIT_CHANNEL, kTraceError,
1159 "Channel::Init() callbacks not registered");
1160 return -1;
1161 }
1162
1163 // --- Register all supported codecs to the receiving side of the
1164 // RTP/RTCP module
1165
1166 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001167 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001168
1169 for (int idx = 0; idx < nSupportedCodecs; idx++)
1170 {
1171 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001172 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001173 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 {
1175 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1176 VoEId(_instanceId,_channelId),
1177 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1178 "to RTP/RTCP receiver",
1179 codec.plname, codec.pltype, codec.plfreq,
1180 codec.channels, codec.rate);
1181 }
1182 else
1183 {
1184 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1185 VoEId(_instanceId,_channelId),
1186 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1187 "the RTP/RTCP receiver",
1188 codec.plname, codec.pltype, codec.plfreq,
1189 codec.channels, codec.rate);
1190 }
1191
1192 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001193 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 {
1195 SetSendCodec(codec);
1196 }
1197
1198 // Register default PT for outband 'telephone-event'
1199 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1200 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001201 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001202 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1203 {
1204 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1205 VoEId(_instanceId,_channelId),
1206 "Channel::Init() failed to register outband "
1207 "'telephone-event' (%d/%d) correctly",
1208 codec.pltype, codec.plfreq);
1209 }
1210 }
1211
1212 if (!STR_CASE_CMP(codec.plname, "CN"))
1213 {
1214 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1215 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001216 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 {
1218 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1219 VoEId(_instanceId,_channelId),
1220 "Channel::Init() failed to register CN (%d/%d) "
1221 "correctly - 1",
1222 codec.pltype, codec.plfreq);
1223 }
1224 }
1225#ifdef WEBRTC_CODEC_RED
1226 // Register RED to the receiving side of the ACM.
1227 // We will not receive an OnInitializeDecoder() callback for RED.
1228 if (!STR_CASE_CMP(codec.plname, "RED"))
1229 {
1230 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1231 {
1232 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1233 VoEId(_instanceId,_channelId),
1234 "Channel::Init() failed to register RED (%d/%d) "
1235 "correctly",
1236 codec.pltype, codec.plfreq);
1237 }
1238 }
1239#endif
1240 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001241
niklase@google.com470e71d2011-07-07 08:21:25 +00001242 // Initialize the far end AP module
1243 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1244 // changed at the first receiving audio.
1245 if (_rxAudioProcessingModulePtr == NULL)
1246 {
1247 _engineStatisticsPtr->SetLastError(
1248 VE_NO_MEMORY, kTraceCritical,
1249 "Channel::Init() failed to create the far-end AudioProcessing"
1250 " module");
1251 return -1;
1252 }
1253
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1255 {
1256 _engineStatisticsPtr->SetLastError(
1257 VE_APM_ERROR, kTraceWarning,
1258 "Channel::Init() failed to set the sample rate to 8K for"
1259 " far-end AP module");
1260 }
1261
1262 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1263 {
1264 _engineStatisticsPtr->SetLastError(
1265 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001266 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001267 }
1268
1269 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1270 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1271 {
1272 _engineStatisticsPtr->SetLastError(
1273 VE_APM_ERROR, kTraceWarning,
1274 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001275 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 }
1277
1278 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1279 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1280 {
1281 _engineStatisticsPtr->SetLastError(
1282 VE_APM_ERROR, kTraceWarning,
1283 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001284 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001285 }
1286 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1287 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1288 {
1289 _engineStatisticsPtr->SetLastError(
1290 VE_APM_ERROR, kTraceWarning,
1291 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001292 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 }
1294
1295 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1296 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1297 {
1298 _engineStatisticsPtr->SetLastError(
1299 VE_APM_ERROR, kTraceWarning,
1300 "Init() failed to set AGC mode for far-end AP module");
1301 }
1302 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1303 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1304 {
1305 _engineStatisticsPtr->SetLastError(
1306 VE_APM_ERROR, kTraceWarning,
1307 "Init() failed to set AGC state for far-end AP module");
1308 }
1309
1310 return 0;
1311}
1312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001313int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001314Channel::SetEngineInformation(Statistics& engineStatistics,
1315 OutputMixer& outputMixer,
1316 voe::TransmitMixer& transmitMixer,
1317 ProcessThread& moduleProcessThread,
1318 AudioDeviceModule& audioDeviceModule,
1319 VoiceEngineObserver* voiceEngineObserver,
1320 CriticalSectionWrapper* callbackCritSect)
1321{
1322 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1323 "Channel::SetEngineInformation()");
1324 _engineStatisticsPtr = &engineStatistics;
1325 _outputMixerPtr = &outputMixer;
1326 _transmitMixerPtr = &transmitMixer,
1327 _moduleProcessThreadPtr = &moduleProcessThread;
1328 _audioDeviceModulePtr = &audioDeviceModule;
1329 _voiceEngineObserverPtr = voiceEngineObserver;
1330 _callbackCritSectPtr = callbackCritSect;
1331 return 0;
1332}
1333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001334int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001335Channel::UpdateLocalTimeStamp()
1336{
1337
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001338 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001339 return 0;
1340}
1341
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001342int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001343Channel::StartPlayout()
1344{
1345 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1346 "Channel::StartPlayout()");
1347 if (_playing)
1348 {
1349 return 0;
1350 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001351
1352 if (!_externalMixing) {
1353 // Add participant as candidates for mixing.
1354 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1355 {
1356 _engineStatisticsPtr->SetLastError(
1357 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1358 "StartPlayout() failed to add participant to mixer");
1359 return -1;
1360 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001361 }
1362
1363 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001364
1365 if (RegisterFilePlayingToMixer() != 0)
1366 return -1;
1367
niklase@google.com470e71d2011-07-07 08:21:25 +00001368 return 0;
1369}
1370
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001371int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001372Channel::StopPlayout()
1373{
1374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1375 "Channel::StopPlayout()");
1376 if (!_playing)
1377 {
1378 return 0;
1379 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001380
1381 if (!_externalMixing) {
1382 // Remove participant as candidates for mixing
1383 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1384 {
1385 _engineStatisticsPtr->SetLastError(
1386 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1387 "StopPlayout() failed to remove participant from mixer");
1388 return -1;
1389 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 }
1391
1392 _playing = false;
1393 _outputAudioLevel.Clear();
1394
1395 return 0;
1396}
1397
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001398int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001399Channel::StartSend()
1400{
1401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1402 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001404 // A lock is needed because |_sending| can be accessed or modified by
1405 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001406 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001407
1408 if (_sending)
1409 {
1410 return 0;
1411 }
1412 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001413 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001414
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001415 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 {
1417 _engineStatisticsPtr->SetLastError(
1418 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1419 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001420 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001421 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001422 return -1;
1423 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001424
niklase@google.com470e71d2011-07-07 08:21:25 +00001425 return 0;
1426}
1427
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001428int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001429Channel::StopSend()
1430{
1431 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1432 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001434 // A lock is needed because |_sending| can be accessed or modified by
1435 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001436 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001437
1438 if (!_sending)
1439 {
1440 return 0;
1441 }
1442 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001443 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001444
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 // Reset sending SSRC and sequence number and triggers direct transmission
1446 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001447 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1448 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
1450 _engineStatisticsPtr->SetLastError(
1451 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1452 "StartSend() RTP/RTCP failed to stop sending");
1453 }
1454
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 return 0;
1456}
1457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001458int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001459Channel::StartReceiving()
1460{
1461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1462 "Channel::StartReceiving()");
1463 if (_receiving)
1464 {
1465 return 0;
1466 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001467 _receiving = true;
1468 _numberOfDiscardedPackets = 0;
1469 return 0;
1470}
1471
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001472int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001473Channel::StopReceiving()
1474{
1475 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1476 "Channel::StopReceiving()");
1477 if (!_receiving)
1478 {
1479 return 0;
1480 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001481
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001482 // Recover DTMF detection status.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001483 int32_t ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001484 if (ret != 0) {
1485 _engineStatisticsPtr->SetLastError(
1486 VE_INVALID_OPERATION, kTraceWarning,
1487 "StopReceiving() failed to restore telephone-event status.");
1488 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001489 RegisterReceiveCodecsToRTPModule();
1490 _receiving = false;
1491 return 0;
1492}
1493
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001494int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001495Channel::SetNetEQPlayoutMode(NetEqModes mode)
1496{
1497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1498 "Channel::SetNetEQPlayoutMode()");
1499 AudioPlayoutMode playoutMode(voice);
1500 switch (mode)
1501 {
1502 case kNetEqDefault:
1503 playoutMode = voice;
1504 break;
1505 case kNetEqStreaming:
1506 playoutMode = streaming;
1507 break;
1508 case kNetEqFax:
1509 playoutMode = fax;
1510 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001511 case kNetEqOff:
1512 playoutMode = off;
1513 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001514 }
1515 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1516 {
1517 _engineStatisticsPtr->SetLastError(
1518 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1519 "SetNetEQPlayoutMode() failed to set playout mode");
1520 return -1;
1521 }
1522 return 0;
1523}
1524
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001525int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001526Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1527{
1528 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1529 switch (playoutMode)
1530 {
1531 case voice:
1532 mode = kNetEqDefault;
1533 break;
1534 case streaming:
1535 mode = kNetEqStreaming;
1536 break;
1537 case fax:
1538 mode = kNetEqFax;
1539 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001540 case off:
1541 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001542 }
1543 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1544 VoEId(_instanceId,_channelId),
1545 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1546 return 0;
1547}
1548
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001549int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001550Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1551{
1552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1553 "Channel::SetOnHoldStatus()");
1554 if (mode == kHoldSendAndPlay)
1555 {
1556 _outputIsOnHold = enable;
1557 _inputIsOnHold = enable;
1558 }
1559 else if (mode == kHoldPlayOnly)
1560 {
1561 _outputIsOnHold = enable;
1562 }
1563 if (mode == kHoldSendOnly)
1564 {
1565 _inputIsOnHold = enable;
1566 }
1567 return 0;
1568}
1569
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001571Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1572{
1573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574 "Channel::GetOnHoldStatus()");
1575 enabled = (_outputIsOnHold || _inputIsOnHold);
1576 if (_outputIsOnHold && _inputIsOnHold)
1577 {
1578 mode = kHoldSendAndPlay;
1579 }
1580 else if (_outputIsOnHold && !_inputIsOnHold)
1581 {
1582 mode = kHoldPlayOnly;
1583 }
1584 else if (!_outputIsOnHold && _inputIsOnHold)
1585 {
1586 mode = kHoldSendOnly;
1587 }
1588 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1589 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1590 enabled, mode);
1591 return 0;
1592}
1593
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001594int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001595Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1596{
1597 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1598 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001599 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001600
1601 if (_voiceEngineObserverPtr)
1602 {
1603 _engineStatisticsPtr->SetLastError(
1604 VE_INVALID_OPERATION, kTraceError,
1605 "RegisterVoiceEngineObserver() observer already enabled");
1606 return -1;
1607 }
1608 _voiceEngineObserverPtr = &observer;
1609 return 0;
1610}
1611
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001612int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001613Channel::DeRegisterVoiceEngineObserver()
1614{
1615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1616 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001617 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001618
1619 if (!_voiceEngineObserverPtr)
1620 {
1621 _engineStatisticsPtr->SetLastError(
1622 VE_INVALID_OPERATION, kTraceWarning,
1623 "DeRegisterVoiceEngineObserver() observer already disabled");
1624 return 0;
1625 }
1626 _voiceEngineObserverPtr = NULL;
1627 return 0;
1628}
1629
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001630int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001631Channel::GetSendCodec(CodecInst& codec)
1632{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001633 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001634}
1635
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001636int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001637Channel::GetRecCodec(CodecInst& codec)
1638{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001639 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001640}
1641
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001642int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001643Channel::SetSendCodec(const CodecInst& codec)
1644{
1645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1646 "Channel::SetSendCodec()");
1647
1648 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1649 {
1650 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1651 "SetSendCodec() failed to register codec to ACM");
1652 return -1;
1653 }
1654
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001655 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001656 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001657 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1658 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001659 {
1660 WEBRTC_TRACE(
1661 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1662 "SetSendCodec() failed to register codec to"
1663 " RTP/RTCP module");
1664 return -1;
1665 }
1666 }
1667
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001668 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001669 {
1670 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1671 "SetSendCodec() failed to set audio packet size");
1672 return -1;
1673 }
1674
1675 return 0;
1676}
1677
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001678int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001679Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1680{
1681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1682 "Channel::SetVADStatus(mode=%d)", mode);
1683 // To disable VAD, DTX must be disabled too
1684 disableDTX = ((enableVAD == false) ? true : disableDTX);
1685 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1686 {
1687 _engineStatisticsPtr->SetLastError(
1688 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1689 "SetVADStatus() failed to set VAD");
1690 return -1;
1691 }
1692 return 0;
1693}
1694
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001695int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001696Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1697{
1698 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1699 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001700 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001701 {
1702 _engineStatisticsPtr->SetLastError(
1703 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1704 "GetVADStatus() failed to get VAD status");
1705 return -1;
1706 }
1707 disabledDTX = !disabledDTX;
1708 return 0;
1709}
1710
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001711int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001712Channel::SetRecPayloadType(const CodecInst& codec)
1713{
1714 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1715 "Channel::SetRecPayloadType()");
1716
1717 if (_playing)
1718 {
1719 _engineStatisticsPtr->SetLastError(
1720 VE_ALREADY_PLAYING, kTraceError,
1721 "SetRecPayloadType() unable to set PT while playing");
1722 return -1;
1723 }
1724 if (_receiving)
1725 {
1726 _engineStatisticsPtr->SetLastError(
1727 VE_ALREADY_LISTENING, kTraceError,
1728 "SetRecPayloadType() unable to set PT while listening");
1729 return -1;
1730 }
1731
1732 if (codec.pltype == -1)
1733 {
1734 // De-register the selected codec (RTP/RTCP module and ACM)
1735
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001736 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001737 CodecInst rxCodec = codec;
1738
1739 // Get payload type for the given codec
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001740 _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001741 rxCodec.pltype = pltype;
1742
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001743 if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001744 {
1745 _engineStatisticsPtr->SetLastError(
1746 VE_RTP_RTCP_MODULE_ERROR,
1747 kTraceError,
1748 "SetRecPayloadType() RTP/RTCP-module deregistration "
1749 "failed");
1750 return -1;
1751 }
1752 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1753 {
1754 _engineStatisticsPtr->SetLastError(
1755 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1756 "SetRecPayloadType() ACM deregistration failed - 1");
1757 return -1;
1758 }
1759 return 0;
1760 }
1761
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001762 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 {
1764 // First attempt to register failed => de-register and try again
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001765 _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
1766 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001767 {
1768 _engineStatisticsPtr->SetLastError(
1769 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1770 "SetRecPayloadType() RTP/RTCP-module registration failed");
1771 return -1;
1772 }
1773 }
1774 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1775 {
1776 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1777 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1778 {
1779 _engineStatisticsPtr->SetLastError(
1780 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1781 "SetRecPayloadType() ACM registration failed - 1");
1782 return -1;
1783 }
1784 }
1785 return 0;
1786}
1787
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001788int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001789Channel::GetRecPayloadType(CodecInst& codec)
1790{
1791 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1792 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001793 int8_t payloadType(-1);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001794 if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001795 {
1796 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001797 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001798 "GetRecPayloadType() failed to retrieve RX payload type");
1799 return -1;
1800 }
1801 codec.pltype = payloadType;
1802 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1803 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1804 return 0;
1805}
1806
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001807int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001808Channel::SetAMREncFormat(AmrMode mode)
1809{
1810 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1811 "Channel::SetAMREncFormat()");
1812
1813 // ACM doesn't support AMR
1814 return -1;
1815}
1816
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001817int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001818Channel::SetAMRDecFormat(AmrMode mode)
1819{
1820 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1821 "Channel::SetAMRDecFormat()");
1822
1823 // ACM doesn't support AMR
1824 return -1;
1825}
1826
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001827int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001828Channel::SetAMRWbEncFormat(AmrMode mode)
1829{
1830 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1831 "Channel::SetAMRWbEncFormat()");
1832
1833 // ACM doesn't support AMR
1834 return -1;
1835
1836}
1837
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001838int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001839Channel::SetAMRWbDecFormat(AmrMode mode)
1840{
1841 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1842 "Channel::SetAMRWbDecFormat()");
1843
1844 // ACM doesn't support AMR
1845 return -1;
1846}
1847
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001849Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1850{
1851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1852 "Channel::SetSendCNPayloadType()");
1853
1854 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001855 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001856 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001857 if (frequency == kFreq32000Hz)
1858 samplingFreqHz = 32000;
1859 else if (frequency == kFreq16000Hz)
1860 samplingFreqHz = 16000;
1861
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001862 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001863 {
1864 _engineStatisticsPtr->SetLastError(
1865 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1866 "SetSendCNPayloadType() failed to retrieve default CN codec "
1867 "settings");
1868 return -1;
1869 }
1870
1871 // Modify the payload type (must be set to dynamic range)
1872 codec.pltype = type;
1873
1874 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1875 {
1876 _engineStatisticsPtr->SetLastError(
1877 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1878 "SetSendCNPayloadType() failed to register CN to ACM");
1879 return -1;
1880 }
1881
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001882 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001883 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001884 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1885 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001886 {
1887 _engineStatisticsPtr->SetLastError(
1888 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1889 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1890 "module");
1891 return -1;
1892 }
1893 }
1894 return 0;
1895}
1896
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001897int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001898Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1899{
1900 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1901 "Channel::SetISACInitTargetRate()");
1902
1903 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001904 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_CODEC_ERROR, kTraceError,
1908 "SetISACInitTargetRate() failed to retrieve send codec");
1909 return -1;
1910 }
1911 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1912 {
1913 // This API is only valid if iSAC is setup to run in channel-adaptive
1914 // mode.
1915 // We do not validate the adaptive mode here. It is done later in the
1916 // ConfigISACBandwidthEstimator() API.
1917 _engineStatisticsPtr->SetLastError(
1918 VE_CODEC_ERROR, kTraceError,
1919 "SetISACInitTargetRate() send codec is not iSAC");
1920 return -1;
1921 }
1922
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001923 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001924 if (16000 == sendCodec.plfreq)
1925 {
1926 // Note that 0 is a valid and corresponds to "use default
1927 if ((rateBps != 0 &&
1928 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1929 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1930 {
1931 _engineStatisticsPtr->SetLastError(
1932 VE_INVALID_ARGUMENT, kTraceError,
1933 "SetISACInitTargetRate() invalid target rate - 1");
1934 return -1;
1935 }
1936 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001937 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001938 }
1939 else if (32000 == sendCodec.plfreq)
1940 {
1941 if ((rateBps != 0 &&
1942 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1943 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1944 {
1945 _engineStatisticsPtr->SetLastError(
1946 VE_INVALID_ARGUMENT, kTraceError,
1947 "SetISACInitTargetRate() invalid target rate - 2");
1948 return -1;
1949 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001950 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001951 }
1952
1953 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1954 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1955 {
1956 _engineStatisticsPtr->SetLastError(
1957 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1958 "SetISACInitTargetRate() iSAC BWE config failed");
1959 return -1;
1960 }
1961
1962 return 0;
1963}
1964
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001965int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001966Channel::SetISACMaxRate(int rateBps)
1967{
1968 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1969 "Channel::SetISACMaxRate()");
1970
1971 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001972 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 {
1974 _engineStatisticsPtr->SetLastError(
1975 VE_CODEC_ERROR, kTraceError,
1976 "SetISACMaxRate() failed to retrieve send codec");
1977 return -1;
1978 }
1979 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1980 {
1981 // This API is only valid if iSAC is selected as sending codec.
1982 _engineStatisticsPtr->SetLastError(
1983 VE_CODEC_ERROR, kTraceError,
1984 "SetISACMaxRate() send codec is not iSAC");
1985 return -1;
1986 }
1987 if (16000 == sendCodec.plfreq)
1988 {
1989 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1990 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1991 {
1992 _engineStatisticsPtr->SetLastError(
1993 VE_INVALID_ARGUMENT, kTraceError,
1994 "SetISACMaxRate() invalid max rate - 1");
1995 return -1;
1996 }
1997 }
1998 else if (32000 == sendCodec.plfreq)
1999 {
2000 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2001 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2002 {
2003 _engineStatisticsPtr->SetLastError(
2004 VE_INVALID_ARGUMENT, kTraceError,
2005 "SetISACMaxRate() invalid max rate - 2");
2006 return -1;
2007 }
2008 }
2009 if (_sending)
2010 {
2011 _engineStatisticsPtr->SetLastError(
2012 VE_SENDING, kTraceError,
2013 "SetISACMaxRate() unable to set max rate while sending");
2014 return -1;
2015 }
2016
2017 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2018 // and non-adaptive mode)
2019 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2020 {
2021 _engineStatisticsPtr->SetLastError(
2022 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2023 "SetISACMaxRate() failed to set max rate");
2024 return -1;
2025 }
2026
2027 return 0;
2028}
2029
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002030int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002031Channel::SetISACMaxPayloadSize(int sizeBytes)
2032{
2033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2034 "Channel::SetISACMaxPayloadSize()");
2035 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002036 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002037 {
2038 _engineStatisticsPtr->SetLastError(
2039 VE_CODEC_ERROR, kTraceError,
2040 "SetISACMaxPayloadSize() failed to retrieve send codec");
2041 return -1;
2042 }
2043 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2044 {
2045 _engineStatisticsPtr->SetLastError(
2046 VE_CODEC_ERROR, kTraceError,
2047 "SetISACMaxPayloadSize() send codec is not iSAC");
2048 return -1;
2049 }
2050 if (16000 == sendCodec.plfreq)
2051 {
2052 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2053 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2054 {
2055 _engineStatisticsPtr->SetLastError(
2056 VE_INVALID_ARGUMENT, kTraceError,
2057 "SetISACMaxPayloadSize() invalid max payload - 1");
2058 return -1;
2059 }
2060 }
2061 else if (32000 == sendCodec.plfreq)
2062 {
2063 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2064 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2065 {
2066 _engineStatisticsPtr->SetLastError(
2067 VE_INVALID_ARGUMENT, kTraceError,
2068 "SetISACMaxPayloadSize() invalid max payload - 2");
2069 return -1;
2070 }
2071 }
2072 if (_sending)
2073 {
2074 _engineStatisticsPtr->SetLastError(
2075 VE_SENDING, kTraceError,
2076 "SetISACMaxPayloadSize() unable to set max rate while sending");
2077 return -1;
2078 }
2079
2080 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2081 {
2082 _engineStatisticsPtr->SetLastError(
2083 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2084 "SetISACMaxPayloadSize() failed to set max payload size");
2085 return -1;
2086 }
2087 return 0;
2088}
2089
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002090int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002091{
2092 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2093 "Channel::RegisterExternalTransport()");
2094
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002095 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002096
niklase@google.com470e71d2011-07-07 08:21:25 +00002097 if (_externalTransport)
2098 {
2099 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2100 kTraceError,
2101 "RegisterExternalTransport() external transport already enabled");
2102 return -1;
2103 }
2104 _externalTransport = true;
2105 _transportPtr = &transport;
2106 return 0;
2107}
2108
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002109int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002110Channel::DeRegisterExternalTransport()
2111{
2112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2113 "Channel::DeRegisterExternalTransport()");
2114
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002115 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002116
niklase@google.com470e71d2011-07-07 08:21:25 +00002117 if (!_transportPtr)
2118 {
2119 _engineStatisticsPtr->SetLastError(
2120 VE_INVALID_OPERATION, kTraceWarning,
2121 "DeRegisterExternalTransport() external transport already "
2122 "disabled");
2123 return 0;
2124 }
2125 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002126 _transportPtr = NULL;
2127 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2128 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002129 return 0;
2130}
2131
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002132int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002133 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2134 "Channel::ReceivedRTPPacket()");
2135
2136 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002137 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002138
2139 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002140 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2141 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2143 VoEId(_instanceId,_channelId),
2144 "Channel::SendPacket() RTP dump to input file failed");
2145 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002146 RTPHeader header;
2147 if (!rtp_header_parser_->Parse(reinterpret_cast<const uint8_t*>(data),
2148 static_cast<uint16_t>(length), &header)) {
2149 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo,
2150 VoEId(_instanceId,_channelId),
2151 "IncomingPacket invalid RTP header");
2152 return -1;
2153 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002154 // Deliver RTP packet to RTP/RTCP module for parsing
2155 // The packet will be pushed back to the channel thru the
2156 // OnReceivedPayloadData callback so we don't push it to the ACM here
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002157 if (_rtpRtcpModule->IncomingRtpPacket(reinterpret_cast<const uint8_t*>(data),
2158 static_cast<uint16_t>(length),
2159 header) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002160 _engineStatisticsPtr->SetLastError(
2161 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2162 "Channel::IncomingRTPPacket() RTP packet is invalid");
2163 }
2164 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002165}
2166
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002167int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002168 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2169 "Channel::ReceivedRTCPPacket()");
2170 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002171 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002172
2173 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002174 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2175 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2177 VoEId(_instanceId,_channelId),
2178 "Channel::SendPacket() RTCP dump to input file failed");
2179 }
2180
2181 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002182 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2183 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002184 _engineStatisticsPtr->SetLastError(
2185 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2186 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2187 }
2188 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002189}
2190
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002191int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002192Channel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
2193{
2194 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2195 "Channel::SetPacketTimeoutNotification()");
2196 if (enable)
2197 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002198 const uint32_t RTPtimeoutMS = 1000*timeoutSeconds;
2199 const uint32_t RTCPtimeoutMS = 0;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002200 _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
niklase@google.com470e71d2011-07-07 08:21:25 +00002201 _rtpPacketTimeOutIsEnabled = true;
2202 _rtpTimeOutSeconds = timeoutSeconds;
2203 }
2204 else
2205 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002206 _rtpRtcpModule->SetPacketTimeout(0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002207 _rtpPacketTimeOutIsEnabled = false;
2208 _rtpTimeOutSeconds = 0;
2209 }
2210 return 0;
2211}
2212
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002213int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002214Channel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
2215{
2216 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2217 "Channel::GetPacketTimeoutNotification()");
2218 enabled = _rtpPacketTimeOutIsEnabled;
2219 if (enabled)
2220 {
2221 timeoutSeconds = _rtpTimeOutSeconds;
2222 }
2223 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2224 "GetPacketTimeoutNotification() => enabled=%d,"
2225 " timeoutSeconds=%d",
2226 enabled, timeoutSeconds);
2227 return 0;
2228}
2229
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002230int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002231Channel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
2232{
2233 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2234 "Channel::RegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002235 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002236
2237 if (_connectionObserverPtr)
2238 {
2239 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
2240 "RegisterDeadOrAliveObserver() observer already enabled");
2241 return -1;
2242 }
2243
2244 _connectionObserverPtr = &observer;
2245 _connectionObserver = true;
2246
2247 return 0;
2248}
2249
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002250int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002251Channel::DeRegisterDeadOrAliveObserver()
2252{
2253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2254 "Channel::DeRegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002255 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002256
2257 if (!_connectionObserverPtr)
2258 {
2259 _engineStatisticsPtr->SetLastError(
2260 VE_INVALID_OPERATION, kTraceWarning,
2261 "DeRegisterDeadOrAliveObserver() observer already disabled");
2262 return 0;
2263 }
2264
2265 _connectionObserver = false;
2266 _connectionObserverPtr = NULL;
2267
2268 return 0;
2269}
2270
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002271int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002272Channel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
2273{
2274 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2275 "Channel::SetPeriodicDeadOrAliveStatus()");
2276 if (!_connectionObserverPtr)
2277 {
2278 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
2279 "SetPeriodicDeadOrAliveStatus() connection observer has"
2280 " not been registered");
2281 }
2282 if (enable)
2283 {
2284 ResetDeadOrAliveCounters();
2285 }
2286 bool enabled(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002287 uint8_t currentSampleTimeSec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002288 // Store last state (will be used later if dead-or-alive is disabled).
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002289 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00002290 // Update the dead-or-alive state.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002291 if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002292 enable, (uint8_t)sampleTimeSeconds) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002293 {
2294 _engineStatisticsPtr->SetLastError(
2295 VE_RTP_RTCP_MODULE_ERROR,
2296 kTraceError,
2297 "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
2298 "status");
2299 return -1;
2300 }
2301 if (!enable)
2302 {
2303 // Restore last utilized sample time.
2304 // Without this, the sample time would always be reset to default
2305 // (2 sec), each time dead-or-alived was disabled without sample-time
2306 // parameter.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002307 _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
niklase@google.com470e71d2011-07-07 08:21:25 +00002308 currentSampleTimeSec);
2309 }
2310 return 0;
2311}
2312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002313int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002314Channel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
2315{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002316 _rtpRtcpModule->PeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00002317 enabled,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002318 (uint8_t&)sampleTimeSeconds);
niklase@google.com470e71d2011-07-07 08:21:25 +00002319 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2320 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
2321 " sampleTimeSeconds=%d",
2322 enabled, sampleTimeSeconds);
2323 return 0;
2324}
2325
niklase@google.com470e71d2011-07-07 08:21:25 +00002326int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002327 bool loop,
2328 FileFormats format,
2329 int startPosition,
2330 float volumeScaling,
2331 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002332 const CodecInst* codecInst)
2333{
2334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2335 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2336 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2337 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2338 startPosition, stopPosition);
2339
2340 if (_outputFilePlaying)
2341 {
2342 _engineStatisticsPtr->SetLastError(
2343 VE_ALREADY_PLAYING, kTraceError,
2344 "StartPlayingFileLocally() is already playing");
2345 return -1;
2346 }
2347
niklase@google.com470e71d2011-07-07 08:21:25 +00002348 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002349 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002350
2351 if (_outputFilePlayerPtr)
2352 {
2353 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2354 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2355 _outputFilePlayerPtr = NULL;
2356 }
2357
2358 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2359 _outputFilePlayerId, (const FileFormats)format);
2360
2361 if (_outputFilePlayerPtr == NULL)
2362 {
2363 _engineStatisticsPtr->SetLastError(
2364 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002365 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002366 return -1;
2367 }
2368
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002369 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002370
2371 if (_outputFilePlayerPtr->StartPlayingFile(
2372 fileName,
2373 loop,
2374 startPosition,
2375 volumeScaling,
2376 notificationTime,
2377 stopPosition,
2378 (const CodecInst*)codecInst) != 0)
2379 {
2380 _engineStatisticsPtr->SetLastError(
2381 VE_BAD_FILE, kTraceError,
2382 "StartPlayingFile() failed to start file playout");
2383 _outputFilePlayerPtr->StopPlayingFile();
2384 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2385 _outputFilePlayerPtr = NULL;
2386 return -1;
2387 }
2388 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2389 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002390 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002391
2392 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002393 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002394
2395 return 0;
2396}
2397
2398int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002399 FileFormats format,
2400 int startPosition,
2401 float volumeScaling,
2402 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002403 const CodecInst* codecInst)
2404{
2405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2406 "Channel::StartPlayingFileLocally(format=%d,"
2407 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2408 format, volumeScaling, startPosition, stopPosition);
2409
2410 if(stream == NULL)
2411 {
2412 _engineStatisticsPtr->SetLastError(
2413 VE_BAD_FILE, kTraceError,
2414 "StartPlayingFileLocally() NULL as input stream");
2415 return -1;
2416 }
2417
2418
2419 if (_outputFilePlaying)
2420 {
2421 _engineStatisticsPtr->SetLastError(
2422 VE_ALREADY_PLAYING, kTraceError,
2423 "StartPlayingFileLocally() is already playing");
2424 return -1;
2425 }
2426
niklase@google.com470e71d2011-07-07 08:21:25 +00002427 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002428 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002429
2430 // Destroy the old instance
2431 if (_outputFilePlayerPtr)
2432 {
2433 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2434 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2435 _outputFilePlayerPtr = NULL;
2436 }
2437
2438 // Create the instance
2439 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2440 _outputFilePlayerId,
2441 (const FileFormats)format);
2442
2443 if (_outputFilePlayerPtr == NULL)
2444 {
2445 _engineStatisticsPtr->SetLastError(
2446 VE_INVALID_ARGUMENT, kTraceError,
2447 "StartPlayingFileLocally() filePlayer format isnot correct");
2448 return -1;
2449 }
2450
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002451 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002452
2453 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2454 volumeScaling,
2455 notificationTime,
2456 stopPosition, codecInst) != 0)
2457 {
2458 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2459 "StartPlayingFile() failed to "
2460 "start file playout");
2461 _outputFilePlayerPtr->StopPlayingFile();
2462 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2463 _outputFilePlayerPtr = NULL;
2464 return -1;
2465 }
2466 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2467 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002468 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002469
2470 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002471 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002472
niklase@google.com470e71d2011-07-07 08:21:25 +00002473 return 0;
2474}
2475
2476int Channel::StopPlayingFileLocally()
2477{
2478 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2479 "Channel::StopPlayingFileLocally()");
2480
2481 if (!_outputFilePlaying)
2482 {
2483 _engineStatisticsPtr->SetLastError(
2484 VE_INVALID_OPERATION, kTraceWarning,
2485 "StopPlayingFileLocally() isnot playing");
2486 return 0;
2487 }
2488
niklase@google.com470e71d2011-07-07 08:21:25 +00002489 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002490 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002491
2492 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2493 {
2494 _engineStatisticsPtr->SetLastError(
2495 VE_STOP_RECORDING_FAILED, kTraceError,
2496 "StopPlayingFile() could not stop playing");
2497 return -1;
2498 }
2499 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2500 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2501 _outputFilePlayerPtr = NULL;
2502 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002503 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002504 // _fileCritSect cannot be taken while calling
2505 // SetAnonymousMixibilityStatus. Refer to comments in
2506 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002507 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2508 {
2509 _engineStatisticsPtr->SetLastError(
2510 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002511 "StopPlayingFile() failed to stop participant from playing as"
2512 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002513 return -1;
2514 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002515
2516 return 0;
2517}
2518
2519int Channel::IsPlayingFileLocally() const
2520{
2521 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2522 "Channel::IsPlayingFileLocally()");
2523
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002524 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002525}
2526
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002527int Channel::RegisterFilePlayingToMixer()
2528{
2529 // Return success for not registering for file playing to mixer if:
2530 // 1. playing file before playout is started on that channel.
2531 // 2. starting playout without file playing on that channel.
2532 if (!_playing || !_outputFilePlaying)
2533 {
2534 return 0;
2535 }
2536
2537 // |_fileCritSect| cannot be taken while calling
2538 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2539 // frames can be pulled by the mixer. Since the frames are generated from
2540 // the file, _fileCritSect will be taken. This would result in a deadlock.
2541 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2542 {
2543 CriticalSectionScoped cs(&_fileCritSect);
2544 _outputFilePlaying = false;
2545 _engineStatisticsPtr->SetLastError(
2546 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2547 "StartPlayingFile() failed to add participant as file to mixer");
2548 _outputFilePlayerPtr->StopPlayingFile();
2549 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2550 _outputFilePlayerPtr = NULL;
2551 return -1;
2552 }
2553
2554 return 0;
2555}
2556
pbos@webrtc.org92135212013-05-14 08:31:39 +00002557int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002558{
2559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2560 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2561
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002562 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002563
2564 if (!_outputFilePlaying)
2565 {
2566 _engineStatisticsPtr->SetLastError(
2567 VE_INVALID_OPERATION, kTraceError,
2568 "ScaleLocalFilePlayout() isnot playing");
2569 return -1;
2570 }
2571 if ((_outputFilePlayerPtr == NULL) ||
2572 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2573 {
2574 _engineStatisticsPtr->SetLastError(
2575 VE_BAD_ARGUMENT, kTraceError,
2576 "SetAudioScaling() failed to scale the playout");
2577 return -1;
2578 }
2579
2580 return 0;
2581}
2582
2583int Channel::GetLocalPlayoutPosition(int& positionMs)
2584{
2585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2586 "Channel::GetLocalPlayoutPosition(position=?)");
2587
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002588 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002589
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002590 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002591
2592 if (_outputFilePlayerPtr == NULL)
2593 {
2594 _engineStatisticsPtr->SetLastError(
2595 VE_INVALID_OPERATION, kTraceError,
2596 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2597 return -1;
2598 }
2599
2600 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2601 {
2602 _engineStatisticsPtr->SetLastError(
2603 VE_BAD_FILE, kTraceError,
2604 "GetLocalPlayoutPosition() failed");
2605 return -1;
2606 }
2607 positionMs = position;
2608
2609 return 0;
2610}
2611
2612int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002613 bool loop,
2614 FileFormats format,
2615 int startPosition,
2616 float volumeScaling,
2617 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002618 const CodecInst* codecInst)
2619{
2620 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2621 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2622 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2623 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2624 startPosition, stopPosition);
2625
2626 if (_inputFilePlaying)
2627 {
2628 _engineStatisticsPtr->SetLastError(
2629 VE_ALREADY_PLAYING, kTraceWarning,
2630 "StartPlayingFileAsMicrophone() filePlayer is playing");
2631 return 0;
2632 }
2633
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002634 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002635
2636 // Destroy the old instance
2637 if (_inputFilePlayerPtr)
2638 {
2639 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2640 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2641 _inputFilePlayerPtr = NULL;
2642 }
2643
2644 // Create the instance
2645 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2646 _inputFilePlayerId, (const FileFormats)format);
2647
2648 if (_inputFilePlayerPtr == NULL)
2649 {
2650 _engineStatisticsPtr->SetLastError(
2651 VE_INVALID_ARGUMENT, kTraceError,
2652 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2653 return -1;
2654 }
2655
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002656 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002657
2658 if (_inputFilePlayerPtr->StartPlayingFile(
2659 fileName,
2660 loop,
2661 startPosition,
2662 volumeScaling,
2663 notificationTime,
2664 stopPosition,
2665 (const CodecInst*)codecInst) != 0)
2666 {
2667 _engineStatisticsPtr->SetLastError(
2668 VE_BAD_FILE, kTraceError,
2669 "StartPlayingFile() failed to start file playout");
2670 _inputFilePlayerPtr->StopPlayingFile();
2671 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2672 _inputFilePlayerPtr = NULL;
2673 return -1;
2674 }
2675 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2676 _inputFilePlaying = true;
2677
2678 return 0;
2679}
2680
2681int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002682 FileFormats format,
2683 int startPosition,
2684 float volumeScaling,
2685 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002686 const CodecInst* codecInst)
2687{
2688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2689 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2690 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2691 format, volumeScaling, startPosition, stopPosition);
2692
2693 if(stream == NULL)
2694 {
2695 _engineStatisticsPtr->SetLastError(
2696 VE_BAD_FILE, kTraceError,
2697 "StartPlayingFileAsMicrophone NULL as input stream");
2698 return -1;
2699 }
2700
2701 if (_inputFilePlaying)
2702 {
2703 _engineStatisticsPtr->SetLastError(
2704 VE_ALREADY_PLAYING, kTraceWarning,
2705 "StartPlayingFileAsMicrophone() is playing");
2706 return 0;
2707 }
2708
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002709 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002710
2711 // Destroy the old instance
2712 if (_inputFilePlayerPtr)
2713 {
2714 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2715 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2716 _inputFilePlayerPtr = NULL;
2717 }
2718
2719 // Create the instance
2720 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2721 _inputFilePlayerId, (const FileFormats)format);
2722
2723 if (_inputFilePlayerPtr == NULL)
2724 {
2725 _engineStatisticsPtr->SetLastError(
2726 VE_INVALID_ARGUMENT, kTraceError,
2727 "StartPlayingInputFile() filePlayer format isnot correct");
2728 return -1;
2729 }
2730
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002731 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002732
2733 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2734 volumeScaling, notificationTime,
2735 stopPosition, codecInst) != 0)
2736 {
2737 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2738 "StartPlayingFile() failed to start "
2739 "file playout");
2740 _inputFilePlayerPtr->StopPlayingFile();
2741 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2742 _inputFilePlayerPtr = NULL;
2743 return -1;
2744 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002745
niklase@google.com470e71d2011-07-07 08:21:25 +00002746 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2747 _inputFilePlaying = true;
2748
2749 return 0;
2750}
2751
2752int Channel::StopPlayingFileAsMicrophone()
2753{
2754 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2755 "Channel::StopPlayingFileAsMicrophone()");
2756
2757 if (!_inputFilePlaying)
2758 {
2759 _engineStatisticsPtr->SetLastError(
2760 VE_INVALID_OPERATION, kTraceWarning,
2761 "StopPlayingFileAsMicrophone() isnot playing");
2762 return 0;
2763 }
2764
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002765 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002766 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2767 {
2768 _engineStatisticsPtr->SetLastError(
2769 VE_STOP_RECORDING_FAILED, kTraceError,
2770 "StopPlayingFile() could not stop playing");
2771 return -1;
2772 }
2773 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2774 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2775 _inputFilePlayerPtr = NULL;
2776 _inputFilePlaying = false;
2777
2778 return 0;
2779}
2780
2781int Channel::IsPlayingFileAsMicrophone() const
2782{
2783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2784 "Channel::IsPlayingFileAsMicrophone()");
2785
2786 return _inputFilePlaying;
2787}
2788
pbos@webrtc.org92135212013-05-14 08:31:39 +00002789int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002790{
2791 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2792 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2793
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002794 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002795
2796 if (!_inputFilePlaying)
2797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_INVALID_OPERATION, kTraceError,
2800 "ScaleFileAsMicrophonePlayout() isnot playing");
2801 return -1;
2802 }
2803
2804 if ((_inputFilePlayerPtr == NULL) ||
2805 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2806 {
2807 _engineStatisticsPtr->SetLastError(
2808 VE_BAD_ARGUMENT, kTraceError,
2809 "SetAudioScaling() failed to scale playout");
2810 return -1;
2811 }
2812
2813 return 0;
2814}
2815
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002816int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002817 const CodecInst* codecInst)
2818{
2819 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2820 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2821
2822 if (_outputFileRecording)
2823 {
2824 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2825 "StartRecordingPlayout() is already recording");
2826 return 0;
2827 }
2828
2829 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002830 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002831 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2832
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002833 if ((codecInst != NULL) &&
2834 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002835 {
2836 _engineStatisticsPtr->SetLastError(
2837 VE_BAD_ARGUMENT, kTraceError,
2838 "StartRecordingPlayout() invalid compression");
2839 return(-1);
2840 }
2841 if(codecInst == NULL)
2842 {
2843 format = kFileFormatPcm16kHzFile;
2844 codecInst=&dummyCodec;
2845 }
2846 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2847 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2848 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2849 {
2850 format = kFileFormatWavFile;
2851 }
2852 else
2853 {
2854 format = kFileFormatCompressedFile;
2855 }
2856
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002857 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002858
2859 // Destroy the old instance
2860 if (_outputFileRecorderPtr)
2861 {
2862 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2863 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2864 _outputFileRecorderPtr = NULL;
2865 }
2866
2867 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2868 _outputFileRecorderId, (const FileFormats)format);
2869 if (_outputFileRecorderPtr == NULL)
2870 {
2871 _engineStatisticsPtr->SetLastError(
2872 VE_INVALID_ARGUMENT, kTraceError,
2873 "StartRecordingPlayout() fileRecorder format isnot correct");
2874 return -1;
2875 }
2876
2877 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2878 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2879 {
2880 _engineStatisticsPtr->SetLastError(
2881 VE_BAD_FILE, kTraceError,
2882 "StartRecordingAudioFile() failed to start file recording");
2883 _outputFileRecorderPtr->StopRecording();
2884 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2885 _outputFileRecorderPtr = NULL;
2886 return -1;
2887 }
2888 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2889 _outputFileRecording = true;
2890
2891 return 0;
2892}
2893
2894int Channel::StartRecordingPlayout(OutStream* stream,
2895 const CodecInst* codecInst)
2896{
2897 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2898 "Channel::StartRecordingPlayout()");
2899
2900 if (_outputFileRecording)
2901 {
2902 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2903 "StartRecordingPlayout() is already recording");
2904 return 0;
2905 }
2906
2907 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002908 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002909 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2910
2911 if (codecInst != NULL && codecInst->channels != 1)
2912 {
2913 _engineStatisticsPtr->SetLastError(
2914 VE_BAD_ARGUMENT, kTraceError,
2915 "StartRecordingPlayout() invalid compression");
2916 return(-1);
2917 }
2918 if(codecInst == NULL)
2919 {
2920 format = kFileFormatPcm16kHzFile;
2921 codecInst=&dummyCodec;
2922 }
2923 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2924 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2925 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2926 {
2927 format = kFileFormatWavFile;
2928 }
2929 else
2930 {
2931 format = kFileFormatCompressedFile;
2932 }
2933
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002934 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002935
2936 // Destroy the old instance
2937 if (_outputFileRecorderPtr)
2938 {
2939 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2940 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2941 _outputFileRecorderPtr = NULL;
2942 }
2943
2944 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2945 _outputFileRecorderId, (const FileFormats)format);
2946 if (_outputFileRecorderPtr == NULL)
2947 {
2948 _engineStatisticsPtr->SetLastError(
2949 VE_INVALID_ARGUMENT, kTraceError,
2950 "StartRecordingPlayout() fileRecorder format isnot correct");
2951 return -1;
2952 }
2953
2954 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2955 notificationTime) != 0)
2956 {
2957 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2958 "StartRecordingPlayout() failed to "
2959 "start file recording");
2960 _outputFileRecorderPtr->StopRecording();
2961 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2962 _outputFileRecorderPtr = NULL;
2963 return -1;
2964 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002965
niklase@google.com470e71d2011-07-07 08:21:25 +00002966 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2967 _outputFileRecording = true;
2968
2969 return 0;
2970}
2971
2972int Channel::StopRecordingPlayout()
2973{
2974 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2975 "Channel::StopRecordingPlayout()");
2976
2977 if (!_outputFileRecording)
2978 {
2979 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2980 "StopRecordingPlayout() isnot recording");
2981 return -1;
2982 }
2983
2984
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002985 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002986
2987 if (_outputFileRecorderPtr->StopRecording() != 0)
2988 {
2989 _engineStatisticsPtr->SetLastError(
2990 VE_STOP_RECORDING_FAILED, kTraceError,
2991 "StopRecording() could not stop recording");
2992 return(-1);
2993 }
2994 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2995 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2996 _outputFileRecorderPtr = NULL;
2997 _outputFileRecording = false;
2998
2999 return 0;
3000}
3001
3002void
3003Channel::SetMixWithMicStatus(bool mix)
3004{
3005 _mixFileWithMicrophone=mix;
3006}
3007
3008int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003009Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003010{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003011 int8_t currentLevel = _outputAudioLevel.Level();
3012 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003013 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3014 VoEId(_instanceId,_channelId),
3015 "GetSpeechOutputLevel() => level=%u", level);
3016 return 0;
3017}
3018
3019int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003020Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003021{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003022 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
3023 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003024 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3025 VoEId(_instanceId,_channelId),
3026 "GetSpeechOutputLevelFullRange() => level=%u", level);
3027 return 0;
3028}
3029
3030int
3031Channel::SetMute(bool enable)
3032{
3033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3034 "Channel::SetMute(enable=%d)", enable);
3035 _mute = enable;
3036 return 0;
3037}
3038
3039bool
3040Channel::Mute() const
3041{
3042 return _mute;
3043}
3044
3045int
3046Channel::SetOutputVolumePan(float left, float right)
3047{
3048 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3049 "Channel::SetOutputVolumePan()");
3050 _panLeft = left;
3051 _panRight = right;
3052 return 0;
3053}
3054
3055int
3056Channel::GetOutputVolumePan(float& left, float& right) const
3057{
3058 left = _panLeft;
3059 right = _panRight;
3060 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3061 VoEId(_instanceId,_channelId),
3062 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3063 return 0;
3064}
3065
3066int
3067Channel::SetChannelOutputVolumeScaling(float scaling)
3068{
3069 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3070 "Channel::SetChannelOutputVolumeScaling()");
3071 _outputGain = scaling;
3072 return 0;
3073}
3074
3075int
3076Channel::GetChannelOutputVolumeScaling(float& scaling) const
3077{
3078 scaling = _outputGain;
3079 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3080 VoEId(_instanceId,_channelId),
3081 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3082 return 0;
3083}
3084
niklase@google.com470e71d2011-07-07 08:21:25 +00003085int
3086Channel::RegisterExternalEncryption(Encryption& encryption)
3087{
3088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3089 "Channel::RegisterExternalEncryption()");
3090
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003091 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003092
3093 if (_encryptionPtr)
3094 {
3095 _engineStatisticsPtr->SetLastError(
3096 VE_INVALID_OPERATION, kTraceError,
3097 "RegisterExternalEncryption() encryption already enabled");
3098 return -1;
3099 }
3100
3101 _encryptionPtr = &encryption;
3102
3103 _decrypting = true;
3104 _encrypting = true;
3105
3106 return 0;
3107}
3108
3109int
3110Channel::DeRegisterExternalEncryption()
3111{
3112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3113 "Channel::DeRegisterExternalEncryption()");
3114
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003115 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003116
3117 if (!_encryptionPtr)
3118 {
3119 _engineStatisticsPtr->SetLastError(
3120 VE_INVALID_OPERATION, kTraceWarning,
3121 "DeRegisterExternalEncryption() encryption already disabled");
3122 return 0;
3123 }
3124
3125 _decrypting = false;
3126 _encrypting = false;
3127
3128 _encryptionPtr = NULL;
3129
3130 return 0;
3131}
3132
3133int Channel::SendTelephoneEventOutband(unsigned char eventCode,
3134 int lengthMs, int attenuationDb,
3135 bool playDtmfEvent)
3136{
3137 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3138 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3139 playDtmfEvent);
3140
3141 _playOutbandDtmfEvent = playDtmfEvent;
3142
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003143 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003144 attenuationDb) != 0)
3145 {
3146 _engineStatisticsPtr->SetLastError(
3147 VE_SEND_DTMF_FAILED,
3148 kTraceWarning,
3149 "SendTelephoneEventOutband() failed to send event");
3150 return -1;
3151 }
3152 return 0;
3153}
3154
3155int Channel::SendTelephoneEventInband(unsigned char eventCode,
3156 int lengthMs,
3157 int attenuationDb,
3158 bool playDtmfEvent)
3159{
3160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3161 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3162 playDtmfEvent);
3163
3164 _playInbandDtmfEvent = playDtmfEvent;
3165 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3166
3167 return 0;
3168}
3169
3170int
3171Channel::SetDtmfPlayoutStatus(bool enable)
3172{
3173 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3174 "Channel::SetDtmfPlayoutStatus()");
3175 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3176 {
3177 _engineStatisticsPtr->SetLastError(
3178 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3179 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3180 return -1;
3181 }
3182 return 0;
3183}
3184
3185bool
3186Channel::DtmfPlayoutStatus() const
3187{
3188 return _audioCodingModule.DtmfPlayoutStatus();
3189}
3190
3191int
3192Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3193{
3194 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3195 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003196 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003197 {
3198 _engineStatisticsPtr->SetLastError(
3199 VE_INVALID_ARGUMENT, kTraceError,
3200 "SetSendTelephoneEventPayloadType() invalid type");
3201 return -1;
3202 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003203 CodecInst codec;
3204 codec.plfreq = 8000;
3205 codec.pltype = type;
3206 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003207 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003208 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003209 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3210 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3213 "SetSendTelephoneEventPayloadType() failed to register send"
3214 "payload type");
3215 return -1;
3216 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003217 }
3218 _sendTelephoneEventPayloadType = type;
3219 return 0;
3220}
3221
3222int
3223Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3224{
3225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3226 "Channel::GetSendTelephoneEventPayloadType()");
3227 type = _sendTelephoneEventPayloadType;
3228 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3229 VoEId(_instanceId,_channelId),
3230 "GetSendTelephoneEventPayloadType() => type=%u", type);
3231 return 0;
3232}
3233
niklase@google.com470e71d2011-07-07 08:21:25 +00003234int
3235Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3236{
3237 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3238 "Channel::UpdateRxVadDetection()");
3239
3240 int vadDecision = 1;
3241
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003242 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003243
3244 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3245 {
3246 OnRxVadDetected(vadDecision);
3247 _oldVadDecision = vadDecision;
3248 }
3249
3250 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3251 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3252 vadDecision);
3253 return 0;
3254}
3255
3256int
3257Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3258{
3259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3260 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003261 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003262
3263 if (_rxVadObserverPtr)
3264 {
3265 _engineStatisticsPtr->SetLastError(
3266 VE_INVALID_OPERATION, kTraceError,
3267 "RegisterRxVadObserver() observer already enabled");
3268 return -1;
3269 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 _rxVadObserverPtr = &observer;
3271 _RxVadDetection = true;
3272 return 0;
3273}
3274
3275int
3276Channel::DeRegisterRxVadObserver()
3277{
3278 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3279 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003280 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003281
3282 if (!_rxVadObserverPtr)
3283 {
3284 _engineStatisticsPtr->SetLastError(
3285 VE_INVALID_OPERATION, kTraceWarning,
3286 "DeRegisterRxVadObserver() observer already disabled");
3287 return 0;
3288 }
3289 _rxVadObserverPtr = NULL;
3290 _RxVadDetection = false;
3291 return 0;
3292}
3293
3294int
3295Channel::VoiceActivityIndicator(int &activity)
3296{
3297 activity = _sendFrameType;
3298
3299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3300 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3301 return 0;
3302}
3303
3304#ifdef WEBRTC_VOICE_ENGINE_AGC
3305
3306int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003307Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003308{
3309 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3310 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3311 (int)enable, (int)mode);
3312
3313 GainControl::Mode agcMode(GainControl::kFixedDigital);
3314 switch (mode)
3315 {
3316 case kAgcDefault:
3317 agcMode = GainControl::kAdaptiveDigital;
3318 break;
3319 case kAgcUnchanged:
3320 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3321 break;
3322 case kAgcFixedDigital:
3323 agcMode = GainControl::kFixedDigital;
3324 break;
3325 case kAgcAdaptiveDigital:
3326 agcMode =GainControl::kAdaptiveDigital;
3327 break;
3328 default:
3329 _engineStatisticsPtr->SetLastError(
3330 VE_INVALID_ARGUMENT, kTraceError,
3331 "SetRxAgcStatus() invalid Agc mode");
3332 return -1;
3333 }
3334
3335 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3336 {
3337 _engineStatisticsPtr->SetLastError(
3338 VE_APM_ERROR, kTraceError,
3339 "SetRxAgcStatus() failed to set Agc mode");
3340 return -1;
3341 }
3342 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3343 {
3344 _engineStatisticsPtr->SetLastError(
3345 VE_APM_ERROR, kTraceError,
3346 "SetRxAgcStatus() failed to set Agc state");
3347 return -1;
3348 }
3349
3350 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003351 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3352
3353 return 0;
3354}
3355
3356int
3357Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3358{
3359 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3360 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3361
3362 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3363 GainControl::Mode agcMode =
3364 _rxAudioProcessingModulePtr->gain_control()->mode();
3365
3366 enabled = enable;
3367
3368 switch (agcMode)
3369 {
3370 case GainControl::kFixedDigital:
3371 mode = kAgcFixedDigital;
3372 break;
3373 case GainControl::kAdaptiveDigital:
3374 mode = kAgcAdaptiveDigital;
3375 break;
3376 default:
3377 _engineStatisticsPtr->SetLastError(
3378 VE_APM_ERROR, kTraceError,
3379 "GetRxAgcStatus() invalid Agc mode");
3380 return -1;
3381 }
3382
3383 return 0;
3384}
3385
3386int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003387Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003388{
3389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3390 "Channel::SetRxAgcConfig()");
3391
3392 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3393 config.targetLeveldBOv) != 0)
3394 {
3395 _engineStatisticsPtr->SetLastError(
3396 VE_APM_ERROR, kTraceError,
3397 "SetRxAgcConfig() failed to set target peak |level|"
3398 "(or envelope) of the Agc");
3399 return -1;
3400 }
3401 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3402 config.digitalCompressionGaindB) != 0)
3403 {
3404 _engineStatisticsPtr->SetLastError(
3405 VE_APM_ERROR, kTraceError,
3406 "SetRxAgcConfig() failed to set the range in |gain| the"
3407 " digital compression stage may apply");
3408 return -1;
3409 }
3410 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3411 config.limiterEnable) != 0)
3412 {
3413 _engineStatisticsPtr->SetLastError(
3414 VE_APM_ERROR, kTraceError,
3415 "SetRxAgcConfig() failed to set hard limiter to the signal");
3416 return -1;
3417 }
3418
3419 return 0;
3420}
3421
3422int
3423Channel::GetRxAgcConfig(AgcConfig& config)
3424{
3425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3426 "Channel::GetRxAgcConfig(config=%?)");
3427
3428 config.targetLeveldBOv =
3429 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3430 config.digitalCompressionGaindB =
3431 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3432 config.limiterEnable =
3433 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3434
3435 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3436 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3437 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3438 " limiterEnable=%d",
3439 config.targetLeveldBOv,
3440 config.digitalCompressionGaindB,
3441 config.limiterEnable);
3442
3443 return 0;
3444}
3445
3446#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3447
3448#ifdef WEBRTC_VOICE_ENGINE_NR
3449
3450int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003451Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003452{
3453 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3454 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3455 (int)enable, (int)mode);
3456
3457 NoiseSuppression::Level nsLevel(
3458 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3459 switch (mode)
3460 {
3461
3462 case kNsDefault:
3463 nsLevel = (NoiseSuppression::Level)
3464 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3465 break;
3466 case kNsUnchanged:
3467 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3468 break;
3469 case kNsConference:
3470 nsLevel = NoiseSuppression::kHigh;
3471 break;
3472 case kNsLowSuppression:
3473 nsLevel = NoiseSuppression::kLow;
3474 break;
3475 case kNsModerateSuppression:
3476 nsLevel = NoiseSuppression::kModerate;
3477 break;
3478 case kNsHighSuppression:
3479 nsLevel = NoiseSuppression::kHigh;
3480 break;
3481 case kNsVeryHighSuppression:
3482 nsLevel = NoiseSuppression::kVeryHigh;
3483 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003484 }
3485
3486 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3487 != 0)
3488 {
3489 _engineStatisticsPtr->SetLastError(
3490 VE_APM_ERROR, kTraceError,
3491 "SetRxAgcStatus() failed to set Ns level");
3492 return -1;
3493 }
3494 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3495 {
3496 _engineStatisticsPtr->SetLastError(
3497 VE_APM_ERROR, kTraceError,
3498 "SetRxAgcStatus() failed to set Agc state");
3499 return -1;
3500 }
3501
3502 _rxNsIsEnabled = enable;
3503 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3504
3505 return 0;
3506}
3507
3508int
3509Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3510{
3511 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3512 "Channel::GetRxNsStatus(enable=?, mode=?)");
3513
3514 bool enable =
3515 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3516 NoiseSuppression::Level ncLevel =
3517 _rxAudioProcessingModulePtr->noise_suppression()->level();
3518
3519 enabled = enable;
3520
3521 switch (ncLevel)
3522 {
3523 case NoiseSuppression::kLow:
3524 mode = kNsLowSuppression;
3525 break;
3526 case NoiseSuppression::kModerate:
3527 mode = kNsModerateSuppression;
3528 break;
3529 case NoiseSuppression::kHigh:
3530 mode = kNsHighSuppression;
3531 break;
3532 case NoiseSuppression::kVeryHigh:
3533 mode = kNsVeryHighSuppression;
3534 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003535 }
3536
3537 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3538 VoEId(_instanceId,_channelId),
3539 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3540 return 0;
3541}
3542
3543#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3544
3545int
3546Channel::RegisterRTPObserver(VoERTPObserver& observer)
3547{
3548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3549 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003550 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003551
3552 if (_rtpObserverPtr)
3553 {
3554 _engineStatisticsPtr->SetLastError(
3555 VE_INVALID_OPERATION, kTraceError,
3556 "RegisterRTPObserver() observer already enabled");
3557 return -1;
3558 }
3559
3560 _rtpObserverPtr = &observer;
3561 _rtpObserver = true;
3562
3563 return 0;
3564}
3565
3566int
3567Channel::DeRegisterRTPObserver()
3568{
3569 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3570 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003571 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003572
3573 if (!_rtpObserverPtr)
3574 {
3575 _engineStatisticsPtr->SetLastError(
3576 VE_INVALID_OPERATION, kTraceWarning,
3577 "DeRegisterRTPObserver() observer already disabled");
3578 return 0;
3579 }
3580
3581 _rtpObserver = false;
3582 _rtpObserverPtr = NULL;
3583
3584 return 0;
3585}
3586
3587int
3588Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3589{
3590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3591 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003592 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003593
3594 if (_rtcpObserverPtr)
3595 {
3596 _engineStatisticsPtr->SetLastError(
3597 VE_INVALID_OPERATION, kTraceError,
3598 "RegisterRTCPObserver() observer already enabled");
3599 return -1;
3600 }
3601
3602 _rtcpObserverPtr = &observer;
3603 _rtcpObserver = true;
3604
3605 return 0;
3606}
3607
3608int
3609Channel::DeRegisterRTCPObserver()
3610{
3611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3612 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003613 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003614
3615 if (!_rtcpObserverPtr)
3616 {
3617 _engineStatisticsPtr->SetLastError(
3618 VE_INVALID_OPERATION, kTraceWarning,
3619 "DeRegisterRTCPObserver() observer already disabled");
3620 return 0;
3621 }
3622
3623 _rtcpObserver = false;
3624 _rtcpObserverPtr = NULL;
3625
3626 return 0;
3627}
3628
3629int
3630Channel::SetLocalSSRC(unsigned int ssrc)
3631{
3632 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3633 "Channel::SetLocalSSRC()");
3634 if (_sending)
3635 {
3636 _engineStatisticsPtr->SetLastError(
3637 VE_ALREADY_SENDING, kTraceError,
3638 "SetLocalSSRC() already sending");
3639 return -1;
3640 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003641 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003642 {
3643 _engineStatisticsPtr->SetLastError(
3644 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3645 "SetLocalSSRC() failed to set SSRC");
3646 return -1;
3647 }
3648 return 0;
3649}
3650
3651int
3652Channel::GetLocalSSRC(unsigned int& ssrc)
3653{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003654 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003655 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3656 VoEId(_instanceId,_channelId),
3657 "GetLocalSSRC() => ssrc=%lu", ssrc);
3658 return 0;
3659}
3660
3661int
3662Channel::GetRemoteSSRC(unsigned int& ssrc)
3663{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003664 ssrc = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003665 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3666 VoEId(_instanceId,_channelId),
3667 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3668 return 0;
3669}
3670
3671int
3672Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3673{
3674 if (arrCSRC == NULL)
3675 {
3676 _engineStatisticsPtr->SetLastError(
3677 VE_INVALID_ARGUMENT, kTraceError,
3678 "GetRemoteCSRCs() invalid array argument");
3679 return -1;
3680 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003681 uint32_t arrOfCSRC[kRtpCsrcSize];
3682 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003683 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003684 if (CSRCs > 0)
3685 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003686 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003687 for (int i = 0; i < (int) CSRCs; i++)
3688 {
3689 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3690 VoEId(_instanceId, _channelId),
3691 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3692 }
3693 } else
3694 {
3695 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3696 VoEId(_instanceId, _channelId),
3697 "GetRemoteCSRCs() => list is empty!");
3698 }
3699 return CSRCs;
3700}
3701
3702int
3703Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3704{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003705 if (_rtpAudioProc.get() == NULL)
3706 {
3707 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3708 _channelId)));
3709 if (_rtpAudioProc.get() == NULL)
3710 {
3711 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3712 "Failed to create AudioProcessing");
3713 return -1;
3714 }
3715 }
3716
3717 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3718 AudioProcessing::kNoError)
3719 {
3720 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3721 "Failed to enable AudioProcessing::level_estimator()");
3722 }
3723
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 _includeAudioLevelIndication = enable;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00003725 if (enable) {
3726 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3727 ID);
3728 } else {
3729 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3730 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003731 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003732}
3733int
3734Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3735{
3736 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3737 VoEId(_instanceId,_channelId),
3738 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3739 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003740 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003741}
3742
3743int
3744Channel::SetRTCPStatus(bool enable)
3745{
3746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3747 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003748 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003749 kRtcpCompound : kRtcpOff) != 0)
3750 {
3751 _engineStatisticsPtr->SetLastError(
3752 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3753 "SetRTCPStatus() failed to set RTCP status");
3754 return -1;
3755 }
3756 return 0;
3757}
3758
3759int
3760Channel::GetRTCPStatus(bool& enabled)
3761{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003762 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003763 enabled = (method != kRtcpOff);
3764 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3765 VoEId(_instanceId,_channelId),
3766 "GetRTCPStatus() => enabled=%d", enabled);
3767 return 0;
3768}
3769
3770int
3771Channel::SetRTCP_CNAME(const char cName[256])
3772{
3773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3774 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003775 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 {
3777 _engineStatisticsPtr->SetLastError(
3778 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3779 "SetRTCP_CNAME() failed to set RTCP CNAME");
3780 return -1;
3781 }
3782 return 0;
3783}
3784
3785int
3786Channel::GetRTCP_CNAME(char cName[256])
3787{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003788 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003789 {
3790 _engineStatisticsPtr->SetLastError(
3791 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3792 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3793 return -1;
3794 }
3795 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3796 VoEId(_instanceId, _channelId),
3797 "GetRTCP_CNAME() => cName=%s", cName);
3798 return 0;
3799}
3800
3801int
3802Channel::GetRemoteRTCP_CNAME(char cName[256])
3803{
3804 if (cName == NULL)
3805 {
3806 _engineStatisticsPtr->SetLastError(
3807 VE_INVALID_ARGUMENT, kTraceError,
3808 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3809 return -1;
3810 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003811 char cname[RTCP_CNAME_SIZE];
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003812 const uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003813 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003814 {
3815 _engineStatisticsPtr->SetLastError(
3816 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3817 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3818 return -1;
3819 }
3820 strcpy(cName, cname);
3821 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3822 VoEId(_instanceId, _channelId),
3823 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3824 return 0;
3825}
3826
3827int
3828Channel::GetRemoteRTCPData(
3829 unsigned int& NTPHigh,
3830 unsigned int& NTPLow,
3831 unsigned int& timestamp,
3832 unsigned int& playoutTimestamp,
3833 unsigned int* jitter,
3834 unsigned short* fractionLost)
3835{
3836 // --- Information from sender info in received Sender Reports
3837
3838 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003839 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003840 {
3841 _engineStatisticsPtr->SetLastError(
3842 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003843 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003844 "side");
3845 return -1;
3846 }
3847
3848 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3849 // and octet count)
3850 NTPHigh = senderInfo.NTPseconds;
3851 NTPLow = senderInfo.NTPfraction;
3852 timestamp = senderInfo.RTPtimeStamp;
3853
3854 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3855 VoEId(_instanceId, _channelId),
3856 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3857 "timestamp=%lu",
3858 NTPHigh, NTPLow, timestamp);
3859
3860 // --- Locally derived information
3861
3862 // This value is updated on each incoming RTCP packet (0 when no packet
3863 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003864 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003865
3866 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3867 VoEId(_instanceId, _channelId),
3868 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003869 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003870
3871 if (NULL != jitter || NULL != fractionLost)
3872 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003873 // Get all RTCP receiver report blocks that have been received on this
3874 // channel. If we receive RTP packets from a remote source we know the
3875 // remote SSRC and use the report block from him.
3876 // Otherwise use the first report block.
3877 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003878 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003879 remote_stats.empty()) {
3880 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3881 VoEId(_instanceId, _channelId),
3882 "GetRemoteRTCPData() failed to measure statistics due"
3883 " to lack of received RTP and/or RTCP packets");
3884 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003885 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003886
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003887 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003888 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3889 for (; it != remote_stats.end(); ++it) {
3890 if (it->remoteSSRC == remoteSSRC)
3891 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003892 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003893
3894 if (it == remote_stats.end()) {
3895 // If we have not received any RTCP packets from this SSRC it probably
3896 // means that we have not received any RTP packets.
3897 // Use the first received report block instead.
3898 it = remote_stats.begin();
3899 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003900 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003901
xians@webrtc.org79af7342012-01-31 12:22:14 +00003902 if (jitter) {
3903 *jitter = it->jitter;
3904 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3905 VoEId(_instanceId, _channelId),
3906 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3907 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003908
xians@webrtc.org79af7342012-01-31 12:22:14 +00003909 if (fractionLost) {
3910 *fractionLost = it->fractionLost;
3911 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3912 VoEId(_instanceId, _channelId),
3913 "GetRemoteRTCPData() => fractionLost = %lu",
3914 *fractionLost);
3915 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003916 }
3917 return 0;
3918}
3919
3920int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003921Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003922 unsigned int name,
3923 const char* data,
3924 unsigned short dataLengthInBytes)
3925{
3926 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3927 "Channel::SendApplicationDefinedRTCPPacket()");
3928 if (!_sending)
3929 {
3930 _engineStatisticsPtr->SetLastError(
3931 VE_NOT_SENDING, kTraceError,
3932 "SendApplicationDefinedRTCPPacket() not sending");
3933 return -1;
3934 }
3935 if (NULL == data)
3936 {
3937 _engineStatisticsPtr->SetLastError(
3938 VE_INVALID_ARGUMENT, kTraceError,
3939 "SendApplicationDefinedRTCPPacket() invalid data value");
3940 return -1;
3941 }
3942 if (dataLengthInBytes % 4 != 0)
3943 {
3944 _engineStatisticsPtr->SetLastError(
3945 VE_INVALID_ARGUMENT, kTraceError,
3946 "SendApplicationDefinedRTCPPacket() invalid length value");
3947 return -1;
3948 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003949 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003950 if (status == kRtcpOff)
3951 {
3952 _engineStatisticsPtr->SetLastError(
3953 VE_RTCP_ERROR, kTraceError,
3954 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3955 return -1;
3956 }
3957
3958 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003959 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003960 subType,
3961 name,
3962 (const unsigned char*) data,
3963 dataLengthInBytes) != 0)
3964 {
3965 _engineStatisticsPtr->SetLastError(
3966 VE_SEND_ERROR, kTraceError,
3967 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3968 return -1;
3969 }
3970 return 0;
3971}
3972
3973int
3974Channel::GetRTPStatistics(
3975 unsigned int& averageJitterMs,
3976 unsigned int& maxJitterMs,
3977 unsigned int& discardedPackets)
3978{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003979 uint8_t fraction_lost(0);
3980 uint32_t cum_lost(0);
3981 uint32_t ext_max(0);
3982 uint32_t jitter(0);
3983 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003984
3985 // The jitter statistics is updated for each received RTP packet and is
3986 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003987 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00003988 &cum_lost,
3989 &ext_max,
3990 &jitter,
3991 &max_jitter) != 0)
3992 {
3993 _engineStatisticsPtr->SetLastError(
3994 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003995 "GetRTPStatistics() failed to read RTP statistics from the "
niklase@google.com470e71d2011-07-07 08:21:25 +00003996 "RTP/RTCP module");
3997 }
3998
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003999 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00004000 _audioCodingModule.PlayoutFrequency();
4001 if (playoutFrequency > 0)
4002 {
4003 // Scale RTP statistics given the current playout frequency
4004 maxJitterMs = max_jitter / (playoutFrequency / 1000);
4005 averageJitterMs = jitter / (playoutFrequency / 1000);
4006 }
4007
4008 discardedPackets = _numberOfDiscardedPackets;
4009
4010 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4011 VoEId(_instanceId, _channelId),
4012 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004013 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004014 averageJitterMs, maxJitterMs, discardedPackets);
4015 return 0;
4016}
4017
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00004018int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
4019 if (sender_info == NULL) {
4020 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4021 "GetRemoteRTCPSenderInfo() invalid sender_info.");
4022 return -1;
4023 }
4024
4025 // Get the sender info from the latest received RTCP Sender Report.
4026 RTCPSenderInfo rtcp_sender_info;
4027 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
4028 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4029 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
4030 return -1;
4031 }
4032
4033 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
4034 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
4035 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
4036 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
4037 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
4038 return 0;
4039}
4040
4041int Channel::GetRemoteRTCPReportBlocks(
4042 std::vector<ReportBlock>* report_blocks) {
4043 if (report_blocks == NULL) {
4044 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4045 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4046 return -1;
4047 }
4048
4049 // Get the report blocks from the latest received RTCP Sender or Receiver
4050 // Report. Each element in the vector contains the sender's SSRC and a
4051 // report block according to RFC 3550.
4052 std::vector<RTCPReportBlock> rtcp_report_blocks;
4053 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4054 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4055 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4056 return -1;
4057 }
4058
4059 if (rtcp_report_blocks.empty())
4060 return 0;
4061
4062 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4063 for (; it != rtcp_report_blocks.end(); ++it) {
4064 ReportBlock report_block;
4065 report_block.sender_SSRC = it->remoteSSRC;
4066 report_block.source_SSRC = it->sourceSSRC;
4067 report_block.fraction_lost = it->fractionLost;
4068 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4069 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4070 report_block.interarrival_jitter = it->jitter;
4071 report_block.last_SR_timestamp = it->lastSR;
4072 report_block.delay_since_last_SR = it->delaySinceLastSR;
4073 report_blocks->push_back(report_block);
4074 }
4075 return 0;
4076}
4077
niklase@google.com470e71d2011-07-07 08:21:25 +00004078int
4079Channel::GetRTPStatistics(CallStatistics& stats)
4080{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004081 uint8_t fraction_lost(0);
4082 uint32_t cum_lost(0);
4083 uint32_t ext_max(0);
4084 uint32_t jitter(0);
4085 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004086
4087 // --- Part one of the final structure (four values)
4088
4089 // The jitter statistics is updated for each received RTP packet and is
4090 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004091 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00004092 &cum_lost,
4093 &ext_max,
4094 &jitter,
4095 &max_jitter) != 0)
4096 {
4097 _engineStatisticsPtr->SetLastError(
4098 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4099 "GetRTPStatistics() failed to read RTP statistics from the "
4100 "RTP/RTCP module");
4101 }
4102
4103 stats.fractionLost = fraction_lost;
4104 stats.cumulativeLost = cum_lost;
4105 stats.extendedMax = ext_max;
4106 stats.jitterSamples = jitter;
4107
4108 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4109 VoEId(_instanceId, _channelId),
4110 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004111 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004112 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4113 stats.jitterSamples);
4114
4115 // --- Part two of the final structure (one value)
4116
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004117 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004118 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004119 if (method == kRtcpOff)
4120 {
4121 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4122 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004123 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004124 "measurements cannot be retrieved");
4125 } else
4126 {
4127 // The remote SSRC will be zero if no RTP packet has been received.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004128 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004129 if (remoteSSRC > 0)
4130 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004131 uint16_t avgRTT(0);
4132 uint16_t maxRTT(0);
4133 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004134
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004135 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004136 != 0)
4137 {
4138 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4139 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004140 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004141 "the RTP/RTCP module");
4142 }
4143 } else
4144 {
4145 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4146 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004147 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004148 "RTP packets have been received yet");
4149 }
4150 }
4151
4152 stats.rttMs = static_cast<int> (RTT);
4153
4154 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4155 VoEId(_instanceId, _channelId),
4156 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4157
4158 // --- Part three of the final structure (four values)
4159
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004160 uint32_t bytesSent(0);
4161 uint32_t packetsSent(0);
4162 uint32_t bytesReceived(0);
4163 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004164
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004165 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
niklase@google.com470e71d2011-07-07 08:21:25 +00004166 &packetsSent,
4167 &bytesReceived,
4168 &packetsReceived) != 0)
4169 {
4170 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4171 VoEId(_instanceId, _channelId),
4172 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004173 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004174 }
4175
4176 stats.bytesSent = bytesSent;
4177 stats.packetsSent = packetsSent;
4178 stats.bytesReceived = bytesReceived;
4179 stats.packetsReceived = packetsReceived;
4180
4181 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4182 VoEId(_instanceId, _channelId),
4183 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004184 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004185 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4186 stats.packetsReceived);
4187
4188 return 0;
4189}
4190
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004191int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4193 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004194
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004195 if (enable) {
4196 if (redPayloadtype < 0 || redPayloadtype > 127) {
4197 _engineStatisticsPtr->SetLastError(
4198 VE_PLTYPE_ERROR, kTraceError,
4199 "SetFECStatus() invalid RED payload type");
4200 return -1;
4201 }
4202
4203 if (SetRedPayloadType(redPayloadtype) < 0) {
4204 _engineStatisticsPtr->SetLastError(
4205 VE_CODEC_ERROR, kTraceError,
4206 "SetSecondarySendCodec() Failed to register RED ACM");
4207 return -1;
4208 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004209 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004210
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004211 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4212 _engineStatisticsPtr->SetLastError(
4213 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4214 "SetFECStatus() failed to set FEC state in the ACM");
4215 return -1;
4216 }
4217 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004218}
4219
4220int
4221Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4222{
4223 enabled = _audioCodingModule.FECStatus();
4224 if (enabled)
4225 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004226 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004227 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004228 {
4229 _engineStatisticsPtr->SetLastError(
4230 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4231 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4232 "module");
4233 return -1;
4234 }
4235 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4236 VoEId(_instanceId, _channelId),
4237 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4238 enabled, redPayloadtype);
4239 return 0;
4240 }
4241 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4242 VoEId(_instanceId, _channelId),
4243 "GetFECStatus() => enabled=%d", enabled);
4244 return 0;
4245}
4246
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004247void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4248 // None of these functions can fail.
4249 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
4250 _rtpRtcpModule->SetNACKStatus(enable ? kNackRtcp : kNackOff,
4251 maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004252 if (enable)
4253 _audioCodingModule.EnableNack(maxNumberOfPackets);
4254 else
4255 _audioCodingModule.DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004256}
4257
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004258// Called when we are missing one or more packets.
4259int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004260 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4261}
4262
niklase@google.com470e71d2011-07-07 08:21:25 +00004263int
niklase@google.com470e71d2011-07-07 08:21:25 +00004264Channel::StartRTPDump(const char fileNameUTF8[1024],
4265 RTPDirections direction)
4266{
4267 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4268 "Channel::StartRTPDump()");
4269 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4270 {
4271 _engineStatisticsPtr->SetLastError(
4272 VE_INVALID_ARGUMENT, kTraceError,
4273 "StartRTPDump() invalid RTP direction");
4274 return -1;
4275 }
4276 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4277 &_rtpDumpIn : &_rtpDumpOut;
4278 if (rtpDumpPtr == NULL)
4279 {
4280 assert(false);
4281 return -1;
4282 }
4283 if (rtpDumpPtr->IsActive())
4284 {
4285 rtpDumpPtr->Stop();
4286 }
4287 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4288 {
4289 _engineStatisticsPtr->SetLastError(
4290 VE_BAD_FILE, kTraceError,
4291 "StartRTPDump() failed to create file");
4292 return -1;
4293 }
4294 return 0;
4295}
4296
4297int
4298Channel::StopRTPDump(RTPDirections direction)
4299{
4300 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4301 "Channel::StopRTPDump()");
4302 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4303 {
4304 _engineStatisticsPtr->SetLastError(
4305 VE_INVALID_ARGUMENT, kTraceError,
4306 "StopRTPDump() invalid RTP direction");
4307 return -1;
4308 }
4309 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4310 &_rtpDumpIn : &_rtpDumpOut;
4311 if (rtpDumpPtr == NULL)
4312 {
4313 assert(false);
4314 return -1;
4315 }
4316 if (!rtpDumpPtr->IsActive())
4317 {
4318 return 0;
4319 }
4320 return rtpDumpPtr->Stop();
4321}
4322
4323bool
4324Channel::RTPDumpIsActive(RTPDirections direction)
4325{
4326 if ((direction != kRtpIncoming) &&
4327 (direction != kRtpOutgoing))
4328 {
4329 _engineStatisticsPtr->SetLastError(
4330 VE_INVALID_ARGUMENT, kTraceError,
4331 "RTPDumpIsActive() invalid RTP direction");
4332 return false;
4333 }
4334 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4335 &_rtpDumpIn : &_rtpDumpOut;
4336 return rtpDumpPtr->IsActive();
4337}
4338
4339int
4340Channel::InsertExtraRTPPacket(unsigned char payloadType,
4341 bool markerBit,
4342 const char* payloadData,
4343 unsigned short payloadSize)
4344{
4345 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4346 "Channel::InsertExtraRTPPacket()");
4347 if (payloadType > 127)
4348 {
4349 _engineStatisticsPtr->SetLastError(
4350 VE_INVALID_PLTYPE, kTraceError,
4351 "InsertExtraRTPPacket() invalid payload type");
4352 return -1;
4353 }
4354 if (payloadData == NULL)
4355 {
4356 _engineStatisticsPtr->SetLastError(
4357 VE_INVALID_ARGUMENT, kTraceError,
4358 "InsertExtraRTPPacket() invalid payload data");
4359 return -1;
4360 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004361 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004362 {
4363 _engineStatisticsPtr->SetLastError(
4364 VE_INVALID_ARGUMENT, kTraceError,
4365 "InsertExtraRTPPacket() invalid payload size");
4366 return -1;
4367 }
4368 if (!_sending)
4369 {
4370 _engineStatisticsPtr->SetLastError(
4371 VE_NOT_SENDING, kTraceError,
4372 "InsertExtraRTPPacket() not sending");
4373 return -1;
4374 }
4375
4376 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4377 // Transport::SendPacket() will be called by the module when the RTP packet
4378 // is created.
4379 // The call to SendOutgoingData() does *not* modify the timestamp and
4380 // payloadtype to ensure that the RTP module generates a valid RTP packet
4381 // (user might utilize a non-registered payload type).
4382 // The marker bit and payload type will be replaced just before the actual
4383 // transmission, i.e., the actual modification is done *after* the RTP
4384 // module has delivered its RTP packet back to the VoE.
4385 // We will use the stored values above when the packet is modified
4386 // (see Channel::SendPacket()).
4387
4388 _extraPayloadType = payloadType;
4389 _extraMarkerBit = markerBit;
4390 _insertExtraRTPPacket = true;
4391
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004392 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004393 _lastPayloadType,
4394 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004395 // Leaving the time when this frame was
4396 // received from the capture device as
4397 // undefined for voice for now.
4398 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004399 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004400 payloadSize) != 0)
4401 {
4402 _engineStatisticsPtr->SetLastError(
4403 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4404 "InsertExtraRTPPacket() failed to send extra RTP packet");
4405 return -1;
4406 }
4407
4408 return 0;
4409}
4410
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004411uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004412Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004413{
4414 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004415 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004416 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004417 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004418 return 0;
4419}
4420
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004421uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004422Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004423{
4424 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4425 "Channel::PrepareEncodeAndSend()");
4426
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004427 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004428 {
4429 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4430 "Channel::PrepareEncodeAndSend() invalid audio frame");
4431 return -1;
4432 }
4433
4434 if (_inputFilePlaying)
4435 {
4436 MixOrReplaceAudioWithFile(mixingFrequency);
4437 }
4438
4439 if (_mute)
4440 {
4441 AudioFrameOperations::Mute(_audioFrame);
4442 }
4443
4444 if (_inputExternalMedia)
4445 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004446 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004447 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004448 if (_inputExternalMediaCallbackPtr)
4449 {
4450 _inputExternalMediaCallbackPtr->Process(
4451 _channelId,
4452 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004453 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004454 _audioFrame.samples_per_channel_,
4455 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004456 isStereo);
4457 }
4458 }
4459
4460 InsertInbandDtmfTone();
4461
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004462 if (_includeAudioLevelIndication)
4463 {
4464 assert(_rtpAudioProc.get() != NULL);
4465
4466 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004467 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004468 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004469 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004470 AudioProcessing::kNoError)
4471 {
4472 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4473 VoEId(_instanceId, _channelId),
4474 "Error setting AudioProcessing sample rate");
4475 return -1;
4476 }
4477 }
4478
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004479 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004480 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004481 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4482 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004483 != AudioProcessing::kNoError)
4484 {
4485 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4486 VoEId(_instanceId, _channelId),
4487 "Error setting AudioProcessing channels");
4488 return -1;
4489 }
4490 }
4491
4492 // Performs level analysis only; does not affect the signal.
4493 _rtpAudioProc->ProcessStream(&_audioFrame);
4494 }
4495
niklase@google.com470e71d2011-07-07 08:21:25 +00004496 return 0;
4497}
4498
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004499uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004500Channel::EncodeAndSend()
4501{
4502 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4503 "Channel::EncodeAndSend()");
4504
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004505 assert(_audioFrame.num_channels_ <= 2);
4506 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004507 {
4508 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4509 "Channel::EncodeAndSend() invalid audio frame");
4510 return -1;
4511 }
4512
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004513 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004514
4515 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4516
4517 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004518 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004519 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4520 {
4521 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4522 "Channel::EncodeAndSend() ACM encoding failed");
4523 return -1;
4524 }
4525
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004526 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004527
4528 // --- Encode if complete frame is ready
4529
4530 // This call will trigger AudioPacketizationCallback::SendData if encoding
4531 // is done and payload is ready for packetization and transmission.
4532 return _audioCodingModule.Process();
4533}
4534
4535int Channel::RegisterExternalMediaProcessing(
4536 ProcessingTypes type,
4537 VoEMediaProcess& processObject)
4538{
4539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4540 "Channel::RegisterExternalMediaProcessing()");
4541
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004542 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004543
4544 if (kPlaybackPerChannel == type)
4545 {
4546 if (_outputExternalMediaCallbackPtr)
4547 {
4548 _engineStatisticsPtr->SetLastError(
4549 VE_INVALID_OPERATION, kTraceError,
4550 "Channel::RegisterExternalMediaProcessing() "
4551 "output external media already enabled");
4552 return -1;
4553 }
4554 _outputExternalMediaCallbackPtr = &processObject;
4555 _outputExternalMedia = true;
4556 }
4557 else if (kRecordingPerChannel == type)
4558 {
4559 if (_inputExternalMediaCallbackPtr)
4560 {
4561 _engineStatisticsPtr->SetLastError(
4562 VE_INVALID_OPERATION, kTraceError,
4563 "Channel::RegisterExternalMediaProcessing() "
4564 "output external media already enabled");
4565 return -1;
4566 }
4567 _inputExternalMediaCallbackPtr = &processObject;
4568 _inputExternalMedia = true;
4569 }
4570 return 0;
4571}
4572
4573int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4574{
4575 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4576 "Channel::DeRegisterExternalMediaProcessing()");
4577
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004578 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004579
4580 if (kPlaybackPerChannel == type)
4581 {
4582 if (!_outputExternalMediaCallbackPtr)
4583 {
4584 _engineStatisticsPtr->SetLastError(
4585 VE_INVALID_OPERATION, kTraceWarning,
4586 "Channel::DeRegisterExternalMediaProcessing() "
4587 "output external media already disabled");
4588 return 0;
4589 }
4590 _outputExternalMedia = false;
4591 _outputExternalMediaCallbackPtr = NULL;
4592 }
4593 else if (kRecordingPerChannel == type)
4594 {
4595 if (!_inputExternalMediaCallbackPtr)
4596 {
4597 _engineStatisticsPtr->SetLastError(
4598 VE_INVALID_OPERATION, kTraceWarning,
4599 "Channel::DeRegisterExternalMediaProcessing() "
4600 "input external media already disabled");
4601 return 0;
4602 }
4603 _inputExternalMedia = false;
4604 _inputExternalMediaCallbackPtr = NULL;
4605 }
4606
4607 return 0;
4608}
4609
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004610int Channel::SetExternalMixing(bool enabled) {
4611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4612 "Channel::SetExternalMixing(enabled=%d)", enabled);
4613
4614 if (_playing)
4615 {
4616 _engineStatisticsPtr->SetLastError(
4617 VE_INVALID_OPERATION, kTraceError,
4618 "Channel::SetExternalMixing() "
4619 "external mixing cannot be changed while playing.");
4620 return -1;
4621 }
4622
4623 _externalMixing = enabled;
4624
4625 return 0;
4626}
4627
niklase@google.com470e71d2011-07-07 08:21:25 +00004628int
4629Channel::ResetRTCPStatistics()
4630{
4631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4632 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004633 uint32_t remoteSSRC(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004634 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4635 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004636}
4637
4638int
4639Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4640{
4641 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4642 "Channel::GetRoundTripTimeSummary()");
4643 // Override default module outputs for the case when RTCP is disabled.
4644 // This is done to ensure that we are backward compatible with the
4645 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004646 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004647 {
4648 delaysMs.min = -1;
4649 delaysMs.max = -1;
4650 delaysMs.average = -1;
4651 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4652 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4653 " valid RTT measurements cannot be retrieved");
4654 return 0;
4655 }
4656
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004657 uint32_t remoteSSRC;
4658 uint16_t RTT;
4659 uint16_t avgRTT;
4660 uint16_t maxRTT;
4661 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004662 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004663 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004664 if (remoteSSRC == 0)
4665 {
4666 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4667 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4668 " since no RTP packet has been received yet");
4669 }
4670
4671 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4672 // channel and SSRC. The SSRC is required to parse out the correct source
4673 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004674 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004675 {
4676 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4677 "GetRoundTripTimeSummary unable to retrieve RTT values"
4678 " from the RTCP layer");
4679 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4680 }
4681 else
4682 {
4683 delaysMs.min = minRTT;
4684 delaysMs.max = maxRTT;
4685 delaysMs.average = avgRTT;
4686 }
4687 return 0;
4688}
4689
4690int
4691Channel::GetNetworkStatistics(NetworkStatistics& stats)
4692{
4693 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4694 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004695 ACMNetworkStatistics acm_stats;
4696 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4697 if (return_value >= 0) {
4698 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4699 }
4700 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004701}
4702
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004703bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4704 int* playout_buffer_delay_ms) const {
4705 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004707 "Channel::GetDelayEstimate() no valid estimate.");
4708 return false;
4709 }
4710 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4711 _recPacketDelayMs;
4712 *playout_buffer_delay_ms = playout_delay_ms_;
4713 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4714 "Channel::GetDelayEstimate()");
4715 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004716}
4717
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004718int Channel::SetInitialPlayoutDelay(int delay_ms)
4719{
4720 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4721 "Channel::SetInitialPlayoutDelay()");
4722 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4723 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4724 {
4725 _engineStatisticsPtr->SetLastError(
4726 VE_INVALID_ARGUMENT, kTraceError,
4727 "SetInitialPlayoutDelay() invalid min delay");
4728 return -1;
4729 }
4730 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4731 {
4732 _engineStatisticsPtr->SetLastError(
4733 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4734 "SetInitialPlayoutDelay() failed to set min playout delay");
4735 return -1;
4736 }
4737 return 0;
4738}
4739
4740
niklase@google.com470e71d2011-07-07 08:21:25 +00004741int
4742Channel::SetMinimumPlayoutDelay(int delayMs)
4743{
4744 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4745 "Channel::SetMinimumPlayoutDelay()");
4746 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4747 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4748 {
4749 _engineStatisticsPtr->SetLastError(
4750 VE_INVALID_ARGUMENT, kTraceError,
4751 "SetMinimumPlayoutDelay() invalid min delay");
4752 return -1;
4753 }
4754 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4755 {
4756 _engineStatisticsPtr->SetLastError(
4757 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4758 "SetMinimumPlayoutDelay() failed to set min playout delay");
4759 return -1;
4760 }
4761 return 0;
4762}
4763
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004764void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4765 uint32_t playout_timestamp = 0;
4766
4767 if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1) {
4768 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4769 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4770 " timestamp from the ACM");
4771 _engineStatisticsPtr->SetLastError(
4772 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4773 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4774 return;
4775 }
4776
4777 uint16_t delay_ms = 0;
4778 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4779 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4780 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4781 " delay from the ADM");
4782 _engineStatisticsPtr->SetLastError(
4783 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4784 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4785 return;
4786 }
4787
4788 int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
4789 CodecInst current_recive_codec;
4790 if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
4791 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4792 playout_frequency = 8000;
4793 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4794 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004795 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004796 }
4797
4798 // Remove the playout delay.
4799 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4800
4801 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4802 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4803 playout_timestamp);
4804
4805 if (rtcp) {
4806 playout_timestamp_rtcp_ = playout_timestamp;
4807 } else {
4808 playout_timestamp_rtp_ = playout_timestamp;
4809 }
4810 playout_delay_ms_ = delay_ms;
4811}
4812
4813int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4814 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4815 "Channel::GetPlayoutTimestamp()");
4816 if (playout_timestamp_rtp_ == 0) {
4817 _engineStatisticsPtr->SetLastError(
4818 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4819 "GetPlayoutTimestamp() failed to retrieve timestamp");
4820 return -1;
4821 }
4822 timestamp = playout_timestamp_rtp_;
4823 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4824 VoEId(_instanceId,_channelId),
4825 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4826 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004827}
4828
4829int
4830Channel::SetInitTimestamp(unsigned int timestamp)
4831{
4832 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4833 "Channel::SetInitTimestamp()");
4834 if (_sending)
4835 {
4836 _engineStatisticsPtr->SetLastError(
4837 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4838 return -1;
4839 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004840 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004841 {
4842 _engineStatisticsPtr->SetLastError(
4843 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4844 "SetInitTimestamp() failed to set timestamp");
4845 return -1;
4846 }
4847 return 0;
4848}
4849
4850int
4851Channel::SetInitSequenceNumber(short sequenceNumber)
4852{
4853 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4854 "Channel::SetInitSequenceNumber()");
4855 if (_sending)
4856 {
4857 _engineStatisticsPtr->SetLastError(
4858 VE_SENDING, kTraceError,
4859 "SetInitSequenceNumber() already sending");
4860 return -1;
4861 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004862 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004863 {
4864 _engineStatisticsPtr->SetLastError(
4865 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4866 "SetInitSequenceNumber() failed to set sequence number");
4867 return -1;
4868 }
4869 return 0;
4870}
4871
4872int
4873Channel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
4874{
4875 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4876 "Channel::GetRtpRtcp()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004877 rtpRtcpModule = _rtpRtcpModule.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004878 return 0;
4879}
4880
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004881// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4882// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004883int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004884Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004885{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004886 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004887 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004888
4889 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004890 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004891
4892 if (_inputFilePlayerPtr == NULL)
4893 {
4894 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4895 VoEId(_instanceId, _channelId),
4896 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4897 " doesnt exist");
4898 return -1;
4899 }
4900
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004901 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004902 fileSamples,
4903 mixingFrequency) == -1)
4904 {
4905 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4906 VoEId(_instanceId, _channelId),
4907 "Channel::MixOrReplaceAudioWithFile() file mixing "
4908 "failed");
4909 return -1;
4910 }
4911 if (fileSamples == 0)
4912 {
4913 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4914 VoEId(_instanceId, _channelId),
4915 "Channel::MixOrReplaceAudioWithFile() file is ended");
4916 return 0;
4917 }
4918 }
4919
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004920 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004921
4922 if (_mixFileWithMicrophone)
4923 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004924 // Currently file stream is always mono.
4925 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004926 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004927 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004928 fileBuffer.get(),
4929 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004930 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004931 }
4932 else
4933 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004934 // Replace ACM audio with file.
4935 // Currently file stream is always mono.
4936 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004937 _audioFrame.UpdateFrame(_channelId,
4938 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004939 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004940 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004941 mixingFrequency,
4942 AudioFrame::kNormalSpeech,
4943 AudioFrame::kVadUnknown,
4944 1);
4945
4946 }
4947 return 0;
4948}
4949
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004950int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004951Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004952 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004953{
4954 assert(mixingFrequency <= 32000);
4955
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004956 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004957 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004958
4959 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004960 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004961
4962 if (_outputFilePlayerPtr == NULL)
4963 {
4964 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4965 VoEId(_instanceId, _channelId),
4966 "Channel::MixAudioWithFile() file mixing failed");
4967 return -1;
4968 }
4969
4970 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004971 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004972 fileSamples,
4973 mixingFrequency) == -1)
4974 {
4975 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4976 VoEId(_instanceId, _channelId),
4977 "Channel::MixAudioWithFile() file mixing failed");
4978 return -1;
4979 }
4980 }
4981
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004982 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004983 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004984 // Currently file stream is always mono.
4985 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004986 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004987 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004988 fileBuffer.get(),
4989 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004990 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004991 }
4992 else
4993 {
4994 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004995 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004996 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004997 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004998 return -1;
4999 }
5000
5001 return 0;
5002}
5003
5004int
5005Channel::InsertInbandDtmfTone()
5006{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005007 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00005008 if (_inbandDtmfQueue.PendingDtmf() &&
5009 !_inbandDtmfGenerator.IsAddingTone() &&
5010 _inbandDtmfGenerator.DelaySinceLastTone() >
5011 kMinTelephoneEventSeparationMs)
5012 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005013 int8_t eventCode(0);
5014 uint16_t lengthMs(0);
5015 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005016
5017 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
5018 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
5019 if (_playInbandDtmfEvent)
5020 {
5021 // Add tone to output mixer using a reduced length to minimize
5022 // risk of echo.
5023 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
5024 attenuationDb);
5025 }
5026 }
5027
5028 if (_inbandDtmfGenerator.IsAddingTone())
5029 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005030 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005031 _inbandDtmfGenerator.GetSampleRate(frequency);
5032
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005033 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005034 {
5035 // Update sample rate of Dtmf tone since the mixing frequency
5036 // has changed.
5037 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005038 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005039 // Reset the tone to be added taking the new sample rate into
5040 // account.
5041 _inbandDtmfGenerator.ResetTone();
5042 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005043
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005044 int16_t toneBuffer[320];
5045 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005046 // Get 10ms tone segment and set time since last tone to zero
5047 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5048 {
5049 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5050 VoEId(_instanceId, _channelId),
5051 "Channel::EncodeAndSend() inserting Dtmf failed");
5052 return -1;
5053 }
5054
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005055 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005056 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005057 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005058 sample++)
5059 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005060 for (int channel = 0;
5061 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005062 channel++)
5063 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005064 const int index = sample * _audioFrame.num_channels_ + channel;
5065 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005066 }
5067 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005068
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005069 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005070 } else
5071 {
5072 // Add 10ms to "delay-since-last-tone" counter
5073 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5074 }
5075 return 0;
5076}
5077
niklase@google.com470e71d2011-07-07 08:21:25 +00005078void
5079Channel::ResetDeadOrAliveCounters()
5080{
5081 _countDeadDetections = 0;
5082 _countAliveDetections = 0;
5083}
5084
5085void
5086Channel::UpdateDeadOrAliveCounters(bool alive)
5087{
5088 if (alive)
5089 _countAliveDetections++;
5090 else
5091 _countDeadDetections++;
5092}
5093
5094int
5095Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5096{
5097 bool enabled;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005098 uint8_t timeSec;
niklase@google.com470e71d2011-07-07 08:21:25 +00005099
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005100 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00005101 if (!enabled)
5102 return (-1);
5103
5104 countDead = static_cast<int> (_countDeadDetections);
5105 countAlive = static_cast<int> (_countAliveDetections);
5106 return 0;
5107}
5108
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005109int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005110Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5111{
5112 if (_transportPtr == NULL)
5113 {
5114 return -1;
5115 }
5116 if (!RTCP)
5117 {
5118 return _transportPtr->SendPacket(_channelId, data, len);
5119 }
5120 else
5121 {
5122 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5123 }
5124}
5125
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005126// Called for incoming RTP packets after successful RTP header parsing.
5127void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5128 uint16_t sequence_number) {
5129 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5130 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5131 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005132
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005133 // Get frequency of last received payload
5134 int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005135
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005136 CodecInst current_receive_codec;
5137 if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
5138 return;
5139 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005140
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005141 // Update the least required delay.
5142 least_required_delay_ms_ = _audioCodingModule.LeastRequiredDelayMs();
5143
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005144 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5145 // Even though the actual sampling rate for G.722 audio is
5146 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5147 // 8,000 Hz because that value was erroneously assigned in
5148 // RFC 1890 and must remain unchanged for backward compatibility.
5149 rtp_receive_frequency = 8000;
5150 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5151 // We are resampling Opus internally to 32,000 Hz until all our
5152 // DSP routines can operate at 48,000 Hz, but the RTP clock
5153 // rate for the Opus payload format is standardized to 48,000 Hz,
5154 // because that is the maximum supported decoding sampling rate.
5155 rtp_receive_frequency = 48000;
5156 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005157
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005158 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5159 // packet.
5160 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5161 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005162
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005163 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5164 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005165
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005166 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005167
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005168 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5169 timestamp_diff_ms = 0;
5170 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005171
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005172 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005173
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005174 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5175 _recPacketDelayMs = packet_delay_ms;
5176 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005177
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005178 if (_average_jitter_buffer_delay_us == 0) {
5179 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5180 return;
5181 }
5182
5183 // Filter average delay value using exponential filter (alpha is
5184 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5185 // risk of rounding error) and compensate for it in GetDelayEstimate()
5186 // later.
5187 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5188 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005189}
5190
5191void
5192Channel::RegisterReceiveCodecsToRTPModule()
5193{
5194 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5195 "Channel::RegisterReceiveCodecsToRTPModule()");
5196
5197
5198 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005199 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005200
5201 for (int idx = 0; idx < nSupportedCodecs; idx++)
5202 {
5203 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005204 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005205 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005206 {
5207 WEBRTC_TRACE(
5208 kTraceWarning,
5209 kTraceVoice,
5210 VoEId(_instanceId, _channelId),
5211 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5212 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5213 codec.plname, codec.pltype, codec.plfreq,
5214 codec.channels, codec.rate);
5215 }
5216 else
5217 {
5218 WEBRTC_TRACE(
5219 kTraceInfo,
5220 kTraceVoice,
5221 VoEId(_instanceId, _channelId),
5222 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005223 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005224 "receiver",
5225 codec.plname, codec.pltype, codec.plfreq,
5226 codec.channels, codec.rate);
5227 }
5228 }
5229}
5230
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005231int Channel::ApmProcessRx(AudioFrame& frame) {
5232 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5233 // Register the (possibly new) frame parameters.
5234 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005235 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005236 }
5237 if (audioproc->set_num_channels(frame.num_channels_,
5238 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005239 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005240 }
5241 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005242 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005243 }
5244 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005245}
5246
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005247int Channel::SetSecondarySendCodec(const CodecInst& codec,
5248 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005249 // Sanity check for payload type.
5250 if (red_payload_type < 0 || red_payload_type > 127) {
5251 _engineStatisticsPtr->SetLastError(
5252 VE_PLTYPE_ERROR, kTraceError,
5253 "SetRedPayloadType() invalid RED payload type");
5254 return -1;
5255 }
5256
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005257 if (SetRedPayloadType(red_payload_type) < 0) {
5258 _engineStatisticsPtr->SetLastError(
5259 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5260 "SetSecondarySendCodec() Failed to register RED ACM");
5261 return -1;
5262 }
5263 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5264 _engineStatisticsPtr->SetLastError(
5265 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5266 "SetSecondarySendCodec() Failed to register secondary send codec in "
5267 "ACM");
5268 return -1;
5269 }
5270
5271 return 0;
5272}
5273
5274void Channel::RemoveSecondarySendCodec() {
5275 _audioCodingModule.UnregisterSecondarySendCodec();
5276}
5277
5278int Channel::GetSecondarySendCodec(CodecInst* codec) {
5279 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5280 _engineStatisticsPtr->SetLastError(
5281 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5282 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5283 return -1;
5284 }
5285 return 0;
5286}
5287
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005288// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005289int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005290 CodecInst codec;
5291 bool found_red = false;
5292
5293 // Get default RED settings from the ACM database
5294 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5295 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005296 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005297 if (!STR_CASE_CMP(codec.plname, "RED")) {
5298 found_red = true;
5299 break;
5300 }
5301 }
5302
5303 if (!found_red) {
5304 _engineStatisticsPtr->SetLastError(
5305 VE_CODEC_ERROR, kTraceError,
5306 "SetRedPayloadType() RED is not supported");
5307 return -1;
5308 }
5309
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005310 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005311 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5312 _engineStatisticsPtr->SetLastError(
5313 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5314 "SetRedPayloadType() RED registration in ACM module failed");
5315 return -1;
5316 }
5317
5318 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5319 _engineStatisticsPtr->SetLastError(
5320 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5321 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5322 return -1;
5323 }
5324 return 0;
5325}
5326
niklase@google.com470e71d2011-07-07 08:21:25 +00005327} // namespace voe
niklase@google.com470e71d2011-07-07 08:21:25 +00005328} // namespace webrtc