blob: d6629029bc50f53544bf1ce53eaa5d1c0abd07f5 [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
niklase@google.com470e71d2011-07-07 08:21:25 +000097Channel::OnRxVadDetected(const int vadDecision)
98{
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.org6141e132013-04-09 10:09:10 +0000335Channel::OnPlayTelephoneEvent(const int32_t id,
336 const uint8_t event,
337 const uint16_t lengthMs,
338 const 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.org6141e132013-04-09 10:09:10 +0000359Channel::OnIncomingSSRCChanged(const int32_t id,
360 const 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.org6141e132013-04-09 10:09:10 +0000385void Channel::OnIncomingCSRCChanged(const int32_t id,
386 const uint32_t CSRC,
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 const bool added)
388{
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.org6141e132013-04-09 10:09:10 +0000408Channel::OnApplicationDataReceived(const int32_t id,
409 const uint8_t subType,
410 const uint32_t name,
411 const uint16_t length,
412 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.org6141e132013-04-09 10:09:10 +0000439 const int32_t id,
440 const int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000441 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
xians@google.com0b0665a2011-08-08 08:18:44 +0000442 const int frequency,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000443 const uint8_t channels,
444 const 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.org6141e132013-04-09 10:09:10 +0000480Channel::OnPacketTimeout(const 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.org6141e132013-04-09 10:09:10 +0000507Channel::OnReceivedPacket(const int32_t id,
niklase@google.com470e71d2011-07-07 08:21:25 +0000508 const RtpRtcpPacketType packetType)
509{
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.org6141e132013-04-09 10:09:10 +0000539Channel::OnPeriodicDeadOrAlive(const int32_t id,
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 const RTPAliveType alive)
541{
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,
593 const 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
628 // Update the packet delay
629 UpdatePacketDelay(rtpHeader->header.timestamp,
630 rtpHeader->header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 return 0;
632}
633
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000634int32_t Channel::GetAudioFrame(const int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000635{
636 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
637 "Channel::GetAudioFrame(id=%d)", id);
638
639 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000640 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000641 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 {
643 WEBRTC_TRACE(kTraceError, kTraceVoice,
644 VoEId(_instanceId,_channelId),
645 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000646 // In all likelihood, the audio in this frame is garbage. We return an
647 // error so that the audio mixer module doesn't add it to the mix. As
648 // a result, it won't be played out and the actions skipped here are
649 // irrelevant.
650 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 }
652
653 if (_RxVadDetection)
654 {
655 UpdateRxVadDetection(audioFrame);
656 }
657
658 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000659 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000661 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000662
663 // Perform far-end AudioProcessing module processing on the received signal
664 if (_rxApmIsEnabled)
665 {
666 ApmProcessRx(audioFrame);
667 }
668
669 // Output volume scaling
670 if (_outputGain < 0.99f || _outputGain > 1.01f)
671 {
672 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
673 }
674
675 // Scale left and/or right channel(s) if stereo and master balance is
676 // active
677
678 if (_panLeft != 1.0f || _panRight != 1.0f)
679 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000680 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 {
682 // Emulate stereo mode since panning is active.
683 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000684 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 }
686 // For true stereo mode (when we are receiving a stereo signal), no
687 // action is needed.
688
689 // Do the panning operation (the audio frame contains stereo at this
690 // stage)
691 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
692 }
693
694 // Mix decoded PCM output with file if file mixing is enabled
695 if (_outputFilePlaying)
696 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000697 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
699
700 // Place channel in on-hold state (~muted) if on-hold is activated
701 if (_outputIsOnHold)
702 {
703 AudioFrameOperations::Mute(audioFrame);
704 }
705
706 // External media
707 if (_outputExternalMedia)
708 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000709 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000710 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 if (_outputExternalMediaCallbackPtr)
712 {
713 _outputExternalMediaCallbackPtr->Process(
714 _channelId,
715 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000716 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000717 audioFrame.samples_per_channel_,
718 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000719 isStereo);
720 }
721 }
722
723 // Record playout if enabled
724 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000725 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726
727 if (_outputFileRecording && _outputFileRecorderPtr)
728 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000729 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 }
731 }
732
733 // Measure audio level (0-9)
734 _outputAudioLevel.ComputeLevel(audioFrame);
735
736 return 0;
737}
738
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000739int32_t
740Channel::NeededFrequency(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000741{
742 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
743 "Channel::NeededFrequency(id=%d)", id);
744
745 int highestNeeded = 0;
746
747 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000748 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000749
750 // Return the bigger of playout and receive frequency in the ACM.
751 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
752 {
753 highestNeeded = _audioCodingModule.PlayoutFrequency();
754 }
755 else
756 {
757 highestNeeded = receiveFrequency;
758 }
759
760 // Special case, if we're playing a file on the playout side
761 // we take that frequency into consideration as well
762 // This is not needed on sending side, since the codec will
763 // limit the spectrum anyway.
764 if (_outputFilePlaying)
765 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000766 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 if (_outputFilePlayerPtr && _outputFilePlaying)
768 {
769 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
770 {
771 highestNeeded=_outputFilePlayerPtr->Frequency();
772 }
773 }
774 }
775
776 return(highestNeeded);
777}
778
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000779int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000780Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000781 const int32_t channelId,
782 const uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000783{
784 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
785 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
786 channelId, instanceId);
787
788 channel = new Channel(channelId, instanceId);
789 if (channel == NULL)
790 {
791 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
792 VoEId(instanceId,channelId),
793 "Channel::CreateChannel() unable to allocate memory for"
794 " channel");
795 return -1;
796 }
797 return 0;
798}
799
800void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000801Channel::PlayNotification(const int32_t id, const uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000802{
803 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
804 "Channel::PlayNotification(id=%d, durationMs=%d)",
805 id, durationMs);
806
807 // Not implement yet
808}
809
810void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000811Channel::RecordNotification(const int32_t id, const uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000812{
813 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
814 "Channel::RecordNotification(id=%d, durationMs=%d)",
815 id, durationMs);
816
817 // Not implement yet
818}
819
820void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000821Channel::PlayFileEnded(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000822{
823 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
824 "Channel::PlayFileEnded(id=%d)", id);
825
826 if (id == _inputFilePlayerId)
827 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000828 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000829
830 _inputFilePlaying = false;
831 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
832 VoEId(_instanceId,_channelId),
833 "Channel::PlayFileEnded() => input file player module is"
834 " shutdown");
835 }
836 else if (id == _outputFilePlayerId)
837 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000838 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000839
840 _outputFilePlaying = false;
841 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
842 VoEId(_instanceId,_channelId),
843 "Channel::PlayFileEnded() => output file player module is"
844 " shutdown");
845 }
846}
847
848void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000849Channel::RecordFileEnded(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000850{
851 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
852 "Channel::RecordFileEnded(id=%d)", id);
853
854 assert(id == _outputFileRecorderId);
855
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000856 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000857
858 _outputFileRecording = false;
859 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
860 VoEId(_instanceId,_channelId),
861 "Channel::RecordFileEnded() => output file recorder module is"
862 " shutdown");
863}
864
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000865Channel::Channel(const int32_t channelId,
866 const uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
868 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000869 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000870 _channelId(channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000871 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000872 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 _rtpDumpIn(*RtpDump::CreateRtpDump()),
874 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 _inputFilePlayerPtr(NULL),
878 _outputFilePlayerPtr(NULL),
879 _outputFileRecorderPtr(NULL),
880 // Avoid conflict with other channels by adding 1024 - 1026,
881 // won't use as much as 1024 channels.
882 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
883 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
884 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
885 _inputFilePlaying(false),
886 _outputFilePlaying(false),
887 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000888 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
889 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000890 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000891 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 _inputExternalMediaCallbackPtr(NULL),
893 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000894 _encryptionRTPBufferPtr(NULL),
895 _decryptionRTPBufferPtr(NULL),
896 _encryptionRTCPBufferPtr(NULL),
897 _decryptionRTCPBufferPtr(NULL),
898 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
899 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000900 playout_timestamp_rtp_(0),
901 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000902 _numberOfDiscardedPackets(0),
903 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000904 _outputMixerPtr(NULL),
905 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000906 _moduleProcessThreadPtr(NULL),
907 _audioDeviceModulePtr(NULL),
908 _voiceEngineObserverPtr(NULL),
909 _callbackCritSectPtr(NULL),
910 _transportPtr(NULL),
911 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000912 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000913 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000914 _rxVadObserverPtr(NULL),
915 _oldVadDecision(-1),
916 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 _rtpObserverPtr(NULL),
918 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000919 _outputIsOnHold(false),
920 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000921 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000922 _inputIsOnHold(false),
923 _playing(false),
924 _sending(false),
925 _receiving(false),
926 _mixFileWithMicrophone(false),
927 _rtpObserver(false),
928 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 _mute(false),
930 _panLeft(1.0f),
931 _panRight(1.0f),
932 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000933 _encrypting(false),
934 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 _playOutbandDtmfEvent(false),
936 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000937 _extraPayloadType(0),
938 _insertExtraRTPPacket(false),
939 _extraMarkerBit(false),
940 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000941 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000943 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 _rtpPacketTimedOut(false),
945 _rtpPacketTimeOutIsEnabled(false),
946 _rtpTimeOutSeconds(0),
947 _connectionObserver(false),
948 _connectionObserverPtr(NULL),
949 _countAliveDetections(0),
950 _countDeadDetections(0),
951 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000952 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 _previousTimestamp(0),
954 _recPacketDelayMs(20),
955 _RxVadDetection(false),
956 _rxApmIsEnabled(false),
957 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000958 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000959{
960 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
961 "Channel::Channel() - ctor");
962 _inbandDtmfQueue.ResetDtmf();
963 _inbandDtmfGenerator.Init();
964 _outputAudioLevel.Clear();
965
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000966 RtpRtcp::Configuration configuration;
967 configuration.id = VoEModuleId(instanceId, channelId);
968 configuration.audio = true;
969 configuration.incoming_data = this;
970 configuration.incoming_messages = this;
971 configuration.outgoing_transport = this;
972 configuration.rtcp_feedback = this;
973 configuration.audio_messages = this;
974
975 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
976
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 // Create far end AudioProcessing Module
978 _rxAudioProcessingModulePtr = AudioProcessing::Create(
979 VoEModuleId(instanceId, channelId));
980}
981
982Channel::~Channel()
983{
984 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
985 "Channel::~Channel() - dtor");
986
987 if (_outputExternalMedia)
988 {
989 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
990 }
991 if (_inputExternalMedia)
992 {
993 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
994 }
995 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 StopPlayout();
997
998 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000999 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 if (_inputFilePlayerPtr)
1001 {
1002 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1003 _inputFilePlayerPtr->StopPlayingFile();
1004 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1005 _inputFilePlayerPtr = NULL;
1006 }
1007 if (_outputFilePlayerPtr)
1008 {
1009 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1010 _outputFilePlayerPtr->StopPlayingFile();
1011 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1012 _outputFilePlayerPtr = NULL;
1013 }
1014 if (_outputFileRecorderPtr)
1015 {
1016 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1017 _outputFileRecorderPtr->StopRecording();
1018 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1019 _outputFileRecorderPtr = NULL;
1020 }
1021 }
1022
1023 // The order to safely shutdown modules in a channel is:
1024 // 1. De-register callbacks in modules
1025 // 2. De-register modules in process thread
1026 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1028 {
1029 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1030 VoEId(_instanceId,_channelId),
1031 "~Channel() failed to de-register transport callback"
1032 " (Audio coding module)");
1033 }
1034 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1035 {
1036 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1037 VoEId(_instanceId,_channelId),
1038 "~Channel() failed to de-register VAD callback"
1039 " (Audio coding module)");
1040 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001042 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
1044 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1045 VoEId(_instanceId,_channelId),
1046 "~Channel() failed to deregister RTP/RTCP module");
1047 }
1048
1049 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 if (_rxAudioProcessingModulePtr != NULL)
1052 {
1053 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1054 _rxAudioProcessingModulePtr = NULL;
1055 }
1056
1057 // End of modules shutdown
1058
1059 // Delete other objects
1060 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1061 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1062 delete [] _encryptionRTPBufferPtr;
1063 delete [] _decryptionRTPBufferPtr;
1064 delete [] _encryptionRTCPBufferPtr;
1065 delete [] _decryptionRTCPBufferPtr;
1066 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 delete &_fileCritSect;
1068}
1069
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001070int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001071Channel::Init()
1072{
1073 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1074 "Channel::Init()");
1075
1076 // --- Initial sanity
1077
1078 if ((_engineStatisticsPtr == NULL) ||
1079 (_moduleProcessThreadPtr == NULL))
1080 {
1081 WEBRTC_TRACE(kTraceError, kTraceVoice,
1082 VoEId(_instanceId,_channelId),
1083 "Channel::Init() must call SetEngineInformation() first");
1084 return -1;
1085 }
1086
1087 // --- Add modules to process thread (for periodic schedulation)
1088
1089 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001090 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 if (processThreadFail)
1093 {
1094 _engineStatisticsPtr->SetLastError(
1095 VE_CANNOT_INIT_CHANNEL, kTraceError,
1096 "Channel::Init() modules not registered");
1097 return -1;
1098 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001099 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001100
1101 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1102#ifdef WEBRTC_CODEC_AVT
1103 // out-of-band Dtmf tones are played out by default
1104 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1105#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 (_audioCodingModule.InitializeSender() == -1))
1107 {
1108 _engineStatisticsPtr->SetLastError(
1109 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1110 "Channel::Init() unable to initialize the ACM - 1");
1111 return -1;
1112 }
1113
1114 // --- RTP/RTCP module initialization
1115
1116 // Ensure that RTCP is enabled by default for the created channel.
1117 // Note that, the module will keep generating RTCP until it is explicitly
1118 // disabled by the user.
1119 // After StopListen (when no sockets exists), RTCP packets will no longer
1120 // be transmitted since the Transport object will then be invalid.
1121
1122 const bool rtpRtcpFail =
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001123 ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 // RTCP is enabled by default
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001125 (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
niklase@google.com470e71d2011-07-07 08:21:25 +00001126 if (rtpRtcpFail)
1127 {
1128 _engineStatisticsPtr->SetLastError(
1129 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1130 "Channel::Init() RTP/RTCP module not initialized");
1131 return -1;
1132 }
1133
1134 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1137 (_audioCodingModule.RegisterVADCallback(this) == -1);
1138
1139 if (fail)
1140 {
1141 _engineStatisticsPtr->SetLastError(
1142 VE_CANNOT_INIT_CHANNEL, kTraceError,
1143 "Channel::Init() callbacks not registered");
1144 return -1;
1145 }
1146
1147 // --- Register all supported codecs to the receiving side of the
1148 // RTP/RTCP module
1149
1150 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001151 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001152
1153 for (int idx = 0; idx < nSupportedCodecs; idx++)
1154 {
1155 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001156 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001157 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 {
1159 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1160 VoEId(_instanceId,_channelId),
1161 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1162 "to RTP/RTCP receiver",
1163 codec.plname, codec.pltype, codec.plfreq,
1164 codec.channels, codec.rate);
1165 }
1166 else
1167 {
1168 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1169 VoEId(_instanceId,_channelId),
1170 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1171 "the RTP/RTCP receiver",
1172 codec.plname, codec.pltype, codec.plfreq,
1173 codec.channels, codec.rate);
1174 }
1175
1176 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001177 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 {
1179 SetSendCodec(codec);
1180 }
1181
1182 // Register default PT for outband 'telephone-event'
1183 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1184 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001185 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1187 {
1188 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1189 VoEId(_instanceId,_channelId),
1190 "Channel::Init() failed to register outband "
1191 "'telephone-event' (%d/%d) correctly",
1192 codec.pltype, codec.plfreq);
1193 }
1194 }
1195
1196 if (!STR_CASE_CMP(codec.plname, "CN"))
1197 {
1198 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1199 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001200 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 {
1202 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1203 VoEId(_instanceId,_channelId),
1204 "Channel::Init() failed to register CN (%d/%d) "
1205 "correctly - 1",
1206 codec.pltype, codec.plfreq);
1207 }
1208 }
1209#ifdef WEBRTC_CODEC_RED
1210 // Register RED to the receiving side of the ACM.
1211 // We will not receive an OnInitializeDecoder() callback for RED.
1212 if (!STR_CASE_CMP(codec.plname, "RED"))
1213 {
1214 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1215 {
1216 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1217 VoEId(_instanceId,_channelId),
1218 "Channel::Init() failed to register RED (%d/%d) "
1219 "correctly",
1220 codec.pltype, codec.plfreq);
1221 }
1222 }
1223#endif
1224 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001225
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 // Initialize the far end AP module
1227 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1228 // changed at the first receiving audio.
1229 if (_rxAudioProcessingModulePtr == NULL)
1230 {
1231 _engineStatisticsPtr->SetLastError(
1232 VE_NO_MEMORY, kTraceCritical,
1233 "Channel::Init() failed to create the far-end AudioProcessing"
1234 " module");
1235 return -1;
1236 }
1237
niklase@google.com470e71d2011-07-07 08:21:25 +00001238 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1239 {
1240 _engineStatisticsPtr->SetLastError(
1241 VE_APM_ERROR, kTraceWarning,
1242 "Channel::Init() failed to set the sample rate to 8K for"
1243 " far-end AP module");
1244 }
1245
1246 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1247 {
1248 _engineStatisticsPtr->SetLastError(
1249 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001250 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001251 }
1252
1253 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1254 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1255 {
1256 _engineStatisticsPtr->SetLastError(
1257 VE_APM_ERROR, kTraceWarning,
1258 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001259 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 }
1261
1262 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1263 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1264 {
1265 _engineStatisticsPtr->SetLastError(
1266 VE_APM_ERROR, kTraceWarning,
1267 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001268 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 }
1270 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1271 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1272 {
1273 _engineStatisticsPtr->SetLastError(
1274 VE_APM_ERROR, kTraceWarning,
1275 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001276 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 }
1278
1279 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1280 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1281 {
1282 _engineStatisticsPtr->SetLastError(
1283 VE_APM_ERROR, kTraceWarning,
1284 "Init() failed to set AGC mode for far-end AP module");
1285 }
1286 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1287 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1288 {
1289 _engineStatisticsPtr->SetLastError(
1290 VE_APM_ERROR, kTraceWarning,
1291 "Init() failed to set AGC state for far-end AP module");
1292 }
1293
1294 return 0;
1295}
1296
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001297int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001298Channel::SetEngineInformation(Statistics& engineStatistics,
1299 OutputMixer& outputMixer,
1300 voe::TransmitMixer& transmitMixer,
1301 ProcessThread& moduleProcessThread,
1302 AudioDeviceModule& audioDeviceModule,
1303 VoiceEngineObserver* voiceEngineObserver,
1304 CriticalSectionWrapper* callbackCritSect)
1305{
1306 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1307 "Channel::SetEngineInformation()");
1308 _engineStatisticsPtr = &engineStatistics;
1309 _outputMixerPtr = &outputMixer;
1310 _transmitMixerPtr = &transmitMixer,
1311 _moduleProcessThreadPtr = &moduleProcessThread;
1312 _audioDeviceModulePtr = &audioDeviceModule;
1313 _voiceEngineObserverPtr = voiceEngineObserver;
1314 _callbackCritSectPtr = callbackCritSect;
1315 return 0;
1316}
1317
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001318int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001319Channel::UpdateLocalTimeStamp()
1320{
1321
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001322 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001323 return 0;
1324}
1325
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001326int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001327Channel::StartPlayout()
1328{
1329 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1330 "Channel::StartPlayout()");
1331 if (_playing)
1332 {
1333 return 0;
1334 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001335
1336 if (!_externalMixing) {
1337 // Add participant as candidates for mixing.
1338 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1339 {
1340 _engineStatisticsPtr->SetLastError(
1341 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1342 "StartPlayout() failed to add participant to mixer");
1343 return -1;
1344 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001345 }
1346
1347 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001348
1349 if (RegisterFilePlayingToMixer() != 0)
1350 return -1;
1351
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 return 0;
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::StopPlayout()
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::StopPlayout()");
1360 if (!_playing)
1361 {
1362 return 0;
1363 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001364
1365 if (!_externalMixing) {
1366 // Remove participant as candidates for mixing
1367 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1368 {
1369 _engineStatisticsPtr->SetLastError(
1370 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1371 "StopPlayout() failed to remove participant from mixer");
1372 return -1;
1373 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 }
1375
1376 _playing = false;
1377 _outputAudioLevel.Clear();
1378
1379 return 0;
1380}
1381
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001382int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001383Channel::StartSend()
1384{
1385 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1386 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001387 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001388 // A lock is needed because |_sending| can be accessed or modified by
1389 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001390 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001391
1392 if (_sending)
1393 {
1394 return 0;
1395 }
1396 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001397 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001398
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001399 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001400 {
1401 _engineStatisticsPtr->SetLastError(
1402 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1403 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001404 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001405 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 return -1;
1407 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001408
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 return 0;
1410}
1411
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001412int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001413Channel::StopSend()
1414{
1415 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1416 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001417 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001418 // A lock is needed because |_sending| can be accessed or modified by
1419 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001420 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001421
1422 if (!_sending)
1423 {
1424 return 0;
1425 }
1426 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001428
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 // Reset sending SSRC and sequence number and triggers direct transmission
1430 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001431 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1432 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 {
1434 _engineStatisticsPtr->SetLastError(
1435 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1436 "StartSend() RTP/RTCP failed to stop sending");
1437 }
1438
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 return 0;
1440}
1441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001442int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001443Channel::StartReceiving()
1444{
1445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446 "Channel::StartReceiving()");
1447 if (_receiving)
1448 {
1449 return 0;
1450 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001451 _receiving = true;
1452 _numberOfDiscardedPackets = 0;
1453 return 0;
1454}
1455
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001456int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001457Channel::StopReceiving()
1458{
1459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1460 "Channel::StopReceiving()");
1461 if (!_receiving)
1462 {
1463 return 0;
1464 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001465
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001466 // Recover DTMF detection status.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001467 int32_t ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001468 if (ret != 0) {
1469 _engineStatisticsPtr->SetLastError(
1470 VE_INVALID_OPERATION, kTraceWarning,
1471 "StopReceiving() failed to restore telephone-event status.");
1472 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 RegisterReceiveCodecsToRTPModule();
1474 _receiving = false;
1475 return 0;
1476}
1477
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001478int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001479Channel::SetNetEQPlayoutMode(NetEqModes mode)
1480{
1481 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1482 "Channel::SetNetEQPlayoutMode()");
1483 AudioPlayoutMode playoutMode(voice);
1484 switch (mode)
1485 {
1486 case kNetEqDefault:
1487 playoutMode = voice;
1488 break;
1489 case kNetEqStreaming:
1490 playoutMode = streaming;
1491 break;
1492 case kNetEqFax:
1493 playoutMode = fax;
1494 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001495 case kNetEqOff:
1496 playoutMode = off;
1497 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001498 }
1499 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1500 {
1501 _engineStatisticsPtr->SetLastError(
1502 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1503 "SetNetEQPlayoutMode() failed to set playout mode");
1504 return -1;
1505 }
1506 return 0;
1507}
1508
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001509int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001510Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1511{
1512 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1513 switch (playoutMode)
1514 {
1515 case voice:
1516 mode = kNetEqDefault;
1517 break;
1518 case streaming:
1519 mode = kNetEqStreaming;
1520 break;
1521 case fax:
1522 mode = kNetEqFax;
1523 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001524 case off:
1525 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001526 }
1527 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1528 VoEId(_instanceId,_channelId),
1529 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1530 return 0;
1531}
1532
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001533int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001534Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1535{
1536 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1537 "Channel::SetOnHoldStatus()");
1538 if (mode == kHoldSendAndPlay)
1539 {
1540 _outputIsOnHold = enable;
1541 _inputIsOnHold = enable;
1542 }
1543 else if (mode == kHoldPlayOnly)
1544 {
1545 _outputIsOnHold = enable;
1546 }
1547 if (mode == kHoldSendOnly)
1548 {
1549 _inputIsOnHold = enable;
1550 }
1551 return 0;
1552}
1553
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001554int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001555Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1556{
1557 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1558 "Channel::GetOnHoldStatus()");
1559 enabled = (_outputIsOnHold || _inputIsOnHold);
1560 if (_outputIsOnHold && _inputIsOnHold)
1561 {
1562 mode = kHoldSendAndPlay;
1563 }
1564 else if (_outputIsOnHold && !_inputIsOnHold)
1565 {
1566 mode = kHoldPlayOnly;
1567 }
1568 else if (!_outputIsOnHold && _inputIsOnHold)
1569 {
1570 mode = kHoldSendOnly;
1571 }
1572 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1573 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1574 enabled, mode);
1575 return 0;
1576}
1577
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001578int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001579Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1580{
1581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1582 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001583 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001584
1585 if (_voiceEngineObserverPtr)
1586 {
1587 _engineStatisticsPtr->SetLastError(
1588 VE_INVALID_OPERATION, kTraceError,
1589 "RegisterVoiceEngineObserver() observer already enabled");
1590 return -1;
1591 }
1592 _voiceEngineObserverPtr = &observer;
1593 return 0;
1594}
1595
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001596int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001597Channel::DeRegisterVoiceEngineObserver()
1598{
1599 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1600 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001601 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001602
1603 if (!_voiceEngineObserverPtr)
1604 {
1605 _engineStatisticsPtr->SetLastError(
1606 VE_INVALID_OPERATION, kTraceWarning,
1607 "DeRegisterVoiceEngineObserver() observer already disabled");
1608 return 0;
1609 }
1610 _voiceEngineObserverPtr = NULL;
1611 return 0;
1612}
1613
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001614int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001615Channel::GetSendCodec(CodecInst& codec)
1616{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001617 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001618}
1619
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001620int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001621Channel::GetRecCodec(CodecInst& codec)
1622{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001623 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001624}
1625
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001626int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001627Channel::SetSendCodec(const CodecInst& codec)
1628{
1629 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1630 "Channel::SetSendCodec()");
1631
1632 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1633 {
1634 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1635 "SetSendCodec() failed to register codec to ACM");
1636 return -1;
1637 }
1638
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001639 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001640 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001641 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1642 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001643 {
1644 WEBRTC_TRACE(
1645 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1646 "SetSendCodec() failed to register codec to"
1647 " RTP/RTCP module");
1648 return -1;
1649 }
1650 }
1651
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001652 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001653 {
1654 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1655 "SetSendCodec() failed to set audio packet size");
1656 return -1;
1657 }
1658
1659 return 0;
1660}
1661
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001662int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001663Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1664{
1665 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1666 "Channel::SetVADStatus(mode=%d)", mode);
1667 // To disable VAD, DTX must be disabled too
1668 disableDTX = ((enableVAD == false) ? true : disableDTX);
1669 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1670 {
1671 _engineStatisticsPtr->SetLastError(
1672 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1673 "SetVADStatus() failed to set VAD");
1674 return -1;
1675 }
1676 return 0;
1677}
1678
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001679int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001680Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1681{
1682 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1683 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001684 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001685 {
1686 _engineStatisticsPtr->SetLastError(
1687 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1688 "GetVADStatus() failed to get VAD status");
1689 return -1;
1690 }
1691 disabledDTX = !disabledDTX;
1692 return 0;
1693}
1694
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001695int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001696Channel::SetRecPayloadType(const CodecInst& codec)
1697{
1698 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1699 "Channel::SetRecPayloadType()");
1700
1701 if (_playing)
1702 {
1703 _engineStatisticsPtr->SetLastError(
1704 VE_ALREADY_PLAYING, kTraceError,
1705 "SetRecPayloadType() unable to set PT while playing");
1706 return -1;
1707 }
1708 if (_receiving)
1709 {
1710 _engineStatisticsPtr->SetLastError(
1711 VE_ALREADY_LISTENING, kTraceError,
1712 "SetRecPayloadType() unable to set PT while listening");
1713 return -1;
1714 }
1715
1716 if (codec.pltype == -1)
1717 {
1718 // De-register the selected codec (RTP/RTCP module and ACM)
1719
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001720 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001721 CodecInst rxCodec = codec;
1722
1723 // Get payload type for the given codec
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001724 _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001725 rxCodec.pltype = pltype;
1726
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001727 if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001728 {
1729 _engineStatisticsPtr->SetLastError(
1730 VE_RTP_RTCP_MODULE_ERROR,
1731 kTraceError,
1732 "SetRecPayloadType() RTP/RTCP-module deregistration "
1733 "failed");
1734 return -1;
1735 }
1736 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1737 {
1738 _engineStatisticsPtr->SetLastError(
1739 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1740 "SetRecPayloadType() ACM deregistration failed - 1");
1741 return -1;
1742 }
1743 return 0;
1744 }
1745
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001746 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001747 {
1748 // First attempt to register failed => de-register and try again
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001749 _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
1750 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001751 {
1752 _engineStatisticsPtr->SetLastError(
1753 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1754 "SetRecPayloadType() RTP/RTCP-module registration failed");
1755 return -1;
1756 }
1757 }
1758 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1759 {
1760 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1761 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1762 {
1763 _engineStatisticsPtr->SetLastError(
1764 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1765 "SetRecPayloadType() ACM registration failed - 1");
1766 return -1;
1767 }
1768 }
1769 return 0;
1770}
1771
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001772int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001773Channel::GetRecPayloadType(CodecInst& codec)
1774{
1775 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1776 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001777 int8_t payloadType(-1);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001778 if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001779 {
1780 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001781 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001782 "GetRecPayloadType() failed to retrieve RX payload type");
1783 return -1;
1784 }
1785 codec.pltype = payloadType;
1786 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1787 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1788 return 0;
1789}
1790
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001791int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001792Channel::SetAMREncFormat(AmrMode mode)
1793{
1794 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1795 "Channel::SetAMREncFormat()");
1796
1797 // ACM doesn't support AMR
1798 return -1;
1799}
1800
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001801int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001802Channel::SetAMRDecFormat(AmrMode mode)
1803{
1804 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1805 "Channel::SetAMRDecFormat()");
1806
1807 // ACM doesn't support AMR
1808 return -1;
1809}
1810
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001811int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001812Channel::SetAMRWbEncFormat(AmrMode mode)
1813{
1814 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1815 "Channel::SetAMRWbEncFormat()");
1816
1817 // ACM doesn't support AMR
1818 return -1;
1819
1820}
1821
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001822int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001823Channel::SetAMRWbDecFormat(AmrMode mode)
1824{
1825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1826 "Channel::SetAMRWbDecFormat()");
1827
1828 // ACM doesn't support AMR
1829 return -1;
1830}
1831
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001832int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001833Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1834{
1835 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1836 "Channel::SetSendCNPayloadType()");
1837
1838 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001839 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001840 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001841 if (frequency == kFreq32000Hz)
1842 samplingFreqHz = 32000;
1843 else if (frequency == kFreq16000Hz)
1844 samplingFreqHz = 16000;
1845
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001846 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001847 {
1848 _engineStatisticsPtr->SetLastError(
1849 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1850 "SetSendCNPayloadType() failed to retrieve default CN codec "
1851 "settings");
1852 return -1;
1853 }
1854
1855 // Modify the payload type (must be set to dynamic range)
1856 codec.pltype = type;
1857
1858 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1859 {
1860 _engineStatisticsPtr->SetLastError(
1861 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1862 "SetSendCNPayloadType() failed to register CN to ACM");
1863 return -1;
1864 }
1865
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001866 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001867 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001868 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1869 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001870 {
1871 _engineStatisticsPtr->SetLastError(
1872 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1873 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1874 "module");
1875 return -1;
1876 }
1877 }
1878 return 0;
1879}
1880
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001881int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001882Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1883{
1884 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1885 "Channel::SetISACInitTargetRate()");
1886
1887 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001888 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001889 {
1890 _engineStatisticsPtr->SetLastError(
1891 VE_CODEC_ERROR, kTraceError,
1892 "SetISACInitTargetRate() failed to retrieve send codec");
1893 return -1;
1894 }
1895 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1896 {
1897 // This API is only valid if iSAC is setup to run in channel-adaptive
1898 // mode.
1899 // We do not validate the adaptive mode here. It is done later in the
1900 // ConfigISACBandwidthEstimator() API.
1901 _engineStatisticsPtr->SetLastError(
1902 VE_CODEC_ERROR, kTraceError,
1903 "SetISACInitTargetRate() send codec is not iSAC");
1904 return -1;
1905 }
1906
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001907 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001908 if (16000 == sendCodec.plfreq)
1909 {
1910 // Note that 0 is a valid and corresponds to "use default
1911 if ((rateBps != 0 &&
1912 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1913 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1914 {
1915 _engineStatisticsPtr->SetLastError(
1916 VE_INVALID_ARGUMENT, kTraceError,
1917 "SetISACInitTargetRate() invalid target rate - 1");
1918 return -1;
1919 }
1920 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001921 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001922 }
1923 else if (32000 == sendCodec.plfreq)
1924 {
1925 if ((rateBps != 0 &&
1926 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1927 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1928 {
1929 _engineStatisticsPtr->SetLastError(
1930 VE_INVALID_ARGUMENT, kTraceError,
1931 "SetISACInitTargetRate() invalid target rate - 2");
1932 return -1;
1933 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001934 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 }
1936
1937 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1938 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1939 {
1940 _engineStatisticsPtr->SetLastError(
1941 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1942 "SetISACInitTargetRate() iSAC BWE config failed");
1943 return -1;
1944 }
1945
1946 return 0;
1947}
1948
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001949int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001950Channel::SetISACMaxRate(int rateBps)
1951{
1952 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1953 "Channel::SetISACMaxRate()");
1954
1955 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001956 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001957 {
1958 _engineStatisticsPtr->SetLastError(
1959 VE_CODEC_ERROR, kTraceError,
1960 "SetISACMaxRate() failed to retrieve send codec");
1961 return -1;
1962 }
1963 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1964 {
1965 // This API is only valid if iSAC is selected as sending codec.
1966 _engineStatisticsPtr->SetLastError(
1967 VE_CODEC_ERROR, kTraceError,
1968 "SetISACMaxRate() send codec is not iSAC");
1969 return -1;
1970 }
1971 if (16000 == sendCodec.plfreq)
1972 {
1973 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1974 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1975 {
1976 _engineStatisticsPtr->SetLastError(
1977 VE_INVALID_ARGUMENT, kTraceError,
1978 "SetISACMaxRate() invalid max rate - 1");
1979 return -1;
1980 }
1981 }
1982 else if (32000 == sendCodec.plfreq)
1983 {
1984 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1985 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1986 {
1987 _engineStatisticsPtr->SetLastError(
1988 VE_INVALID_ARGUMENT, kTraceError,
1989 "SetISACMaxRate() invalid max rate - 2");
1990 return -1;
1991 }
1992 }
1993 if (_sending)
1994 {
1995 _engineStatisticsPtr->SetLastError(
1996 VE_SENDING, kTraceError,
1997 "SetISACMaxRate() unable to set max rate while sending");
1998 return -1;
1999 }
2000
2001 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2002 // and non-adaptive mode)
2003 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2004 {
2005 _engineStatisticsPtr->SetLastError(
2006 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2007 "SetISACMaxRate() failed to set max rate");
2008 return -1;
2009 }
2010
2011 return 0;
2012}
2013
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002014int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002015Channel::SetISACMaxPayloadSize(int sizeBytes)
2016{
2017 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2018 "Channel::SetISACMaxPayloadSize()");
2019 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002020 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 {
2022 _engineStatisticsPtr->SetLastError(
2023 VE_CODEC_ERROR, kTraceError,
2024 "SetISACMaxPayloadSize() failed to retrieve send codec");
2025 return -1;
2026 }
2027 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2028 {
2029 _engineStatisticsPtr->SetLastError(
2030 VE_CODEC_ERROR, kTraceError,
2031 "SetISACMaxPayloadSize() send codec is not iSAC");
2032 return -1;
2033 }
2034 if (16000 == sendCodec.plfreq)
2035 {
2036 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2037 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2038 {
2039 _engineStatisticsPtr->SetLastError(
2040 VE_INVALID_ARGUMENT, kTraceError,
2041 "SetISACMaxPayloadSize() invalid max payload - 1");
2042 return -1;
2043 }
2044 }
2045 else if (32000 == sendCodec.plfreq)
2046 {
2047 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2048 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2049 {
2050 _engineStatisticsPtr->SetLastError(
2051 VE_INVALID_ARGUMENT, kTraceError,
2052 "SetISACMaxPayloadSize() invalid max payload - 2");
2053 return -1;
2054 }
2055 }
2056 if (_sending)
2057 {
2058 _engineStatisticsPtr->SetLastError(
2059 VE_SENDING, kTraceError,
2060 "SetISACMaxPayloadSize() unable to set max rate while sending");
2061 return -1;
2062 }
2063
2064 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2065 {
2066 _engineStatisticsPtr->SetLastError(
2067 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2068 "SetISACMaxPayloadSize() failed to set max payload size");
2069 return -1;
2070 }
2071 return 0;
2072}
2073
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002074int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002075{
2076 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2077 "Channel::RegisterExternalTransport()");
2078
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002079 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002080
niklase@google.com470e71d2011-07-07 08:21:25 +00002081 if (_externalTransport)
2082 {
2083 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2084 kTraceError,
2085 "RegisterExternalTransport() external transport already enabled");
2086 return -1;
2087 }
2088 _externalTransport = true;
2089 _transportPtr = &transport;
2090 return 0;
2091}
2092
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002093int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002094Channel::DeRegisterExternalTransport()
2095{
2096 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2097 "Channel::DeRegisterExternalTransport()");
2098
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002099 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002100
niklase@google.com470e71d2011-07-07 08:21:25 +00002101 if (!_transportPtr)
2102 {
2103 _engineStatisticsPtr->SetLastError(
2104 VE_INVALID_OPERATION, kTraceWarning,
2105 "DeRegisterExternalTransport() external transport already "
2106 "disabled");
2107 return 0;
2108 }
2109 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002110 _transportPtr = NULL;
2111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2112 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002113 return 0;
2114}
2115
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002116int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002117 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2118 "Channel::ReceivedRTPPacket()");
2119
2120 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002121 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002122
2123 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002124 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2125 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002126 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2127 VoEId(_instanceId,_channelId),
2128 "Channel::SendPacket() RTP dump to input file failed");
2129 }
2130
2131 // Deliver RTP packet to RTP/RTCP module for parsing
2132 // The packet will be pushed back to the channel thru the
2133 // OnReceivedPayloadData callback so we don't push it to the ACM here
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002134 if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
2135 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002136 _engineStatisticsPtr->SetLastError(
2137 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2138 "Channel::IncomingRTPPacket() RTP packet is invalid");
2139 }
2140 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002141}
2142
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002143int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002144 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2145 "Channel::ReceivedRTCPPacket()");
2146 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002147 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002148
2149 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002150 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2151 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002152 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2153 VoEId(_instanceId,_channelId),
2154 "Channel::SendPacket() RTCP dump to input file failed");
2155 }
2156
2157 // Deliver RTCP packet to RTP/RTCP module for parsing
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002158 if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
2159 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002160 _engineStatisticsPtr->SetLastError(
2161 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2162 "Channel::IncomingRTPPacket() RTCP 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
niklase@google.com470e71d2011-07-07 08:21:25 +00002168Channel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
2169{
2170 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2171 "Channel::SetPacketTimeoutNotification()");
2172 if (enable)
2173 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002174 const uint32_t RTPtimeoutMS = 1000*timeoutSeconds;
2175 const uint32_t RTCPtimeoutMS = 0;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002176 _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
niklase@google.com470e71d2011-07-07 08:21:25 +00002177 _rtpPacketTimeOutIsEnabled = true;
2178 _rtpTimeOutSeconds = timeoutSeconds;
2179 }
2180 else
2181 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002182 _rtpRtcpModule->SetPacketTimeout(0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002183 _rtpPacketTimeOutIsEnabled = false;
2184 _rtpTimeOutSeconds = 0;
2185 }
2186 return 0;
2187}
2188
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002189int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002190Channel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
2191{
2192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2193 "Channel::GetPacketTimeoutNotification()");
2194 enabled = _rtpPacketTimeOutIsEnabled;
2195 if (enabled)
2196 {
2197 timeoutSeconds = _rtpTimeOutSeconds;
2198 }
2199 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2200 "GetPacketTimeoutNotification() => enabled=%d,"
2201 " timeoutSeconds=%d",
2202 enabled, timeoutSeconds);
2203 return 0;
2204}
2205
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002206int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002207Channel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
2208{
2209 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2210 "Channel::RegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002211 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002212
2213 if (_connectionObserverPtr)
2214 {
2215 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
2216 "RegisterDeadOrAliveObserver() observer already enabled");
2217 return -1;
2218 }
2219
2220 _connectionObserverPtr = &observer;
2221 _connectionObserver = true;
2222
2223 return 0;
2224}
2225
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002226int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002227Channel::DeRegisterDeadOrAliveObserver()
2228{
2229 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2230 "Channel::DeRegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002231 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002232
2233 if (!_connectionObserverPtr)
2234 {
2235 _engineStatisticsPtr->SetLastError(
2236 VE_INVALID_OPERATION, kTraceWarning,
2237 "DeRegisterDeadOrAliveObserver() observer already disabled");
2238 return 0;
2239 }
2240
2241 _connectionObserver = false;
2242 _connectionObserverPtr = NULL;
2243
2244 return 0;
2245}
2246
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002247int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002248Channel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
2249{
2250 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2251 "Channel::SetPeriodicDeadOrAliveStatus()");
2252 if (!_connectionObserverPtr)
2253 {
2254 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
2255 "SetPeriodicDeadOrAliveStatus() connection observer has"
2256 " not been registered");
2257 }
2258 if (enable)
2259 {
2260 ResetDeadOrAliveCounters();
2261 }
2262 bool enabled(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002263 uint8_t currentSampleTimeSec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002264 // Store last state (will be used later if dead-or-alive is disabled).
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002265 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00002266 // Update the dead-or-alive state.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002267 if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002268 enable, (uint8_t)sampleTimeSeconds) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002269 {
2270 _engineStatisticsPtr->SetLastError(
2271 VE_RTP_RTCP_MODULE_ERROR,
2272 kTraceError,
2273 "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
2274 "status");
2275 return -1;
2276 }
2277 if (!enable)
2278 {
2279 // Restore last utilized sample time.
2280 // Without this, the sample time would always be reset to default
2281 // (2 sec), each time dead-or-alived was disabled without sample-time
2282 // parameter.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002283 _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
niklase@google.com470e71d2011-07-07 08:21:25 +00002284 currentSampleTimeSec);
2285 }
2286 return 0;
2287}
2288
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002289int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002290Channel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
2291{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002292 _rtpRtcpModule->PeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00002293 enabled,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002294 (uint8_t&)sampleTimeSeconds);
niklase@google.com470e71d2011-07-07 08:21:25 +00002295 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2296 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
2297 " sampleTimeSeconds=%d",
2298 enabled, sampleTimeSeconds);
2299 return 0;
2300}
2301
niklase@google.com470e71d2011-07-07 08:21:25 +00002302int Channel::StartPlayingFileLocally(const char* fileName,
2303 const bool loop,
2304 const FileFormats format,
2305 const int startPosition,
2306 const float volumeScaling,
2307 const int stopPosition,
2308 const CodecInst* codecInst)
2309{
2310 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2311 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2312 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2313 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2314 startPosition, stopPosition);
2315
2316 if (_outputFilePlaying)
2317 {
2318 _engineStatisticsPtr->SetLastError(
2319 VE_ALREADY_PLAYING, kTraceError,
2320 "StartPlayingFileLocally() is already playing");
2321 return -1;
2322 }
2323
niklase@google.com470e71d2011-07-07 08:21:25 +00002324 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002325 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002326
2327 if (_outputFilePlayerPtr)
2328 {
2329 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2330 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2331 _outputFilePlayerPtr = NULL;
2332 }
2333
2334 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2335 _outputFilePlayerId, (const FileFormats)format);
2336
2337 if (_outputFilePlayerPtr == NULL)
2338 {
2339 _engineStatisticsPtr->SetLastError(
2340 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002341 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002342 return -1;
2343 }
2344
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002345 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002346
2347 if (_outputFilePlayerPtr->StartPlayingFile(
2348 fileName,
2349 loop,
2350 startPosition,
2351 volumeScaling,
2352 notificationTime,
2353 stopPosition,
2354 (const CodecInst*)codecInst) != 0)
2355 {
2356 _engineStatisticsPtr->SetLastError(
2357 VE_BAD_FILE, kTraceError,
2358 "StartPlayingFile() failed to start file playout");
2359 _outputFilePlayerPtr->StopPlayingFile();
2360 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2361 _outputFilePlayerPtr = NULL;
2362 return -1;
2363 }
2364 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2365 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002366 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002367
2368 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002369 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002370
2371 return 0;
2372}
2373
2374int Channel::StartPlayingFileLocally(InStream* stream,
2375 const FileFormats format,
2376 const int startPosition,
2377 const float volumeScaling,
2378 const int stopPosition,
2379 const CodecInst* codecInst)
2380{
2381 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2382 "Channel::StartPlayingFileLocally(format=%d,"
2383 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2384 format, volumeScaling, startPosition, stopPosition);
2385
2386 if(stream == NULL)
2387 {
2388 _engineStatisticsPtr->SetLastError(
2389 VE_BAD_FILE, kTraceError,
2390 "StartPlayingFileLocally() NULL as input stream");
2391 return -1;
2392 }
2393
2394
2395 if (_outputFilePlaying)
2396 {
2397 _engineStatisticsPtr->SetLastError(
2398 VE_ALREADY_PLAYING, kTraceError,
2399 "StartPlayingFileLocally() is already playing");
2400 return -1;
2401 }
2402
niklase@google.com470e71d2011-07-07 08:21:25 +00002403 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002404 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002405
2406 // Destroy the old instance
2407 if (_outputFilePlayerPtr)
2408 {
2409 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2410 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2411 _outputFilePlayerPtr = NULL;
2412 }
2413
2414 // Create the instance
2415 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2416 _outputFilePlayerId,
2417 (const FileFormats)format);
2418
2419 if (_outputFilePlayerPtr == NULL)
2420 {
2421 _engineStatisticsPtr->SetLastError(
2422 VE_INVALID_ARGUMENT, kTraceError,
2423 "StartPlayingFileLocally() filePlayer format isnot correct");
2424 return -1;
2425 }
2426
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002427 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002428
2429 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2430 volumeScaling,
2431 notificationTime,
2432 stopPosition, codecInst) != 0)
2433 {
2434 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2435 "StartPlayingFile() failed to "
2436 "start file playout");
2437 _outputFilePlayerPtr->StopPlayingFile();
2438 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2439 _outputFilePlayerPtr = NULL;
2440 return -1;
2441 }
2442 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2443 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002444 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002445
2446 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002447 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002448
niklase@google.com470e71d2011-07-07 08:21:25 +00002449 return 0;
2450}
2451
2452int Channel::StopPlayingFileLocally()
2453{
2454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2455 "Channel::StopPlayingFileLocally()");
2456
2457 if (!_outputFilePlaying)
2458 {
2459 _engineStatisticsPtr->SetLastError(
2460 VE_INVALID_OPERATION, kTraceWarning,
2461 "StopPlayingFileLocally() isnot playing");
2462 return 0;
2463 }
2464
niklase@google.com470e71d2011-07-07 08:21:25 +00002465 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002466 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002467
2468 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2469 {
2470 _engineStatisticsPtr->SetLastError(
2471 VE_STOP_RECORDING_FAILED, kTraceError,
2472 "StopPlayingFile() could not stop playing");
2473 return -1;
2474 }
2475 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2476 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2477 _outputFilePlayerPtr = NULL;
2478 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002479 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002480 // _fileCritSect cannot be taken while calling
2481 // SetAnonymousMixibilityStatus. Refer to comments in
2482 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002483 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2484 {
2485 _engineStatisticsPtr->SetLastError(
2486 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002487 "StopPlayingFile() failed to stop participant from playing as"
2488 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002489 return -1;
2490 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002491
2492 return 0;
2493}
2494
2495int Channel::IsPlayingFileLocally() const
2496{
2497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2498 "Channel::IsPlayingFileLocally()");
2499
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002500 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002501}
2502
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002503int Channel::RegisterFilePlayingToMixer()
2504{
2505 // Return success for not registering for file playing to mixer if:
2506 // 1. playing file before playout is started on that channel.
2507 // 2. starting playout without file playing on that channel.
2508 if (!_playing || !_outputFilePlaying)
2509 {
2510 return 0;
2511 }
2512
2513 // |_fileCritSect| cannot be taken while calling
2514 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2515 // frames can be pulled by the mixer. Since the frames are generated from
2516 // the file, _fileCritSect will be taken. This would result in a deadlock.
2517 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2518 {
2519 CriticalSectionScoped cs(&_fileCritSect);
2520 _outputFilePlaying = false;
2521 _engineStatisticsPtr->SetLastError(
2522 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2523 "StartPlayingFile() failed to add participant as file to mixer");
2524 _outputFilePlayerPtr->StopPlayingFile();
2525 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2526 _outputFilePlayerPtr = NULL;
2527 return -1;
2528 }
2529
2530 return 0;
2531}
2532
niklase@google.com470e71d2011-07-07 08:21:25 +00002533int Channel::ScaleLocalFilePlayout(const float scale)
2534{
2535 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2536 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2537
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002538 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002539
2540 if (!_outputFilePlaying)
2541 {
2542 _engineStatisticsPtr->SetLastError(
2543 VE_INVALID_OPERATION, kTraceError,
2544 "ScaleLocalFilePlayout() isnot playing");
2545 return -1;
2546 }
2547 if ((_outputFilePlayerPtr == NULL) ||
2548 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2549 {
2550 _engineStatisticsPtr->SetLastError(
2551 VE_BAD_ARGUMENT, kTraceError,
2552 "SetAudioScaling() failed to scale the playout");
2553 return -1;
2554 }
2555
2556 return 0;
2557}
2558
2559int Channel::GetLocalPlayoutPosition(int& positionMs)
2560{
2561 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2562 "Channel::GetLocalPlayoutPosition(position=?)");
2563
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002564 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002565
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002566 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002567
2568 if (_outputFilePlayerPtr == NULL)
2569 {
2570 _engineStatisticsPtr->SetLastError(
2571 VE_INVALID_OPERATION, kTraceError,
2572 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2573 return -1;
2574 }
2575
2576 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2577 {
2578 _engineStatisticsPtr->SetLastError(
2579 VE_BAD_FILE, kTraceError,
2580 "GetLocalPlayoutPosition() failed");
2581 return -1;
2582 }
2583 positionMs = position;
2584
2585 return 0;
2586}
2587
2588int Channel::StartPlayingFileAsMicrophone(const char* fileName,
2589 const bool loop,
2590 const FileFormats format,
2591 const int startPosition,
2592 const float volumeScaling,
2593 const int stopPosition,
2594 const CodecInst* codecInst)
2595{
2596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2597 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2598 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2599 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2600 startPosition, stopPosition);
2601
2602 if (_inputFilePlaying)
2603 {
2604 _engineStatisticsPtr->SetLastError(
2605 VE_ALREADY_PLAYING, kTraceWarning,
2606 "StartPlayingFileAsMicrophone() filePlayer is playing");
2607 return 0;
2608 }
2609
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002610 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002611
2612 // Destroy the old instance
2613 if (_inputFilePlayerPtr)
2614 {
2615 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2616 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2617 _inputFilePlayerPtr = NULL;
2618 }
2619
2620 // Create the instance
2621 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2622 _inputFilePlayerId, (const FileFormats)format);
2623
2624 if (_inputFilePlayerPtr == NULL)
2625 {
2626 _engineStatisticsPtr->SetLastError(
2627 VE_INVALID_ARGUMENT, kTraceError,
2628 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2629 return -1;
2630 }
2631
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002632 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002633
2634 if (_inputFilePlayerPtr->StartPlayingFile(
2635 fileName,
2636 loop,
2637 startPosition,
2638 volumeScaling,
2639 notificationTime,
2640 stopPosition,
2641 (const CodecInst*)codecInst) != 0)
2642 {
2643 _engineStatisticsPtr->SetLastError(
2644 VE_BAD_FILE, kTraceError,
2645 "StartPlayingFile() failed to start file playout");
2646 _inputFilePlayerPtr->StopPlayingFile();
2647 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2648 _inputFilePlayerPtr = NULL;
2649 return -1;
2650 }
2651 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2652 _inputFilePlaying = true;
2653
2654 return 0;
2655}
2656
2657int Channel::StartPlayingFileAsMicrophone(InStream* stream,
2658 const FileFormats format,
2659 const int startPosition,
2660 const float volumeScaling,
2661 const int stopPosition,
2662 const CodecInst* codecInst)
2663{
2664 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2665 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2666 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2667 format, volumeScaling, startPosition, stopPosition);
2668
2669 if(stream == NULL)
2670 {
2671 _engineStatisticsPtr->SetLastError(
2672 VE_BAD_FILE, kTraceError,
2673 "StartPlayingFileAsMicrophone NULL as input stream");
2674 return -1;
2675 }
2676
2677 if (_inputFilePlaying)
2678 {
2679 _engineStatisticsPtr->SetLastError(
2680 VE_ALREADY_PLAYING, kTraceWarning,
2681 "StartPlayingFileAsMicrophone() is playing");
2682 return 0;
2683 }
2684
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002685 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002686
2687 // Destroy the old instance
2688 if (_inputFilePlayerPtr)
2689 {
2690 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2691 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2692 _inputFilePlayerPtr = NULL;
2693 }
2694
2695 // Create the instance
2696 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2697 _inputFilePlayerId, (const FileFormats)format);
2698
2699 if (_inputFilePlayerPtr == NULL)
2700 {
2701 _engineStatisticsPtr->SetLastError(
2702 VE_INVALID_ARGUMENT, kTraceError,
2703 "StartPlayingInputFile() filePlayer format isnot correct");
2704 return -1;
2705 }
2706
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002707 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002708
2709 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2710 volumeScaling, notificationTime,
2711 stopPosition, codecInst) != 0)
2712 {
2713 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2714 "StartPlayingFile() failed to start "
2715 "file playout");
2716 _inputFilePlayerPtr->StopPlayingFile();
2717 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2718 _inputFilePlayerPtr = NULL;
2719 return -1;
2720 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002721
niklase@google.com470e71d2011-07-07 08:21:25 +00002722 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2723 _inputFilePlaying = true;
2724
2725 return 0;
2726}
2727
2728int Channel::StopPlayingFileAsMicrophone()
2729{
2730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2731 "Channel::StopPlayingFileAsMicrophone()");
2732
2733 if (!_inputFilePlaying)
2734 {
2735 _engineStatisticsPtr->SetLastError(
2736 VE_INVALID_OPERATION, kTraceWarning,
2737 "StopPlayingFileAsMicrophone() isnot playing");
2738 return 0;
2739 }
2740
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002741 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002742 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2743 {
2744 _engineStatisticsPtr->SetLastError(
2745 VE_STOP_RECORDING_FAILED, kTraceError,
2746 "StopPlayingFile() could not stop playing");
2747 return -1;
2748 }
2749 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2750 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2751 _inputFilePlayerPtr = NULL;
2752 _inputFilePlaying = false;
2753
2754 return 0;
2755}
2756
2757int Channel::IsPlayingFileAsMicrophone() const
2758{
2759 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2760 "Channel::IsPlayingFileAsMicrophone()");
2761
2762 return _inputFilePlaying;
2763}
2764
2765int Channel::ScaleFileAsMicrophonePlayout(const float scale)
2766{
2767 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2768 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2769
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002770 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002771
2772 if (!_inputFilePlaying)
2773 {
2774 _engineStatisticsPtr->SetLastError(
2775 VE_INVALID_OPERATION, kTraceError,
2776 "ScaleFileAsMicrophonePlayout() isnot playing");
2777 return -1;
2778 }
2779
2780 if ((_inputFilePlayerPtr == NULL) ||
2781 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2782 {
2783 _engineStatisticsPtr->SetLastError(
2784 VE_BAD_ARGUMENT, kTraceError,
2785 "SetAudioScaling() failed to scale playout");
2786 return -1;
2787 }
2788
2789 return 0;
2790}
2791
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002792int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002793 const CodecInst* codecInst)
2794{
2795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2796 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2797
2798 if (_outputFileRecording)
2799 {
2800 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2801 "StartRecordingPlayout() is already recording");
2802 return 0;
2803 }
2804
2805 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002806 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002807 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2808
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002809 if ((codecInst != NULL) &&
2810 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002811 {
2812 _engineStatisticsPtr->SetLastError(
2813 VE_BAD_ARGUMENT, kTraceError,
2814 "StartRecordingPlayout() invalid compression");
2815 return(-1);
2816 }
2817 if(codecInst == NULL)
2818 {
2819 format = kFileFormatPcm16kHzFile;
2820 codecInst=&dummyCodec;
2821 }
2822 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2823 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2824 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2825 {
2826 format = kFileFormatWavFile;
2827 }
2828 else
2829 {
2830 format = kFileFormatCompressedFile;
2831 }
2832
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002833 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002834
2835 // Destroy the old instance
2836 if (_outputFileRecorderPtr)
2837 {
2838 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2839 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2840 _outputFileRecorderPtr = NULL;
2841 }
2842
2843 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2844 _outputFileRecorderId, (const FileFormats)format);
2845 if (_outputFileRecorderPtr == NULL)
2846 {
2847 _engineStatisticsPtr->SetLastError(
2848 VE_INVALID_ARGUMENT, kTraceError,
2849 "StartRecordingPlayout() fileRecorder format isnot correct");
2850 return -1;
2851 }
2852
2853 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2854 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2855 {
2856 _engineStatisticsPtr->SetLastError(
2857 VE_BAD_FILE, kTraceError,
2858 "StartRecordingAudioFile() failed to start file recording");
2859 _outputFileRecorderPtr->StopRecording();
2860 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2861 _outputFileRecorderPtr = NULL;
2862 return -1;
2863 }
2864 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2865 _outputFileRecording = true;
2866
2867 return 0;
2868}
2869
2870int Channel::StartRecordingPlayout(OutStream* stream,
2871 const CodecInst* codecInst)
2872{
2873 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2874 "Channel::StartRecordingPlayout()");
2875
2876 if (_outputFileRecording)
2877 {
2878 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2879 "StartRecordingPlayout() is already recording");
2880 return 0;
2881 }
2882
2883 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002884 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002885 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2886
2887 if (codecInst != NULL && codecInst->channels != 1)
2888 {
2889 _engineStatisticsPtr->SetLastError(
2890 VE_BAD_ARGUMENT, kTraceError,
2891 "StartRecordingPlayout() invalid compression");
2892 return(-1);
2893 }
2894 if(codecInst == NULL)
2895 {
2896 format = kFileFormatPcm16kHzFile;
2897 codecInst=&dummyCodec;
2898 }
2899 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2900 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2901 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2902 {
2903 format = kFileFormatWavFile;
2904 }
2905 else
2906 {
2907 format = kFileFormatCompressedFile;
2908 }
2909
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002910 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002911
2912 // Destroy the old instance
2913 if (_outputFileRecorderPtr)
2914 {
2915 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2916 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2917 _outputFileRecorderPtr = NULL;
2918 }
2919
2920 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2921 _outputFileRecorderId, (const FileFormats)format);
2922 if (_outputFileRecorderPtr == NULL)
2923 {
2924 _engineStatisticsPtr->SetLastError(
2925 VE_INVALID_ARGUMENT, kTraceError,
2926 "StartRecordingPlayout() fileRecorder format isnot correct");
2927 return -1;
2928 }
2929
2930 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2931 notificationTime) != 0)
2932 {
2933 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2934 "StartRecordingPlayout() failed to "
2935 "start file recording");
2936 _outputFileRecorderPtr->StopRecording();
2937 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2938 _outputFileRecorderPtr = NULL;
2939 return -1;
2940 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002941
niklase@google.com470e71d2011-07-07 08:21:25 +00002942 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2943 _outputFileRecording = true;
2944
2945 return 0;
2946}
2947
2948int Channel::StopRecordingPlayout()
2949{
2950 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2951 "Channel::StopRecordingPlayout()");
2952
2953 if (!_outputFileRecording)
2954 {
2955 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2956 "StopRecordingPlayout() isnot recording");
2957 return -1;
2958 }
2959
2960
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002961 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002962
2963 if (_outputFileRecorderPtr->StopRecording() != 0)
2964 {
2965 _engineStatisticsPtr->SetLastError(
2966 VE_STOP_RECORDING_FAILED, kTraceError,
2967 "StopRecording() could not stop recording");
2968 return(-1);
2969 }
2970 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2971 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2972 _outputFileRecorderPtr = NULL;
2973 _outputFileRecording = false;
2974
2975 return 0;
2976}
2977
2978void
2979Channel::SetMixWithMicStatus(bool mix)
2980{
2981 _mixFileWithMicrophone=mix;
2982}
2983
2984int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002985Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002986{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002987 int8_t currentLevel = _outputAudioLevel.Level();
2988 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002989 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2990 VoEId(_instanceId,_channelId),
2991 "GetSpeechOutputLevel() => level=%u", level);
2992 return 0;
2993}
2994
2995int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002996Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002997{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002998 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2999 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003000 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3001 VoEId(_instanceId,_channelId),
3002 "GetSpeechOutputLevelFullRange() => level=%u", level);
3003 return 0;
3004}
3005
3006int
3007Channel::SetMute(bool enable)
3008{
3009 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3010 "Channel::SetMute(enable=%d)", enable);
3011 _mute = enable;
3012 return 0;
3013}
3014
3015bool
3016Channel::Mute() const
3017{
3018 return _mute;
3019}
3020
3021int
3022Channel::SetOutputVolumePan(float left, float right)
3023{
3024 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3025 "Channel::SetOutputVolumePan()");
3026 _panLeft = left;
3027 _panRight = right;
3028 return 0;
3029}
3030
3031int
3032Channel::GetOutputVolumePan(float& left, float& right) const
3033{
3034 left = _panLeft;
3035 right = _panRight;
3036 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3037 VoEId(_instanceId,_channelId),
3038 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3039 return 0;
3040}
3041
3042int
3043Channel::SetChannelOutputVolumeScaling(float scaling)
3044{
3045 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3046 "Channel::SetChannelOutputVolumeScaling()");
3047 _outputGain = scaling;
3048 return 0;
3049}
3050
3051int
3052Channel::GetChannelOutputVolumeScaling(float& scaling) const
3053{
3054 scaling = _outputGain;
3055 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3056 VoEId(_instanceId,_channelId),
3057 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3058 return 0;
3059}
3060
niklase@google.com470e71d2011-07-07 08:21:25 +00003061int
3062Channel::RegisterExternalEncryption(Encryption& encryption)
3063{
3064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3065 "Channel::RegisterExternalEncryption()");
3066
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003067 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003068
3069 if (_encryptionPtr)
3070 {
3071 _engineStatisticsPtr->SetLastError(
3072 VE_INVALID_OPERATION, kTraceError,
3073 "RegisterExternalEncryption() encryption already enabled");
3074 return -1;
3075 }
3076
3077 _encryptionPtr = &encryption;
3078
3079 _decrypting = true;
3080 _encrypting = true;
3081
3082 return 0;
3083}
3084
3085int
3086Channel::DeRegisterExternalEncryption()
3087{
3088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3089 "Channel::DeRegisterExternalEncryption()");
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, kTraceWarning,
3097 "DeRegisterExternalEncryption() encryption already disabled");
3098 return 0;
3099 }
3100
3101 _decrypting = false;
3102 _encrypting = false;
3103
3104 _encryptionPtr = NULL;
3105
3106 return 0;
3107}
3108
3109int Channel::SendTelephoneEventOutband(unsigned char eventCode,
3110 int lengthMs, int attenuationDb,
3111 bool playDtmfEvent)
3112{
3113 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3114 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3115 playDtmfEvent);
3116
3117 _playOutbandDtmfEvent = playDtmfEvent;
3118
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003119 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003120 attenuationDb) != 0)
3121 {
3122 _engineStatisticsPtr->SetLastError(
3123 VE_SEND_DTMF_FAILED,
3124 kTraceWarning,
3125 "SendTelephoneEventOutband() failed to send event");
3126 return -1;
3127 }
3128 return 0;
3129}
3130
3131int Channel::SendTelephoneEventInband(unsigned char eventCode,
3132 int lengthMs,
3133 int attenuationDb,
3134 bool playDtmfEvent)
3135{
3136 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3137 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3138 playDtmfEvent);
3139
3140 _playInbandDtmfEvent = playDtmfEvent;
3141 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3142
3143 return 0;
3144}
3145
3146int
3147Channel::SetDtmfPlayoutStatus(bool enable)
3148{
3149 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3150 "Channel::SetDtmfPlayoutStatus()");
3151 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3152 {
3153 _engineStatisticsPtr->SetLastError(
3154 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3155 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3156 return -1;
3157 }
3158 return 0;
3159}
3160
3161bool
3162Channel::DtmfPlayoutStatus() const
3163{
3164 return _audioCodingModule.DtmfPlayoutStatus();
3165}
3166
3167int
3168Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3169{
3170 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3171 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003172 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003173 {
3174 _engineStatisticsPtr->SetLastError(
3175 VE_INVALID_ARGUMENT, kTraceError,
3176 "SetSendTelephoneEventPayloadType() invalid type");
3177 return -1;
3178 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003179 CodecInst codec;
3180 codec.plfreq = 8000;
3181 codec.pltype = type;
3182 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003183 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003184 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003185 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3186 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3187 _engineStatisticsPtr->SetLastError(
3188 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3189 "SetSendTelephoneEventPayloadType() failed to register send"
3190 "payload type");
3191 return -1;
3192 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003193 }
3194 _sendTelephoneEventPayloadType = type;
3195 return 0;
3196}
3197
3198int
3199Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3200{
3201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3202 "Channel::GetSendTelephoneEventPayloadType()");
3203 type = _sendTelephoneEventPayloadType;
3204 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3205 VoEId(_instanceId,_channelId),
3206 "GetSendTelephoneEventPayloadType() => type=%u", type);
3207 return 0;
3208}
3209
niklase@google.com470e71d2011-07-07 08:21:25 +00003210int
3211Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3212{
3213 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3214 "Channel::UpdateRxVadDetection()");
3215
3216 int vadDecision = 1;
3217
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003218 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003219
3220 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3221 {
3222 OnRxVadDetected(vadDecision);
3223 _oldVadDecision = vadDecision;
3224 }
3225
3226 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3227 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3228 vadDecision);
3229 return 0;
3230}
3231
3232int
3233Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3234{
3235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3236 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003237 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003238
3239 if (_rxVadObserverPtr)
3240 {
3241 _engineStatisticsPtr->SetLastError(
3242 VE_INVALID_OPERATION, kTraceError,
3243 "RegisterRxVadObserver() observer already enabled");
3244 return -1;
3245 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003246 _rxVadObserverPtr = &observer;
3247 _RxVadDetection = true;
3248 return 0;
3249}
3250
3251int
3252Channel::DeRegisterRxVadObserver()
3253{
3254 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3255 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003256 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003257
3258 if (!_rxVadObserverPtr)
3259 {
3260 _engineStatisticsPtr->SetLastError(
3261 VE_INVALID_OPERATION, kTraceWarning,
3262 "DeRegisterRxVadObserver() observer already disabled");
3263 return 0;
3264 }
3265 _rxVadObserverPtr = NULL;
3266 _RxVadDetection = false;
3267 return 0;
3268}
3269
3270int
3271Channel::VoiceActivityIndicator(int &activity)
3272{
3273 activity = _sendFrameType;
3274
3275 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3276 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3277 return 0;
3278}
3279
3280#ifdef WEBRTC_VOICE_ENGINE_AGC
3281
3282int
3283Channel::SetRxAgcStatus(const bool enable, const AgcModes mode)
3284{
3285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3286 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3287 (int)enable, (int)mode);
3288
3289 GainControl::Mode agcMode(GainControl::kFixedDigital);
3290 switch (mode)
3291 {
3292 case kAgcDefault:
3293 agcMode = GainControl::kAdaptiveDigital;
3294 break;
3295 case kAgcUnchanged:
3296 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3297 break;
3298 case kAgcFixedDigital:
3299 agcMode = GainControl::kFixedDigital;
3300 break;
3301 case kAgcAdaptiveDigital:
3302 agcMode =GainControl::kAdaptiveDigital;
3303 break;
3304 default:
3305 _engineStatisticsPtr->SetLastError(
3306 VE_INVALID_ARGUMENT, kTraceError,
3307 "SetRxAgcStatus() invalid Agc mode");
3308 return -1;
3309 }
3310
3311 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3312 {
3313 _engineStatisticsPtr->SetLastError(
3314 VE_APM_ERROR, kTraceError,
3315 "SetRxAgcStatus() failed to set Agc mode");
3316 return -1;
3317 }
3318 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3319 {
3320 _engineStatisticsPtr->SetLastError(
3321 VE_APM_ERROR, kTraceError,
3322 "SetRxAgcStatus() failed to set Agc state");
3323 return -1;
3324 }
3325
3326 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003327 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3328
3329 return 0;
3330}
3331
3332int
3333Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3334{
3335 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3336 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3337
3338 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3339 GainControl::Mode agcMode =
3340 _rxAudioProcessingModulePtr->gain_control()->mode();
3341
3342 enabled = enable;
3343
3344 switch (agcMode)
3345 {
3346 case GainControl::kFixedDigital:
3347 mode = kAgcFixedDigital;
3348 break;
3349 case GainControl::kAdaptiveDigital:
3350 mode = kAgcAdaptiveDigital;
3351 break;
3352 default:
3353 _engineStatisticsPtr->SetLastError(
3354 VE_APM_ERROR, kTraceError,
3355 "GetRxAgcStatus() invalid Agc mode");
3356 return -1;
3357 }
3358
3359 return 0;
3360}
3361
3362int
3363Channel::SetRxAgcConfig(const AgcConfig config)
3364{
3365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3366 "Channel::SetRxAgcConfig()");
3367
3368 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3369 config.targetLeveldBOv) != 0)
3370 {
3371 _engineStatisticsPtr->SetLastError(
3372 VE_APM_ERROR, kTraceError,
3373 "SetRxAgcConfig() failed to set target peak |level|"
3374 "(or envelope) of the Agc");
3375 return -1;
3376 }
3377 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3378 config.digitalCompressionGaindB) != 0)
3379 {
3380 _engineStatisticsPtr->SetLastError(
3381 VE_APM_ERROR, kTraceError,
3382 "SetRxAgcConfig() failed to set the range in |gain| the"
3383 " digital compression stage may apply");
3384 return -1;
3385 }
3386 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3387 config.limiterEnable) != 0)
3388 {
3389 _engineStatisticsPtr->SetLastError(
3390 VE_APM_ERROR, kTraceError,
3391 "SetRxAgcConfig() failed to set hard limiter to the signal");
3392 return -1;
3393 }
3394
3395 return 0;
3396}
3397
3398int
3399Channel::GetRxAgcConfig(AgcConfig& config)
3400{
3401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3402 "Channel::GetRxAgcConfig(config=%?)");
3403
3404 config.targetLeveldBOv =
3405 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3406 config.digitalCompressionGaindB =
3407 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3408 config.limiterEnable =
3409 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3410
3411 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3412 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3413 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3414 " limiterEnable=%d",
3415 config.targetLeveldBOv,
3416 config.digitalCompressionGaindB,
3417 config.limiterEnable);
3418
3419 return 0;
3420}
3421
3422#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3423
3424#ifdef WEBRTC_VOICE_ENGINE_NR
3425
3426int
3427Channel::SetRxNsStatus(const bool enable, const NsModes mode)
3428{
3429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3430 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3431 (int)enable, (int)mode);
3432
3433 NoiseSuppression::Level nsLevel(
3434 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3435 switch (mode)
3436 {
3437
3438 case kNsDefault:
3439 nsLevel = (NoiseSuppression::Level)
3440 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3441 break;
3442 case kNsUnchanged:
3443 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3444 break;
3445 case kNsConference:
3446 nsLevel = NoiseSuppression::kHigh;
3447 break;
3448 case kNsLowSuppression:
3449 nsLevel = NoiseSuppression::kLow;
3450 break;
3451 case kNsModerateSuppression:
3452 nsLevel = NoiseSuppression::kModerate;
3453 break;
3454 case kNsHighSuppression:
3455 nsLevel = NoiseSuppression::kHigh;
3456 break;
3457 case kNsVeryHighSuppression:
3458 nsLevel = NoiseSuppression::kVeryHigh;
3459 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003460 }
3461
3462 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3463 != 0)
3464 {
3465 _engineStatisticsPtr->SetLastError(
3466 VE_APM_ERROR, kTraceError,
3467 "SetRxAgcStatus() failed to set Ns level");
3468 return -1;
3469 }
3470 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3471 {
3472 _engineStatisticsPtr->SetLastError(
3473 VE_APM_ERROR, kTraceError,
3474 "SetRxAgcStatus() failed to set Agc state");
3475 return -1;
3476 }
3477
3478 _rxNsIsEnabled = enable;
3479 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3480
3481 return 0;
3482}
3483
3484int
3485Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3486{
3487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3488 "Channel::GetRxNsStatus(enable=?, mode=?)");
3489
3490 bool enable =
3491 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3492 NoiseSuppression::Level ncLevel =
3493 _rxAudioProcessingModulePtr->noise_suppression()->level();
3494
3495 enabled = enable;
3496
3497 switch (ncLevel)
3498 {
3499 case NoiseSuppression::kLow:
3500 mode = kNsLowSuppression;
3501 break;
3502 case NoiseSuppression::kModerate:
3503 mode = kNsModerateSuppression;
3504 break;
3505 case NoiseSuppression::kHigh:
3506 mode = kNsHighSuppression;
3507 break;
3508 case NoiseSuppression::kVeryHigh:
3509 mode = kNsVeryHighSuppression;
3510 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003511 }
3512
3513 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3514 VoEId(_instanceId,_channelId),
3515 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3516 return 0;
3517}
3518
3519#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3520
3521int
3522Channel::RegisterRTPObserver(VoERTPObserver& observer)
3523{
3524 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3525 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003526 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003527
3528 if (_rtpObserverPtr)
3529 {
3530 _engineStatisticsPtr->SetLastError(
3531 VE_INVALID_OPERATION, kTraceError,
3532 "RegisterRTPObserver() observer already enabled");
3533 return -1;
3534 }
3535
3536 _rtpObserverPtr = &observer;
3537 _rtpObserver = true;
3538
3539 return 0;
3540}
3541
3542int
3543Channel::DeRegisterRTPObserver()
3544{
3545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3546 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003547 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003548
3549 if (!_rtpObserverPtr)
3550 {
3551 _engineStatisticsPtr->SetLastError(
3552 VE_INVALID_OPERATION, kTraceWarning,
3553 "DeRegisterRTPObserver() observer already disabled");
3554 return 0;
3555 }
3556
3557 _rtpObserver = false;
3558 _rtpObserverPtr = NULL;
3559
3560 return 0;
3561}
3562
3563int
3564Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3565{
3566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3567 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003568 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003569
3570 if (_rtcpObserverPtr)
3571 {
3572 _engineStatisticsPtr->SetLastError(
3573 VE_INVALID_OPERATION, kTraceError,
3574 "RegisterRTCPObserver() observer already enabled");
3575 return -1;
3576 }
3577
3578 _rtcpObserverPtr = &observer;
3579 _rtcpObserver = true;
3580
3581 return 0;
3582}
3583
3584int
3585Channel::DeRegisterRTCPObserver()
3586{
3587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3588 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003589 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003590
3591 if (!_rtcpObserverPtr)
3592 {
3593 _engineStatisticsPtr->SetLastError(
3594 VE_INVALID_OPERATION, kTraceWarning,
3595 "DeRegisterRTCPObserver() observer already disabled");
3596 return 0;
3597 }
3598
3599 _rtcpObserver = false;
3600 _rtcpObserverPtr = NULL;
3601
3602 return 0;
3603}
3604
3605int
3606Channel::SetLocalSSRC(unsigned int ssrc)
3607{
3608 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3609 "Channel::SetLocalSSRC()");
3610 if (_sending)
3611 {
3612 _engineStatisticsPtr->SetLastError(
3613 VE_ALREADY_SENDING, kTraceError,
3614 "SetLocalSSRC() already sending");
3615 return -1;
3616 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003617 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003618 {
3619 _engineStatisticsPtr->SetLastError(
3620 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3621 "SetLocalSSRC() failed to set SSRC");
3622 return -1;
3623 }
3624 return 0;
3625}
3626
3627int
3628Channel::GetLocalSSRC(unsigned int& ssrc)
3629{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003630 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003631 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3632 VoEId(_instanceId,_channelId),
3633 "GetLocalSSRC() => ssrc=%lu", ssrc);
3634 return 0;
3635}
3636
3637int
3638Channel::GetRemoteSSRC(unsigned int& ssrc)
3639{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003640 ssrc = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003641 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3642 VoEId(_instanceId,_channelId),
3643 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3644 return 0;
3645}
3646
3647int
3648Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3649{
3650 if (arrCSRC == NULL)
3651 {
3652 _engineStatisticsPtr->SetLastError(
3653 VE_INVALID_ARGUMENT, kTraceError,
3654 "GetRemoteCSRCs() invalid array argument");
3655 return -1;
3656 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003657 uint32_t arrOfCSRC[kRtpCsrcSize];
3658 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003659 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003660 if (CSRCs > 0)
3661 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003662 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003663 for (int i = 0; i < (int) CSRCs; i++)
3664 {
3665 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3666 VoEId(_instanceId, _channelId),
3667 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3668 }
3669 } else
3670 {
3671 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3672 VoEId(_instanceId, _channelId),
3673 "GetRemoteCSRCs() => list is empty!");
3674 }
3675 return CSRCs;
3676}
3677
3678int
3679Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3680{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003681 if (_rtpAudioProc.get() == NULL)
3682 {
3683 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3684 _channelId)));
3685 if (_rtpAudioProc.get() == NULL)
3686 {
3687 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3688 "Failed to create AudioProcessing");
3689 return -1;
3690 }
3691 }
3692
3693 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3694 AudioProcessing::kNoError)
3695 {
3696 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3697 "Failed to enable AudioProcessing::level_estimator()");
3698 }
3699
niklase@google.com470e71d2011-07-07 08:21:25 +00003700 _includeAudioLevelIndication = enable;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003701 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003702}
3703int
3704Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3705{
3706 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3707 VoEId(_instanceId,_channelId),
3708 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3709 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003710 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003711}
3712
3713int
3714Channel::SetRTCPStatus(bool enable)
3715{
3716 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3717 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003718 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003719 kRtcpCompound : kRtcpOff) != 0)
3720 {
3721 _engineStatisticsPtr->SetLastError(
3722 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3723 "SetRTCPStatus() failed to set RTCP status");
3724 return -1;
3725 }
3726 return 0;
3727}
3728
3729int
3730Channel::GetRTCPStatus(bool& enabled)
3731{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003732 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003733 enabled = (method != kRtcpOff);
3734 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3735 VoEId(_instanceId,_channelId),
3736 "GetRTCPStatus() => enabled=%d", enabled);
3737 return 0;
3738}
3739
3740int
3741Channel::SetRTCP_CNAME(const char cName[256])
3742{
3743 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3744 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003745 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003746 {
3747 _engineStatisticsPtr->SetLastError(
3748 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3749 "SetRTCP_CNAME() failed to set RTCP CNAME");
3750 return -1;
3751 }
3752 return 0;
3753}
3754
3755int
3756Channel::GetRTCP_CNAME(char cName[256])
3757{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003758 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003759 {
3760 _engineStatisticsPtr->SetLastError(
3761 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3762 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3763 return -1;
3764 }
3765 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3766 VoEId(_instanceId, _channelId),
3767 "GetRTCP_CNAME() => cName=%s", cName);
3768 return 0;
3769}
3770
3771int
3772Channel::GetRemoteRTCP_CNAME(char cName[256])
3773{
3774 if (cName == NULL)
3775 {
3776 _engineStatisticsPtr->SetLastError(
3777 VE_INVALID_ARGUMENT, kTraceError,
3778 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3779 return -1;
3780 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003781 char cname[RTCP_CNAME_SIZE];
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003782 const uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003783 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003784 {
3785 _engineStatisticsPtr->SetLastError(
3786 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3787 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3788 return -1;
3789 }
3790 strcpy(cName, cname);
3791 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3792 VoEId(_instanceId, _channelId),
3793 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3794 return 0;
3795}
3796
3797int
3798Channel::GetRemoteRTCPData(
3799 unsigned int& NTPHigh,
3800 unsigned int& NTPLow,
3801 unsigned int& timestamp,
3802 unsigned int& playoutTimestamp,
3803 unsigned int* jitter,
3804 unsigned short* fractionLost)
3805{
3806 // --- Information from sender info in received Sender Reports
3807
3808 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003809 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003810 {
3811 _engineStatisticsPtr->SetLastError(
3812 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003813 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003814 "side");
3815 return -1;
3816 }
3817
3818 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3819 // and octet count)
3820 NTPHigh = senderInfo.NTPseconds;
3821 NTPLow = senderInfo.NTPfraction;
3822 timestamp = senderInfo.RTPtimeStamp;
3823
3824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3825 VoEId(_instanceId, _channelId),
3826 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3827 "timestamp=%lu",
3828 NTPHigh, NTPLow, timestamp);
3829
3830 // --- Locally derived information
3831
3832 // This value is updated on each incoming RTCP packet (0 when no packet
3833 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003834 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003835
3836 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3837 VoEId(_instanceId, _channelId),
3838 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003839 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003840
3841 if (NULL != jitter || NULL != fractionLost)
3842 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003843 // Get all RTCP receiver report blocks that have been received on this
3844 // channel. If we receive RTP packets from a remote source we know the
3845 // remote SSRC and use the report block from him.
3846 // Otherwise use the first report block.
3847 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003848 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003849 remote_stats.empty()) {
3850 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3851 VoEId(_instanceId, _channelId),
3852 "GetRemoteRTCPData() failed to measure statistics due"
3853 " to lack of received RTP and/or RTCP packets");
3854 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003855 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003856
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003857 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003858 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3859 for (; it != remote_stats.end(); ++it) {
3860 if (it->remoteSSRC == remoteSSRC)
3861 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003862 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003863
3864 if (it == remote_stats.end()) {
3865 // If we have not received any RTCP packets from this SSRC it probably
3866 // means that we have not received any RTP packets.
3867 // Use the first received report block instead.
3868 it = remote_stats.begin();
3869 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003870 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003871
xians@webrtc.org79af7342012-01-31 12:22:14 +00003872 if (jitter) {
3873 *jitter = it->jitter;
3874 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3875 VoEId(_instanceId, _channelId),
3876 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3877 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003878
xians@webrtc.org79af7342012-01-31 12:22:14 +00003879 if (fractionLost) {
3880 *fractionLost = it->fractionLost;
3881 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3882 VoEId(_instanceId, _channelId),
3883 "GetRemoteRTCPData() => fractionLost = %lu",
3884 *fractionLost);
3885 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003886 }
3887 return 0;
3888}
3889
3890int
3891Channel::SendApplicationDefinedRTCPPacket(const unsigned char subType,
3892 unsigned int name,
3893 const char* data,
3894 unsigned short dataLengthInBytes)
3895{
3896 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3897 "Channel::SendApplicationDefinedRTCPPacket()");
3898 if (!_sending)
3899 {
3900 _engineStatisticsPtr->SetLastError(
3901 VE_NOT_SENDING, kTraceError,
3902 "SendApplicationDefinedRTCPPacket() not sending");
3903 return -1;
3904 }
3905 if (NULL == data)
3906 {
3907 _engineStatisticsPtr->SetLastError(
3908 VE_INVALID_ARGUMENT, kTraceError,
3909 "SendApplicationDefinedRTCPPacket() invalid data value");
3910 return -1;
3911 }
3912 if (dataLengthInBytes % 4 != 0)
3913 {
3914 _engineStatisticsPtr->SetLastError(
3915 VE_INVALID_ARGUMENT, kTraceError,
3916 "SendApplicationDefinedRTCPPacket() invalid length value");
3917 return -1;
3918 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003919 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003920 if (status == kRtcpOff)
3921 {
3922 _engineStatisticsPtr->SetLastError(
3923 VE_RTCP_ERROR, kTraceError,
3924 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3925 return -1;
3926 }
3927
3928 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003929 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003930 subType,
3931 name,
3932 (const unsigned char*) data,
3933 dataLengthInBytes) != 0)
3934 {
3935 _engineStatisticsPtr->SetLastError(
3936 VE_SEND_ERROR, kTraceError,
3937 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3938 return -1;
3939 }
3940 return 0;
3941}
3942
3943int
3944Channel::GetRTPStatistics(
3945 unsigned int& averageJitterMs,
3946 unsigned int& maxJitterMs,
3947 unsigned int& discardedPackets)
3948{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003949 uint8_t fraction_lost(0);
3950 uint32_t cum_lost(0);
3951 uint32_t ext_max(0);
3952 uint32_t jitter(0);
3953 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003954
3955 // The jitter statistics is updated for each received RTP packet and is
3956 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003957 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00003958 &cum_lost,
3959 &ext_max,
3960 &jitter,
3961 &max_jitter) != 0)
3962 {
3963 _engineStatisticsPtr->SetLastError(
3964 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003965 "GetRTPStatistics() failed to read RTP statistics from the "
niklase@google.com470e71d2011-07-07 08:21:25 +00003966 "RTP/RTCP module");
3967 }
3968
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003969 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00003970 _audioCodingModule.PlayoutFrequency();
3971 if (playoutFrequency > 0)
3972 {
3973 // Scale RTP statistics given the current playout frequency
3974 maxJitterMs = max_jitter / (playoutFrequency / 1000);
3975 averageJitterMs = jitter / (playoutFrequency / 1000);
3976 }
3977
3978 discardedPackets = _numberOfDiscardedPackets;
3979
3980 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3981 VoEId(_instanceId, _channelId),
3982 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003983 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003984 averageJitterMs, maxJitterMs, discardedPackets);
3985 return 0;
3986}
3987
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003988int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3989 if (sender_info == NULL) {
3990 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3991 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3992 return -1;
3993 }
3994
3995 // Get the sender info from the latest received RTCP Sender Report.
3996 RTCPSenderInfo rtcp_sender_info;
3997 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3998 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3999 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
4000 return -1;
4001 }
4002
4003 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
4004 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
4005 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
4006 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
4007 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
4008 return 0;
4009}
4010
4011int Channel::GetRemoteRTCPReportBlocks(
4012 std::vector<ReportBlock>* report_blocks) {
4013 if (report_blocks == NULL) {
4014 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4015 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4016 return -1;
4017 }
4018
4019 // Get the report blocks from the latest received RTCP Sender or Receiver
4020 // Report. Each element in the vector contains the sender's SSRC and a
4021 // report block according to RFC 3550.
4022 std::vector<RTCPReportBlock> rtcp_report_blocks;
4023 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4024 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4025 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4026 return -1;
4027 }
4028
4029 if (rtcp_report_blocks.empty())
4030 return 0;
4031
4032 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4033 for (; it != rtcp_report_blocks.end(); ++it) {
4034 ReportBlock report_block;
4035 report_block.sender_SSRC = it->remoteSSRC;
4036 report_block.source_SSRC = it->sourceSSRC;
4037 report_block.fraction_lost = it->fractionLost;
4038 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4039 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4040 report_block.interarrival_jitter = it->jitter;
4041 report_block.last_SR_timestamp = it->lastSR;
4042 report_block.delay_since_last_SR = it->delaySinceLastSR;
4043 report_blocks->push_back(report_block);
4044 }
4045 return 0;
4046}
4047
niklase@google.com470e71d2011-07-07 08:21:25 +00004048int
4049Channel::GetRTPStatistics(CallStatistics& stats)
4050{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004051 uint8_t fraction_lost(0);
4052 uint32_t cum_lost(0);
4053 uint32_t ext_max(0);
4054 uint32_t jitter(0);
4055 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004056
4057 // --- Part one of the final structure (four values)
4058
4059 // The jitter statistics is updated for each received RTP packet and is
4060 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004061 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00004062 &cum_lost,
4063 &ext_max,
4064 &jitter,
4065 &max_jitter) != 0)
4066 {
4067 _engineStatisticsPtr->SetLastError(
4068 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4069 "GetRTPStatistics() failed to read RTP statistics from the "
4070 "RTP/RTCP module");
4071 }
4072
4073 stats.fractionLost = fraction_lost;
4074 stats.cumulativeLost = cum_lost;
4075 stats.extendedMax = ext_max;
4076 stats.jitterSamples = jitter;
4077
4078 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4079 VoEId(_instanceId, _channelId),
4080 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004081 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004082 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4083 stats.jitterSamples);
4084
4085 // --- Part two of the final structure (one value)
4086
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004087 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004088 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004089 if (method == kRtcpOff)
4090 {
4091 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4092 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004093 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004094 "measurements cannot be retrieved");
4095 } else
4096 {
4097 // The remote SSRC will be zero if no RTP packet has been received.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004098 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004099 if (remoteSSRC > 0)
4100 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004101 uint16_t avgRTT(0);
4102 uint16_t maxRTT(0);
4103 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004104
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004105 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004106 != 0)
4107 {
4108 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4109 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004110 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004111 "the RTP/RTCP module");
4112 }
4113 } else
4114 {
4115 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4116 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004117 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004118 "RTP packets have been received yet");
4119 }
4120 }
4121
4122 stats.rttMs = static_cast<int> (RTT);
4123
4124 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4125 VoEId(_instanceId, _channelId),
4126 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4127
4128 // --- Part three of the final structure (four values)
4129
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004130 uint32_t bytesSent(0);
4131 uint32_t packetsSent(0);
4132 uint32_t bytesReceived(0);
4133 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004134
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004135 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
niklase@google.com470e71d2011-07-07 08:21:25 +00004136 &packetsSent,
4137 &bytesReceived,
4138 &packetsReceived) != 0)
4139 {
4140 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4141 VoEId(_instanceId, _channelId),
4142 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004143 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004144 }
4145
4146 stats.bytesSent = bytesSent;
4147 stats.packetsSent = packetsSent;
4148 stats.bytesReceived = bytesReceived;
4149 stats.packetsReceived = packetsReceived;
4150
4151 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4152 VoEId(_instanceId, _channelId),
4153 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004154 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004155 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4156 stats.packetsReceived);
4157
4158 return 0;
4159}
4160
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004161int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4162 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4163 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004164
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004165 if (enable) {
4166 if (redPayloadtype < 0 || redPayloadtype > 127) {
4167 _engineStatisticsPtr->SetLastError(
4168 VE_PLTYPE_ERROR, kTraceError,
4169 "SetFECStatus() invalid RED payload type");
4170 return -1;
4171 }
4172
4173 if (SetRedPayloadType(redPayloadtype) < 0) {
4174 _engineStatisticsPtr->SetLastError(
4175 VE_CODEC_ERROR, kTraceError,
4176 "SetSecondarySendCodec() Failed to register RED ACM");
4177 return -1;
4178 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004179 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004180
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004181 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4182 _engineStatisticsPtr->SetLastError(
4183 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4184 "SetFECStatus() failed to set FEC state in the ACM");
4185 return -1;
4186 }
4187 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004188}
4189
4190int
4191Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4192{
4193 enabled = _audioCodingModule.FECStatus();
4194 if (enabled)
4195 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004196 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004197 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004198 {
4199 _engineStatisticsPtr->SetLastError(
4200 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4201 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4202 "module");
4203 return -1;
4204 }
4205 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4206 VoEId(_instanceId, _channelId),
4207 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4208 enabled, redPayloadtype);
4209 return 0;
4210 }
4211 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4212 VoEId(_instanceId, _channelId),
4213 "GetFECStatus() => enabled=%d", enabled);
4214 return 0;
4215}
4216
4217int
niklase@google.com470e71d2011-07-07 08:21:25 +00004218Channel::StartRTPDump(const char fileNameUTF8[1024],
4219 RTPDirections direction)
4220{
4221 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4222 "Channel::StartRTPDump()");
4223 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4224 {
4225 _engineStatisticsPtr->SetLastError(
4226 VE_INVALID_ARGUMENT, kTraceError,
4227 "StartRTPDump() invalid RTP direction");
4228 return -1;
4229 }
4230 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4231 &_rtpDumpIn : &_rtpDumpOut;
4232 if (rtpDumpPtr == NULL)
4233 {
4234 assert(false);
4235 return -1;
4236 }
4237 if (rtpDumpPtr->IsActive())
4238 {
4239 rtpDumpPtr->Stop();
4240 }
4241 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4242 {
4243 _engineStatisticsPtr->SetLastError(
4244 VE_BAD_FILE, kTraceError,
4245 "StartRTPDump() failed to create file");
4246 return -1;
4247 }
4248 return 0;
4249}
4250
4251int
4252Channel::StopRTPDump(RTPDirections direction)
4253{
4254 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4255 "Channel::StopRTPDump()");
4256 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4257 {
4258 _engineStatisticsPtr->SetLastError(
4259 VE_INVALID_ARGUMENT, kTraceError,
4260 "StopRTPDump() invalid RTP direction");
4261 return -1;
4262 }
4263 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4264 &_rtpDumpIn : &_rtpDumpOut;
4265 if (rtpDumpPtr == NULL)
4266 {
4267 assert(false);
4268 return -1;
4269 }
4270 if (!rtpDumpPtr->IsActive())
4271 {
4272 return 0;
4273 }
4274 return rtpDumpPtr->Stop();
4275}
4276
4277bool
4278Channel::RTPDumpIsActive(RTPDirections direction)
4279{
4280 if ((direction != kRtpIncoming) &&
4281 (direction != kRtpOutgoing))
4282 {
4283 _engineStatisticsPtr->SetLastError(
4284 VE_INVALID_ARGUMENT, kTraceError,
4285 "RTPDumpIsActive() invalid RTP direction");
4286 return false;
4287 }
4288 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4289 &_rtpDumpIn : &_rtpDumpOut;
4290 return rtpDumpPtr->IsActive();
4291}
4292
4293int
4294Channel::InsertExtraRTPPacket(unsigned char payloadType,
4295 bool markerBit,
4296 const char* payloadData,
4297 unsigned short payloadSize)
4298{
4299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4300 "Channel::InsertExtraRTPPacket()");
4301 if (payloadType > 127)
4302 {
4303 _engineStatisticsPtr->SetLastError(
4304 VE_INVALID_PLTYPE, kTraceError,
4305 "InsertExtraRTPPacket() invalid payload type");
4306 return -1;
4307 }
4308 if (payloadData == NULL)
4309 {
4310 _engineStatisticsPtr->SetLastError(
4311 VE_INVALID_ARGUMENT, kTraceError,
4312 "InsertExtraRTPPacket() invalid payload data");
4313 return -1;
4314 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004315 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004316 {
4317 _engineStatisticsPtr->SetLastError(
4318 VE_INVALID_ARGUMENT, kTraceError,
4319 "InsertExtraRTPPacket() invalid payload size");
4320 return -1;
4321 }
4322 if (!_sending)
4323 {
4324 _engineStatisticsPtr->SetLastError(
4325 VE_NOT_SENDING, kTraceError,
4326 "InsertExtraRTPPacket() not sending");
4327 return -1;
4328 }
4329
4330 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4331 // Transport::SendPacket() will be called by the module when the RTP packet
4332 // is created.
4333 // The call to SendOutgoingData() does *not* modify the timestamp and
4334 // payloadtype to ensure that the RTP module generates a valid RTP packet
4335 // (user might utilize a non-registered payload type).
4336 // The marker bit and payload type will be replaced just before the actual
4337 // transmission, i.e., the actual modification is done *after* the RTP
4338 // module has delivered its RTP packet back to the VoE.
4339 // We will use the stored values above when the packet is modified
4340 // (see Channel::SendPacket()).
4341
4342 _extraPayloadType = payloadType;
4343 _extraMarkerBit = markerBit;
4344 _insertExtraRTPPacket = true;
4345
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004346 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004347 _lastPayloadType,
4348 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004349 // Leaving the time when this frame was
4350 // received from the capture device as
4351 // undefined for voice for now.
4352 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004353 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004354 payloadSize) != 0)
4355 {
4356 _engineStatisticsPtr->SetLastError(
4357 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4358 "InsertExtraRTPPacket() failed to send extra RTP packet");
4359 return -1;
4360 }
4361
4362 return 0;
4363}
4364
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004365uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004366Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004367{
4368 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004369 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004370 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004371 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004372 return 0;
4373}
4374
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004375uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004376Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004377{
4378 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4379 "Channel::PrepareEncodeAndSend()");
4380
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004381 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004382 {
4383 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4384 "Channel::PrepareEncodeAndSend() invalid audio frame");
4385 return -1;
4386 }
4387
4388 if (_inputFilePlaying)
4389 {
4390 MixOrReplaceAudioWithFile(mixingFrequency);
4391 }
4392
4393 if (_mute)
4394 {
4395 AudioFrameOperations::Mute(_audioFrame);
4396 }
4397
4398 if (_inputExternalMedia)
4399 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004400 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004401 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004402 if (_inputExternalMediaCallbackPtr)
4403 {
4404 _inputExternalMediaCallbackPtr->Process(
4405 _channelId,
4406 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004407 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004408 _audioFrame.samples_per_channel_,
4409 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004410 isStereo);
4411 }
4412 }
4413
4414 InsertInbandDtmfTone();
4415
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004416 if (_includeAudioLevelIndication)
4417 {
4418 assert(_rtpAudioProc.get() != NULL);
4419
4420 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004421 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004422 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004423 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004424 AudioProcessing::kNoError)
4425 {
4426 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4427 VoEId(_instanceId, _channelId),
4428 "Error setting AudioProcessing sample rate");
4429 return -1;
4430 }
4431 }
4432
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004433 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004434 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004435 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4436 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004437 != AudioProcessing::kNoError)
4438 {
4439 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4440 VoEId(_instanceId, _channelId),
4441 "Error setting AudioProcessing channels");
4442 return -1;
4443 }
4444 }
4445
4446 // Performs level analysis only; does not affect the signal.
4447 _rtpAudioProc->ProcessStream(&_audioFrame);
4448 }
4449
niklase@google.com470e71d2011-07-07 08:21:25 +00004450 return 0;
4451}
4452
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004453uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004454Channel::EncodeAndSend()
4455{
4456 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4457 "Channel::EncodeAndSend()");
4458
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004459 assert(_audioFrame.num_channels_ <= 2);
4460 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004461 {
4462 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4463 "Channel::EncodeAndSend() invalid audio frame");
4464 return -1;
4465 }
4466
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004467 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004468
4469 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4470
4471 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004472 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004473 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4474 {
4475 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4476 "Channel::EncodeAndSend() ACM encoding failed");
4477 return -1;
4478 }
4479
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004480 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004481
4482 // --- Encode if complete frame is ready
4483
4484 // This call will trigger AudioPacketizationCallback::SendData if encoding
4485 // is done and payload is ready for packetization and transmission.
4486 return _audioCodingModule.Process();
4487}
4488
4489int Channel::RegisterExternalMediaProcessing(
4490 ProcessingTypes type,
4491 VoEMediaProcess& processObject)
4492{
4493 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4494 "Channel::RegisterExternalMediaProcessing()");
4495
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004496 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004497
4498 if (kPlaybackPerChannel == type)
4499 {
4500 if (_outputExternalMediaCallbackPtr)
4501 {
4502 _engineStatisticsPtr->SetLastError(
4503 VE_INVALID_OPERATION, kTraceError,
4504 "Channel::RegisterExternalMediaProcessing() "
4505 "output external media already enabled");
4506 return -1;
4507 }
4508 _outputExternalMediaCallbackPtr = &processObject;
4509 _outputExternalMedia = true;
4510 }
4511 else if (kRecordingPerChannel == type)
4512 {
4513 if (_inputExternalMediaCallbackPtr)
4514 {
4515 _engineStatisticsPtr->SetLastError(
4516 VE_INVALID_OPERATION, kTraceError,
4517 "Channel::RegisterExternalMediaProcessing() "
4518 "output external media already enabled");
4519 return -1;
4520 }
4521 _inputExternalMediaCallbackPtr = &processObject;
4522 _inputExternalMedia = true;
4523 }
4524 return 0;
4525}
4526
4527int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4528{
4529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4530 "Channel::DeRegisterExternalMediaProcessing()");
4531
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004532 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004533
4534 if (kPlaybackPerChannel == type)
4535 {
4536 if (!_outputExternalMediaCallbackPtr)
4537 {
4538 _engineStatisticsPtr->SetLastError(
4539 VE_INVALID_OPERATION, kTraceWarning,
4540 "Channel::DeRegisterExternalMediaProcessing() "
4541 "output external media already disabled");
4542 return 0;
4543 }
4544 _outputExternalMedia = false;
4545 _outputExternalMediaCallbackPtr = NULL;
4546 }
4547 else if (kRecordingPerChannel == type)
4548 {
4549 if (!_inputExternalMediaCallbackPtr)
4550 {
4551 _engineStatisticsPtr->SetLastError(
4552 VE_INVALID_OPERATION, kTraceWarning,
4553 "Channel::DeRegisterExternalMediaProcessing() "
4554 "input external media already disabled");
4555 return 0;
4556 }
4557 _inputExternalMedia = false;
4558 _inputExternalMediaCallbackPtr = NULL;
4559 }
4560
4561 return 0;
4562}
4563
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004564int Channel::SetExternalMixing(bool enabled) {
4565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4566 "Channel::SetExternalMixing(enabled=%d)", enabled);
4567
4568 if (_playing)
4569 {
4570 _engineStatisticsPtr->SetLastError(
4571 VE_INVALID_OPERATION, kTraceError,
4572 "Channel::SetExternalMixing() "
4573 "external mixing cannot be changed while playing.");
4574 return -1;
4575 }
4576
4577 _externalMixing = enabled;
4578
4579 return 0;
4580}
4581
niklase@google.com470e71d2011-07-07 08:21:25 +00004582int
4583Channel::ResetRTCPStatistics()
4584{
4585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4586 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004587 uint32_t remoteSSRC(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004588 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4589 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004590}
4591
4592int
4593Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4594{
4595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4596 "Channel::GetRoundTripTimeSummary()");
4597 // Override default module outputs for the case when RTCP is disabled.
4598 // This is done to ensure that we are backward compatible with the
4599 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004600 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004601 {
4602 delaysMs.min = -1;
4603 delaysMs.max = -1;
4604 delaysMs.average = -1;
4605 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4606 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4607 " valid RTT measurements cannot be retrieved");
4608 return 0;
4609 }
4610
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004611 uint32_t remoteSSRC;
4612 uint16_t RTT;
4613 uint16_t avgRTT;
4614 uint16_t maxRTT;
4615 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004616 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004617 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004618 if (remoteSSRC == 0)
4619 {
4620 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4621 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4622 " since no RTP packet has been received yet");
4623 }
4624
4625 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4626 // channel and SSRC. The SSRC is required to parse out the correct source
4627 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004628 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004629 {
4630 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4631 "GetRoundTripTimeSummary unable to retrieve RTT values"
4632 " from the RTCP layer");
4633 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4634 }
4635 else
4636 {
4637 delaysMs.min = minRTT;
4638 delaysMs.max = maxRTT;
4639 delaysMs.average = avgRTT;
4640 }
4641 return 0;
4642}
4643
4644int
4645Channel::GetNetworkStatistics(NetworkStatistics& stats)
4646{
4647 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4648 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004649 ACMNetworkStatistics acm_stats;
4650 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4651 if (return_value >= 0) {
4652 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4653 }
4654 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004655}
4656
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004657bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4658 int* playout_buffer_delay_ms) const {
4659 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004660 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004661 "Channel::GetDelayEstimate() no valid estimate.");
4662 return false;
4663 }
4664 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4665 _recPacketDelayMs;
4666 *playout_buffer_delay_ms = playout_delay_ms_;
4667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4668 "Channel::GetDelayEstimate()");
4669 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004670}
4671
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004672int Channel::SetInitialPlayoutDelay(int delay_ms)
4673{
4674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4675 "Channel::SetInitialPlayoutDelay()");
4676 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4677 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4678 {
4679 _engineStatisticsPtr->SetLastError(
4680 VE_INVALID_ARGUMENT, kTraceError,
4681 "SetInitialPlayoutDelay() invalid min delay");
4682 return -1;
4683 }
4684 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4685 {
4686 _engineStatisticsPtr->SetLastError(
4687 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4688 "SetInitialPlayoutDelay() failed to set min playout delay");
4689 return -1;
4690 }
4691 return 0;
4692}
4693
4694
niklase@google.com470e71d2011-07-07 08:21:25 +00004695int
4696Channel::SetMinimumPlayoutDelay(int delayMs)
4697{
4698 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4699 "Channel::SetMinimumPlayoutDelay()");
4700 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4701 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4702 {
4703 _engineStatisticsPtr->SetLastError(
4704 VE_INVALID_ARGUMENT, kTraceError,
4705 "SetMinimumPlayoutDelay() invalid min delay");
4706 return -1;
4707 }
4708 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4709 {
4710 _engineStatisticsPtr->SetLastError(
4711 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4712 "SetMinimumPlayoutDelay() failed to set min playout delay");
4713 return -1;
4714 }
4715 return 0;
4716}
4717
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004718void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4719 uint32_t playout_timestamp = 0;
4720
4721 if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1) {
4722 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4723 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4724 " timestamp from the ACM");
4725 _engineStatisticsPtr->SetLastError(
4726 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4727 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4728 return;
4729 }
4730
4731 uint16_t delay_ms = 0;
4732 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4733 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4734 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4735 " delay from the ADM");
4736 _engineStatisticsPtr->SetLastError(
4737 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4738 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4739 return;
4740 }
4741
4742 int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
4743 CodecInst current_recive_codec;
4744 if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
4745 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4746 playout_frequency = 8000;
4747 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4748 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004749 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004750 }
4751
4752 // Remove the playout delay.
4753 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4754
4755 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4756 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4757 playout_timestamp);
4758
4759 if (rtcp) {
4760 playout_timestamp_rtcp_ = playout_timestamp;
4761 } else {
4762 playout_timestamp_rtp_ = playout_timestamp;
4763 }
4764 playout_delay_ms_ = delay_ms;
4765}
4766
4767int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4768 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4769 "Channel::GetPlayoutTimestamp()");
4770 if (playout_timestamp_rtp_ == 0) {
4771 _engineStatisticsPtr->SetLastError(
4772 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4773 "GetPlayoutTimestamp() failed to retrieve timestamp");
4774 return -1;
4775 }
4776 timestamp = playout_timestamp_rtp_;
4777 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4778 VoEId(_instanceId,_channelId),
4779 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4780 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004781}
4782
4783int
4784Channel::SetInitTimestamp(unsigned int timestamp)
4785{
4786 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4787 "Channel::SetInitTimestamp()");
4788 if (_sending)
4789 {
4790 _engineStatisticsPtr->SetLastError(
4791 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4792 return -1;
4793 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004794 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004795 {
4796 _engineStatisticsPtr->SetLastError(
4797 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4798 "SetInitTimestamp() failed to set timestamp");
4799 return -1;
4800 }
4801 return 0;
4802}
4803
4804int
4805Channel::SetInitSequenceNumber(short sequenceNumber)
4806{
4807 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4808 "Channel::SetInitSequenceNumber()");
4809 if (_sending)
4810 {
4811 _engineStatisticsPtr->SetLastError(
4812 VE_SENDING, kTraceError,
4813 "SetInitSequenceNumber() already sending");
4814 return -1;
4815 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004816 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004817 {
4818 _engineStatisticsPtr->SetLastError(
4819 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4820 "SetInitSequenceNumber() failed to set sequence number");
4821 return -1;
4822 }
4823 return 0;
4824}
4825
4826int
4827Channel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
4828{
4829 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4830 "Channel::GetRtpRtcp()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004831 rtpRtcpModule = _rtpRtcpModule.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004832 return 0;
4833}
4834
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004835// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4836// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004837int32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004838Channel::MixOrReplaceAudioWithFile(const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004839{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004840 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004841 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004842
4843 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004844 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004845
4846 if (_inputFilePlayerPtr == NULL)
4847 {
4848 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4849 VoEId(_instanceId, _channelId),
4850 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4851 " doesnt exist");
4852 return -1;
4853 }
4854
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004855 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004856 fileSamples,
4857 mixingFrequency) == -1)
4858 {
4859 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4860 VoEId(_instanceId, _channelId),
4861 "Channel::MixOrReplaceAudioWithFile() file mixing "
4862 "failed");
4863 return -1;
4864 }
4865 if (fileSamples == 0)
4866 {
4867 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4868 VoEId(_instanceId, _channelId),
4869 "Channel::MixOrReplaceAudioWithFile() file is ended");
4870 return 0;
4871 }
4872 }
4873
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004874 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004875
4876 if (_mixFileWithMicrophone)
4877 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004878 // Currently file stream is always mono.
4879 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004880 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004881 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004882 fileBuffer.get(),
4883 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004884 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004885 }
4886 else
4887 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004888 // Replace ACM audio with file.
4889 // Currently file stream is always mono.
4890 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004891 _audioFrame.UpdateFrame(_channelId,
4892 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004893 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004894 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004895 mixingFrequency,
4896 AudioFrame::kNormalSpeech,
4897 AudioFrame::kVadUnknown,
4898 1);
4899
4900 }
4901 return 0;
4902}
4903
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004904int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004905Channel::MixAudioWithFile(AudioFrame& audioFrame,
xians@google.com0b0665a2011-08-08 08:18:44 +00004906 const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004907{
4908 assert(mixingFrequency <= 32000);
4909
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004910 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004911 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004912
4913 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004914 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004915
4916 if (_outputFilePlayerPtr == NULL)
4917 {
4918 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4919 VoEId(_instanceId, _channelId),
4920 "Channel::MixAudioWithFile() file mixing failed");
4921 return -1;
4922 }
4923
4924 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004925 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004926 fileSamples,
4927 mixingFrequency) == -1)
4928 {
4929 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4930 VoEId(_instanceId, _channelId),
4931 "Channel::MixAudioWithFile() file mixing failed");
4932 return -1;
4933 }
4934 }
4935
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004936 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004937 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004938 // Currently file stream is always mono.
4939 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004940 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004941 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004942 fileBuffer.get(),
4943 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004944 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004945 }
4946 else
4947 {
4948 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004949 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004950 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004951 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004952 return -1;
4953 }
4954
4955 return 0;
4956}
4957
4958int
4959Channel::InsertInbandDtmfTone()
4960{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004961 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004962 if (_inbandDtmfQueue.PendingDtmf() &&
4963 !_inbandDtmfGenerator.IsAddingTone() &&
4964 _inbandDtmfGenerator.DelaySinceLastTone() >
4965 kMinTelephoneEventSeparationMs)
4966 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004967 int8_t eventCode(0);
4968 uint16_t lengthMs(0);
4969 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004970
4971 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4972 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4973 if (_playInbandDtmfEvent)
4974 {
4975 // Add tone to output mixer using a reduced length to minimize
4976 // risk of echo.
4977 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4978 attenuationDb);
4979 }
4980 }
4981
4982 if (_inbandDtmfGenerator.IsAddingTone())
4983 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004984 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004985 _inbandDtmfGenerator.GetSampleRate(frequency);
4986
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004987 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004988 {
4989 // Update sample rate of Dtmf tone since the mixing frequency
4990 // has changed.
4991 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004992 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004993 // Reset the tone to be added taking the new sample rate into
4994 // account.
4995 _inbandDtmfGenerator.ResetTone();
4996 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004997
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004998 int16_t toneBuffer[320];
4999 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005000 // Get 10ms tone segment and set time since last tone to zero
5001 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5002 {
5003 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5004 VoEId(_instanceId, _channelId),
5005 "Channel::EncodeAndSend() inserting Dtmf failed");
5006 return -1;
5007 }
5008
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005009 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005010 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005011 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005012 sample++)
5013 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005014 for (int channel = 0;
5015 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005016 channel++)
5017 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005018 const int index = sample * _audioFrame.num_channels_ + channel;
5019 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005020 }
5021 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005022
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005023 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005024 } else
5025 {
5026 // Add 10ms to "delay-since-last-tone" counter
5027 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5028 }
5029 return 0;
5030}
5031
niklase@google.com470e71d2011-07-07 08:21:25 +00005032void
5033Channel::ResetDeadOrAliveCounters()
5034{
5035 _countDeadDetections = 0;
5036 _countAliveDetections = 0;
5037}
5038
5039void
5040Channel::UpdateDeadOrAliveCounters(bool alive)
5041{
5042 if (alive)
5043 _countAliveDetections++;
5044 else
5045 _countDeadDetections++;
5046}
5047
5048int
5049Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5050{
5051 bool enabled;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005052 uint8_t timeSec;
niklase@google.com470e71d2011-07-07 08:21:25 +00005053
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005054 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00005055 if (!enabled)
5056 return (-1);
5057
5058 countDead = static_cast<int> (_countDeadDetections);
5059 countAlive = static_cast<int> (_countAliveDetections);
5060 return 0;
5061}
5062
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005063int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005064Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5065{
5066 if (_transportPtr == NULL)
5067 {
5068 return -1;
5069 }
5070 if (!RTCP)
5071 {
5072 return _transportPtr->SendPacket(_channelId, data, len);
5073 }
5074 else
5075 {
5076 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5077 }
5078}
5079
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005080// Called for incoming RTP packets after successful RTP header parsing.
5081void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5082 uint16_t sequence_number) {
5083 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5084 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5085 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005086
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005087 // Get frequency of last received payload
5088 int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005089
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005090 CodecInst current_receive_codec;
5091 if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
5092 return;
5093 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005094
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005095 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5096 // Even though the actual sampling rate for G.722 audio is
5097 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5098 // 8,000 Hz because that value was erroneously assigned in
5099 // RFC 1890 and must remain unchanged for backward compatibility.
5100 rtp_receive_frequency = 8000;
5101 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5102 // We are resampling Opus internally to 32,000 Hz until all our
5103 // DSP routines can operate at 48,000 Hz, but the RTP clock
5104 // rate for the Opus payload format is standardized to 48,000 Hz,
5105 // because that is the maximum supported decoding sampling rate.
5106 rtp_receive_frequency = 48000;
5107 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005108
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005109 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5110 // packet.
5111 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5112 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005113
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005114 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5115 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005116
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005117 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005118
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005119 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5120 timestamp_diff_ms = 0;
5121 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005122
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005123 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005124
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005125 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5126 _recPacketDelayMs = packet_delay_ms;
5127 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005128
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005129 if (_average_jitter_buffer_delay_us == 0) {
5130 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5131 return;
5132 }
5133
5134 // Filter average delay value using exponential filter (alpha is
5135 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5136 // risk of rounding error) and compensate for it in GetDelayEstimate()
5137 // later.
5138 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5139 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005140}
5141
5142void
5143Channel::RegisterReceiveCodecsToRTPModule()
5144{
5145 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5146 "Channel::RegisterReceiveCodecsToRTPModule()");
5147
5148
5149 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005150 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005151
5152 for (int idx = 0; idx < nSupportedCodecs; idx++)
5153 {
5154 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005155 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005156 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005157 {
5158 WEBRTC_TRACE(
5159 kTraceWarning,
5160 kTraceVoice,
5161 VoEId(_instanceId, _channelId),
5162 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5163 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5164 codec.plname, codec.pltype, codec.plfreq,
5165 codec.channels, codec.rate);
5166 }
5167 else
5168 {
5169 WEBRTC_TRACE(
5170 kTraceInfo,
5171 kTraceVoice,
5172 VoEId(_instanceId, _channelId),
5173 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005174 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005175 "receiver",
5176 codec.plname, codec.pltype, codec.plfreq,
5177 codec.channels, codec.rate);
5178 }
5179 }
5180}
5181
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005182int Channel::ApmProcessRx(AudioFrame& frame) {
5183 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5184 // Register the (possibly new) frame parameters.
5185 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005186 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005187 }
5188 if (audioproc->set_num_channels(frame.num_channels_,
5189 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005190 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005191 }
5192 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005193 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005194 }
5195 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005196}
5197
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005198int Channel::SetSecondarySendCodec(const CodecInst& codec,
5199 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005200 // Sanity check for payload type.
5201 if (red_payload_type < 0 || red_payload_type > 127) {
5202 _engineStatisticsPtr->SetLastError(
5203 VE_PLTYPE_ERROR, kTraceError,
5204 "SetRedPayloadType() invalid RED payload type");
5205 return -1;
5206 }
5207
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005208 if (SetRedPayloadType(red_payload_type) < 0) {
5209 _engineStatisticsPtr->SetLastError(
5210 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5211 "SetSecondarySendCodec() Failed to register RED ACM");
5212 return -1;
5213 }
5214 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5215 _engineStatisticsPtr->SetLastError(
5216 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5217 "SetSecondarySendCodec() Failed to register secondary send codec in "
5218 "ACM");
5219 return -1;
5220 }
5221
5222 return 0;
5223}
5224
5225void Channel::RemoveSecondarySendCodec() {
5226 _audioCodingModule.UnregisterSecondarySendCodec();
5227}
5228
5229int Channel::GetSecondarySendCodec(CodecInst* codec) {
5230 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5231 _engineStatisticsPtr->SetLastError(
5232 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5233 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5234 return -1;
5235 }
5236 return 0;
5237}
5238
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005239// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005240int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005241 CodecInst codec;
5242 bool found_red = false;
5243
5244 // Get default RED settings from the ACM database
5245 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5246 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005247 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005248 if (!STR_CASE_CMP(codec.plname, "RED")) {
5249 found_red = true;
5250 break;
5251 }
5252 }
5253
5254 if (!found_red) {
5255 _engineStatisticsPtr->SetLastError(
5256 VE_CODEC_ERROR, kTraceError,
5257 "SetRedPayloadType() RED is not supported");
5258 return -1;
5259 }
5260
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005261 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005262 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5263 _engineStatisticsPtr->SetLastError(
5264 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5265 "SetRedPayloadType() RED registration in ACM module failed");
5266 return -1;
5267 }
5268
5269 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5270 _engineStatisticsPtr->SetLastError(
5271 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5272 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5273 return -1;
5274 }
5275 return 0;
5276}
5277
niklase@google.com470e71d2011-07-07 08:21:25 +00005278} // namespace voe
niklase@google.com470e71d2011-07-07 08:21:25 +00005279} // namespace webrtc