blob: 3480564c6641e41ae3ece84cbb861974c7c241f1 [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);
631
632 return 0;
633}
634
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000635int32_t Channel::GetAudioFrame(const int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000636{
637 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
638 "Channel::GetAudioFrame(id=%d)", id);
639
640 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000641 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000642 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 {
644 WEBRTC_TRACE(kTraceError, kTraceVoice,
645 VoEId(_instanceId,_channelId),
646 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000647 // In all likelihood, the audio in this frame is garbage. We return an
648 // error so that the audio mixer module doesn't add it to the mix. As
649 // a result, it won't be played out and the actions skipped here are
650 // irrelevant.
651 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 }
653
654 if (_RxVadDetection)
655 {
656 UpdateRxVadDetection(audioFrame);
657 }
658
659 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000660 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000662 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000663
664 // Perform far-end AudioProcessing module processing on the received signal
665 if (_rxApmIsEnabled)
666 {
667 ApmProcessRx(audioFrame);
668 }
669
670 // Output volume scaling
671 if (_outputGain < 0.99f || _outputGain > 1.01f)
672 {
673 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
674 }
675
676 // Scale left and/or right channel(s) if stereo and master balance is
677 // active
678
679 if (_panLeft != 1.0f || _panRight != 1.0f)
680 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000681 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 {
683 // Emulate stereo mode since panning is active.
684 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000685 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 }
687 // For true stereo mode (when we are receiving a stereo signal), no
688 // action is needed.
689
690 // Do the panning operation (the audio frame contains stereo at this
691 // stage)
692 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
693 }
694
695 // Mix decoded PCM output with file if file mixing is enabled
696 if (_outputFilePlaying)
697 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000698 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 }
700
701 // Place channel in on-hold state (~muted) if on-hold is activated
702 if (_outputIsOnHold)
703 {
704 AudioFrameOperations::Mute(audioFrame);
705 }
706
707 // External media
708 if (_outputExternalMedia)
709 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000710 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000711 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 if (_outputExternalMediaCallbackPtr)
713 {
714 _outputExternalMediaCallbackPtr->Process(
715 _channelId,
716 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000717 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000718 audioFrame.samples_per_channel_,
719 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 isStereo);
721 }
722 }
723
724 // Record playout if enabled
725 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000726 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000727
728 if (_outputFileRecording && _outputFileRecorderPtr)
729 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000730 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 }
732 }
733
734 // Measure audio level (0-9)
735 _outputAudioLevel.ComputeLevel(audioFrame);
736
737 return 0;
738}
739
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000740int32_t
741Channel::NeededFrequency(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000742{
743 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
744 "Channel::NeededFrequency(id=%d)", id);
745
746 int highestNeeded = 0;
747
748 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000749 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000750
751 // Return the bigger of playout and receive frequency in the ACM.
752 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
753 {
754 highestNeeded = _audioCodingModule.PlayoutFrequency();
755 }
756 else
757 {
758 highestNeeded = receiveFrequency;
759 }
760
761 // Special case, if we're playing a file on the playout side
762 // we take that frequency into consideration as well
763 // This is not needed on sending side, since the codec will
764 // limit the spectrum anyway.
765 if (_outputFilePlaying)
766 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000767 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000768 if (_outputFilePlayerPtr && _outputFilePlaying)
769 {
770 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
771 {
772 highestNeeded=_outputFilePlayerPtr->Frequency();
773 }
774 }
775 }
776
777 return(highestNeeded);
778}
779
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000780int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000781Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000782 const int32_t channelId,
783 const uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000784{
785 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
786 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
787 channelId, instanceId);
788
789 channel = new Channel(channelId, instanceId);
790 if (channel == NULL)
791 {
792 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
793 VoEId(instanceId,channelId),
794 "Channel::CreateChannel() unable to allocate memory for"
795 " channel");
796 return -1;
797 }
798 return 0;
799}
800
801void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000802Channel::PlayNotification(const int32_t id, const uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000803{
804 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
805 "Channel::PlayNotification(id=%d, durationMs=%d)",
806 id, durationMs);
807
808 // Not implement yet
809}
810
811void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000812Channel::RecordNotification(const int32_t id, const uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000813{
814 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
815 "Channel::RecordNotification(id=%d, durationMs=%d)",
816 id, durationMs);
817
818 // Not implement yet
819}
820
821void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000822Channel::PlayFileEnded(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000823{
824 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
825 "Channel::PlayFileEnded(id=%d)", id);
826
827 if (id == _inputFilePlayerId)
828 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000829 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000830
831 _inputFilePlaying = false;
832 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
833 VoEId(_instanceId,_channelId),
834 "Channel::PlayFileEnded() => input file player module is"
835 " shutdown");
836 }
837 else if (id == _outputFilePlayerId)
838 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000839 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000840
841 _outputFilePlaying = false;
842 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
843 VoEId(_instanceId,_channelId),
844 "Channel::PlayFileEnded() => output file player module is"
845 " shutdown");
846 }
847}
848
849void
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000850Channel::RecordFileEnded(const int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000851{
852 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
853 "Channel::RecordFileEnded(id=%d)", id);
854
855 assert(id == _outputFileRecorderId);
856
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000857 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000858
859 _outputFileRecording = false;
860 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
861 VoEId(_instanceId,_channelId),
862 "Channel::RecordFileEnded() => output file recorder module is"
863 " shutdown");
864}
865
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000866Channel::Channel(const int32_t channelId,
867 const uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
869 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000870 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000871 _channelId(channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000872 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000873 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 _rtpDumpIn(*RtpDump::CreateRtpDump()),
875 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 _inputFilePlayerPtr(NULL),
879 _outputFilePlayerPtr(NULL),
880 _outputFileRecorderPtr(NULL),
881 // Avoid conflict with other channels by adding 1024 - 1026,
882 // won't use as much as 1024 channels.
883 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
884 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
885 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
886 _inputFilePlaying(false),
887 _outputFilePlaying(false),
888 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
890 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000891 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000892 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 _inputExternalMediaCallbackPtr(NULL),
894 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000895 _encryptionRTPBufferPtr(NULL),
896 _decryptionRTPBufferPtr(NULL),
897 _encryptionRTCPBufferPtr(NULL),
898 _decryptionRTCPBufferPtr(NULL),
899 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
900 _sendTelephoneEventPayloadType(106),
901 _playoutTimeStampRTP(0),
902 _playoutTimeStampRTCP(0),
903 _numberOfDiscardedPackets(0),
904 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000905 _outputMixerPtr(NULL),
906 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000907 _moduleProcessThreadPtr(NULL),
908 _audioDeviceModulePtr(NULL),
909 _voiceEngineObserverPtr(NULL),
910 _callbackCritSectPtr(NULL),
911 _transportPtr(NULL),
912 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000913 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000914 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000915 _rxVadObserverPtr(NULL),
916 _oldVadDecision(-1),
917 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _rtpObserverPtr(NULL),
919 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000920 _outputIsOnHold(false),
921 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000922 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000923 _inputIsOnHold(false),
924 _playing(false),
925 _sending(false),
926 _receiving(false),
927 _mixFileWithMicrophone(false),
928 _rtpObserver(false),
929 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 _mute(false),
931 _panLeft(1.0f),
932 _panRight(1.0f),
933 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000934 _encrypting(false),
935 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 _playOutbandDtmfEvent(false),
937 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000938 _extraPayloadType(0),
939 _insertExtraRTPPacket(false),
940 _extraMarkerBit(false),
941 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000942 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000944 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000945 _rtpPacketTimedOut(false),
946 _rtpPacketTimeOutIsEnabled(false),
947 _rtpTimeOutSeconds(0),
948 _connectionObserver(false),
949 _connectionObserverPtr(NULL),
950 _countAliveDetections(0),
951 _countDeadDetections(0),
952 _outputSpeechType(AudioFrame::kNormalSpeech),
953 _averageDelayMs(0),
954 _previousSequenceNumber(0),
955 _previousTimestamp(0),
956 _recPacketDelayMs(20),
957 _RxVadDetection(false),
958 _rxApmIsEnabled(false),
959 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000960 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000961{
962 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
963 "Channel::Channel() - ctor");
964 _inbandDtmfQueue.ResetDtmf();
965 _inbandDtmfGenerator.Init();
966 _outputAudioLevel.Clear();
967
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000968 RtpRtcp::Configuration configuration;
969 configuration.id = VoEModuleId(instanceId, channelId);
970 configuration.audio = true;
971 configuration.incoming_data = this;
972 configuration.incoming_messages = this;
973 configuration.outgoing_transport = this;
974 configuration.rtcp_feedback = this;
975 configuration.audio_messages = this;
976
977 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
978
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 // Create far end AudioProcessing Module
980 _rxAudioProcessingModulePtr = AudioProcessing::Create(
981 VoEModuleId(instanceId, channelId));
982}
983
984Channel::~Channel()
985{
986 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
987 "Channel::~Channel() - dtor");
988
989 if (_outputExternalMedia)
990 {
991 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
992 }
993 if (_inputExternalMedia)
994 {
995 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
996 }
997 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 StopPlayout();
999
1000 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001001 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 if (_inputFilePlayerPtr)
1003 {
1004 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1005 _inputFilePlayerPtr->StopPlayingFile();
1006 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1007 _inputFilePlayerPtr = NULL;
1008 }
1009 if (_outputFilePlayerPtr)
1010 {
1011 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1012 _outputFilePlayerPtr->StopPlayingFile();
1013 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1014 _outputFilePlayerPtr = NULL;
1015 }
1016 if (_outputFileRecorderPtr)
1017 {
1018 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1019 _outputFileRecorderPtr->StopRecording();
1020 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1021 _outputFileRecorderPtr = NULL;
1022 }
1023 }
1024
1025 // The order to safely shutdown modules in a channel is:
1026 // 1. De-register callbacks in modules
1027 // 2. De-register modules in process thread
1028 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1030 {
1031 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1032 VoEId(_instanceId,_channelId),
1033 "~Channel() failed to de-register transport callback"
1034 " (Audio coding module)");
1035 }
1036 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1037 {
1038 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1039 VoEId(_instanceId,_channelId),
1040 "~Channel() failed to de-register VAD callback"
1041 " (Audio coding module)");
1042 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001044 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 {
1046 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1047 VoEId(_instanceId,_channelId),
1048 "~Channel() failed to deregister RTP/RTCP module");
1049 }
1050
1051 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 if (_rxAudioProcessingModulePtr != NULL)
1054 {
1055 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1056 _rxAudioProcessingModulePtr = NULL;
1057 }
1058
1059 // End of modules shutdown
1060
1061 // Delete other objects
1062 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1063 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1064 delete [] _encryptionRTPBufferPtr;
1065 delete [] _decryptionRTPBufferPtr;
1066 delete [] _encryptionRTCPBufferPtr;
1067 delete [] _decryptionRTCPBufferPtr;
1068 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 delete &_fileCritSect;
1070}
1071
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001072int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001073Channel::Init()
1074{
1075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1076 "Channel::Init()");
1077
1078 // --- Initial sanity
1079
1080 if ((_engineStatisticsPtr == NULL) ||
1081 (_moduleProcessThreadPtr == NULL))
1082 {
1083 WEBRTC_TRACE(kTraceError, kTraceVoice,
1084 VoEId(_instanceId,_channelId),
1085 "Channel::Init() must call SetEngineInformation() first");
1086 return -1;
1087 }
1088
1089 // --- Add modules to process thread (for periodic schedulation)
1090
1091 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001092 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 if (processThreadFail)
1095 {
1096 _engineStatisticsPtr->SetLastError(
1097 VE_CANNOT_INIT_CHANNEL, kTraceError,
1098 "Channel::Init() modules not registered");
1099 return -1;
1100 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001101 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001102
1103 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1104#ifdef WEBRTC_CODEC_AVT
1105 // out-of-band Dtmf tones are played out by default
1106 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1107#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 (_audioCodingModule.InitializeSender() == -1))
1109 {
1110 _engineStatisticsPtr->SetLastError(
1111 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1112 "Channel::Init() unable to initialize the ACM - 1");
1113 return -1;
1114 }
1115
1116 // --- RTP/RTCP module initialization
1117
1118 // Ensure that RTCP is enabled by default for the created channel.
1119 // Note that, the module will keep generating RTCP until it is explicitly
1120 // disabled by the user.
1121 // After StopListen (when no sockets exists), RTCP packets will no longer
1122 // be transmitted since the Transport object will then be invalid.
1123
1124 const bool rtpRtcpFail =
turaj@webrtc.orgb7edd062013-03-12 22:27:27 +00001125 ((_rtpRtcpModule->SetTelephoneEventForwardToDecoder(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001126 // RTCP is enabled by default
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001127 (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1));
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 if (rtpRtcpFail)
1129 {
1130 _engineStatisticsPtr->SetLastError(
1131 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1132 "Channel::Init() RTP/RTCP module not initialized");
1133 return -1;
1134 }
1135
1136 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1139 (_audioCodingModule.RegisterVADCallback(this) == -1);
1140
1141 if (fail)
1142 {
1143 _engineStatisticsPtr->SetLastError(
1144 VE_CANNOT_INIT_CHANNEL, kTraceError,
1145 "Channel::Init() callbacks not registered");
1146 return -1;
1147 }
1148
1149 // --- Register all supported codecs to the receiving side of the
1150 // RTP/RTCP module
1151
1152 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001153 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001154
1155 for (int idx = 0; idx < nSupportedCodecs; idx++)
1156 {
1157 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001158 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001159 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 {
1161 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1162 VoEId(_instanceId,_channelId),
1163 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1164 "to RTP/RTCP receiver",
1165 codec.plname, codec.pltype, codec.plfreq,
1166 codec.channels, codec.rate);
1167 }
1168 else
1169 {
1170 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1171 VoEId(_instanceId,_channelId),
1172 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1173 "the RTP/RTCP receiver",
1174 codec.plname, codec.pltype, codec.plfreq,
1175 codec.channels, codec.rate);
1176 }
1177
1178 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001179 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001180 {
1181 SetSendCodec(codec);
1182 }
1183
1184 // Register default PT for outband 'telephone-event'
1185 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1186 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001187 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001188 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1189 {
1190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1191 VoEId(_instanceId,_channelId),
1192 "Channel::Init() failed to register outband "
1193 "'telephone-event' (%d/%d) correctly",
1194 codec.pltype, codec.plfreq);
1195 }
1196 }
1197
1198 if (!STR_CASE_CMP(codec.plname, "CN"))
1199 {
1200 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1201 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001202 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 {
1204 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1205 VoEId(_instanceId,_channelId),
1206 "Channel::Init() failed to register CN (%d/%d) "
1207 "correctly - 1",
1208 codec.pltype, codec.plfreq);
1209 }
1210 }
1211#ifdef WEBRTC_CODEC_RED
1212 // Register RED to the receiving side of the ACM.
1213 // We will not receive an OnInitializeDecoder() callback for RED.
1214 if (!STR_CASE_CMP(codec.plname, "RED"))
1215 {
1216 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1217 {
1218 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1219 VoEId(_instanceId,_channelId),
1220 "Channel::Init() failed to register RED (%d/%d) "
1221 "correctly",
1222 codec.pltype, codec.plfreq);
1223 }
1224 }
1225#endif
1226 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001227
niklase@google.com470e71d2011-07-07 08:21:25 +00001228 // Initialize the far end AP module
1229 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1230 // changed at the first receiving audio.
1231 if (_rxAudioProcessingModulePtr == NULL)
1232 {
1233 _engineStatisticsPtr->SetLastError(
1234 VE_NO_MEMORY, kTraceCritical,
1235 "Channel::Init() failed to create the far-end AudioProcessing"
1236 " module");
1237 return -1;
1238 }
1239
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1241 {
1242 _engineStatisticsPtr->SetLastError(
1243 VE_APM_ERROR, kTraceWarning,
1244 "Channel::Init() failed to set the sample rate to 8K for"
1245 " far-end AP module");
1246 }
1247
1248 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1249 {
1250 _engineStatisticsPtr->SetLastError(
1251 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001252 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 }
1254
1255 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1256 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1257 {
1258 _engineStatisticsPtr->SetLastError(
1259 VE_APM_ERROR, kTraceWarning,
1260 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001261 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 }
1263
1264 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1265 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1266 {
1267 _engineStatisticsPtr->SetLastError(
1268 VE_APM_ERROR, kTraceWarning,
1269 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001270 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 }
1272 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1273 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1274 {
1275 _engineStatisticsPtr->SetLastError(
1276 VE_APM_ERROR, kTraceWarning,
1277 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001278 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001279 }
1280
1281 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1282 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1283 {
1284 _engineStatisticsPtr->SetLastError(
1285 VE_APM_ERROR, kTraceWarning,
1286 "Init() failed to set AGC mode for far-end AP module");
1287 }
1288 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1289 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1290 {
1291 _engineStatisticsPtr->SetLastError(
1292 VE_APM_ERROR, kTraceWarning,
1293 "Init() failed to set AGC state for far-end AP module");
1294 }
1295
1296 return 0;
1297}
1298
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001299int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001300Channel::SetEngineInformation(Statistics& engineStatistics,
1301 OutputMixer& outputMixer,
1302 voe::TransmitMixer& transmitMixer,
1303 ProcessThread& moduleProcessThread,
1304 AudioDeviceModule& audioDeviceModule,
1305 VoiceEngineObserver* voiceEngineObserver,
1306 CriticalSectionWrapper* callbackCritSect)
1307{
1308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1309 "Channel::SetEngineInformation()");
1310 _engineStatisticsPtr = &engineStatistics;
1311 _outputMixerPtr = &outputMixer;
1312 _transmitMixerPtr = &transmitMixer,
1313 _moduleProcessThreadPtr = &moduleProcessThread;
1314 _audioDeviceModulePtr = &audioDeviceModule;
1315 _voiceEngineObserverPtr = voiceEngineObserver;
1316 _callbackCritSectPtr = callbackCritSect;
1317 return 0;
1318}
1319
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001320int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001321Channel::UpdateLocalTimeStamp()
1322{
1323
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001324 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 return 0;
1326}
1327
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001328int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001329Channel::StartPlayout()
1330{
1331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1332 "Channel::StartPlayout()");
1333 if (_playing)
1334 {
1335 return 0;
1336 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001337
1338 if (!_externalMixing) {
1339 // Add participant as candidates for mixing.
1340 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1341 {
1342 _engineStatisticsPtr->SetLastError(
1343 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1344 "StartPlayout() failed to add participant to mixer");
1345 return -1;
1346 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 }
1348
1349 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001350
1351 if (RegisterFilePlayingToMixer() != 0)
1352 return -1;
1353
niklase@google.com470e71d2011-07-07 08:21:25 +00001354 return 0;
1355}
1356
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001357int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001358Channel::StopPlayout()
1359{
1360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1361 "Channel::StopPlayout()");
1362 if (!_playing)
1363 {
1364 return 0;
1365 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001366
1367 if (!_externalMixing) {
1368 // Remove participant as candidates for mixing
1369 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1370 {
1371 _engineStatisticsPtr->SetLastError(
1372 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1373 "StopPlayout() failed to remove participant from mixer");
1374 return -1;
1375 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 }
1377
1378 _playing = false;
1379 _outputAudioLevel.Clear();
1380
1381 return 0;
1382}
1383
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001384int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001385Channel::StartSend()
1386{
1387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1388 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001389 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001390 // A lock is needed because |_sending| can be accessed or modified by
1391 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001392 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001393
1394 if (_sending)
1395 {
1396 return 0;
1397 }
1398 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001399 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001400
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001401 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001402 {
1403 _engineStatisticsPtr->SetLastError(
1404 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1405 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001406 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001407 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001408 return -1;
1409 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001410
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 return 0;
1412}
1413
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001414int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001415Channel::StopSend()
1416{
1417 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1418 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001420 // A lock is needed because |_sending| can be accessed or modified by
1421 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001422 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001423
1424 if (!_sending)
1425 {
1426 return 0;
1427 }
1428 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001430
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 // Reset sending SSRC and sequence number and triggers direct transmission
1432 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001433 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1434 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 {
1436 _engineStatisticsPtr->SetLastError(
1437 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1438 "StartSend() RTP/RTCP failed to stop sending");
1439 }
1440
niklase@google.com470e71d2011-07-07 08:21:25 +00001441 return 0;
1442}
1443
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001445Channel::StartReceiving()
1446{
1447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1448 "Channel::StartReceiving()");
1449 if (_receiving)
1450 {
1451 return 0;
1452 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001453 _receiving = true;
1454 _numberOfDiscardedPackets = 0;
1455 return 0;
1456}
1457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001458int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001459Channel::StopReceiving()
1460{
1461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1462 "Channel::StopReceiving()");
1463 if (!_receiving)
1464 {
1465 return 0;
1466 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001467
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001468 // Recover DTMF detection status.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001469 int32_t ret = _rtpRtcpModule->SetTelephoneEventForwardToDecoder(true);
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001470 if (ret != 0) {
1471 _engineStatisticsPtr->SetLastError(
1472 VE_INVALID_OPERATION, kTraceWarning,
1473 "StopReceiving() failed to restore telephone-event status.");
1474 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 RegisterReceiveCodecsToRTPModule();
1476 _receiving = false;
1477 return 0;
1478}
1479
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001480int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001481Channel::SetNetEQPlayoutMode(NetEqModes mode)
1482{
1483 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1484 "Channel::SetNetEQPlayoutMode()");
1485 AudioPlayoutMode playoutMode(voice);
1486 switch (mode)
1487 {
1488 case kNetEqDefault:
1489 playoutMode = voice;
1490 break;
1491 case kNetEqStreaming:
1492 playoutMode = streaming;
1493 break;
1494 case kNetEqFax:
1495 playoutMode = fax;
1496 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001497 case kNetEqOff:
1498 playoutMode = off;
1499 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 }
1501 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1502 {
1503 _engineStatisticsPtr->SetLastError(
1504 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1505 "SetNetEQPlayoutMode() failed to set playout mode");
1506 return -1;
1507 }
1508 return 0;
1509}
1510
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001511int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001512Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1513{
1514 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1515 switch (playoutMode)
1516 {
1517 case voice:
1518 mode = kNetEqDefault;
1519 break;
1520 case streaming:
1521 mode = kNetEqStreaming;
1522 break;
1523 case fax:
1524 mode = kNetEqFax;
1525 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001526 case off:
1527 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001528 }
1529 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1530 VoEId(_instanceId,_channelId),
1531 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1532 return 0;
1533}
1534
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001535int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001536Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1537{
1538 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1539 "Channel::SetOnHoldStatus()");
1540 if (mode == kHoldSendAndPlay)
1541 {
1542 _outputIsOnHold = enable;
1543 _inputIsOnHold = enable;
1544 }
1545 else if (mode == kHoldPlayOnly)
1546 {
1547 _outputIsOnHold = enable;
1548 }
1549 if (mode == kHoldSendOnly)
1550 {
1551 _inputIsOnHold = enable;
1552 }
1553 return 0;
1554}
1555
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001556int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001557Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1558{
1559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1560 "Channel::GetOnHoldStatus()");
1561 enabled = (_outputIsOnHold || _inputIsOnHold);
1562 if (_outputIsOnHold && _inputIsOnHold)
1563 {
1564 mode = kHoldSendAndPlay;
1565 }
1566 else if (_outputIsOnHold && !_inputIsOnHold)
1567 {
1568 mode = kHoldPlayOnly;
1569 }
1570 else if (!_outputIsOnHold && _inputIsOnHold)
1571 {
1572 mode = kHoldSendOnly;
1573 }
1574 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1575 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1576 enabled, mode);
1577 return 0;
1578}
1579
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001580int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001581Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1582{
1583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1584 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001585 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001586
1587 if (_voiceEngineObserverPtr)
1588 {
1589 _engineStatisticsPtr->SetLastError(
1590 VE_INVALID_OPERATION, kTraceError,
1591 "RegisterVoiceEngineObserver() observer already enabled");
1592 return -1;
1593 }
1594 _voiceEngineObserverPtr = &observer;
1595 return 0;
1596}
1597
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001598int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001599Channel::DeRegisterVoiceEngineObserver()
1600{
1601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1602 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001603 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001604
1605 if (!_voiceEngineObserverPtr)
1606 {
1607 _engineStatisticsPtr->SetLastError(
1608 VE_INVALID_OPERATION, kTraceWarning,
1609 "DeRegisterVoiceEngineObserver() observer already disabled");
1610 return 0;
1611 }
1612 _voiceEngineObserverPtr = NULL;
1613 return 0;
1614}
1615
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001616int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001617Channel::GetSendCodec(CodecInst& codec)
1618{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001619 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001620}
1621
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001622int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001623Channel::GetRecCodec(CodecInst& codec)
1624{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001625 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001626}
1627
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001628int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001629Channel::SetSendCodec(const CodecInst& codec)
1630{
1631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1632 "Channel::SetSendCodec()");
1633
1634 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1635 {
1636 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1637 "SetSendCodec() failed to register codec to ACM");
1638 return -1;
1639 }
1640
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001641 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001642 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001643 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1644 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001645 {
1646 WEBRTC_TRACE(
1647 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1648 "SetSendCodec() failed to register codec to"
1649 " RTP/RTCP module");
1650 return -1;
1651 }
1652 }
1653
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001654 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001655 {
1656 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1657 "SetSendCodec() failed to set audio packet size");
1658 return -1;
1659 }
1660
1661 return 0;
1662}
1663
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001664int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001665Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1666{
1667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1668 "Channel::SetVADStatus(mode=%d)", mode);
1669 // To disable VAD, DTX must be disabled too
1670 disableDTX = ((enableVAD == false) ? true : disableDTX);
1671 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1672 {
1673 _engineStatisticsPtr->SetLastError(
1674 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1675 "SetVADStatus() failed to set VAD");
1676 return -1;
1677 }
1678 return 0;
1679}
1680
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001681int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001682Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1683{
1684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001686 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001687 {
1688 _engineStatisticsPtr->SetLastError(
1689 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1690 "GetVADStatus() failed to get VAD status");
1691 return -1;
1692 }
1693 disabledDTX = !disabledDTX;
1694 return 0;
1695}
1696
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001697int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001698Channel::SetRecPayloadType(const CodecInst& codec)
1699{
1700 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1701 "Channel::SetRecPayloadType()");
1702
1703 if (_playing)
1704 {
1705 _engineStatisticsPtr->SetLastError(
1706 VE_ALREADY_PLAYING, kTraceError,
1707 "SetRecPayloadType() unable to set PT while playing");
1708 return -1;
1709 }
1710 if (_receiving)
1711 {
1712 _engineStatisticsPtr->SetLastError(
1713 VE_ALREADY_LISTENING, kTraceError,
1714 "SetRecPayloadType() unable to set PT while listening");
1715 return -1;
1716 }
1717
1718 if (codec.pltype == -1)
1719 {
1720 // De-register the selected codec (RTP/RTCP module and ACM)
1721
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001722 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001723 CodecInst rxCodec = codec;
1724
1725 // Get payload type for the given codec
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001726 _rtpRtcpModule->ReceivePayloadType(rxCodec, &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001727 rxCodec.pltype = pltype;
1728
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001729 if (_rtpRtcpModule->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001730 {
1731 _engineStatisticsPtr->SetLastError(
1732 VE_RTP_RTCP_MODULE_ERROR,
1733 kTraceError,
1734 "SetRecPayloadType() RTP/RTCP-module deregistration "
1735 "failed");
1736 return -1;
1737 }
1738 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1739 {
1740 _engineStatisticsPtr->SetLastError(
1741 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1742 "SetRecPayloadType() ACM deregistration failed - 1");
1743 return -1;
1744 }
1745 return 0;
1746 }
1747
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001748 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001749 {
1750 // First attempt to register failed => de-register and try again
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001751 _rtpRtcpModule->DeRegisterReceivePayload(codec.pltype);
1752 if (_rtpRtcpModule->RegisterReceivePayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001753 {
1754 _engineStatisticsPtr->SetLastError(
1755 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1756 "SetRecPayloadType() RTP/RTCP-module registration failed");
1757 return -1;
1758 }
1759 }
1760 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1761 {
1762 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1763 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1764 {
1765 _engineStatisticsPtr->SetLastError(
1766 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1767 "SetRecPayloadType() ACM registration failed - 1");
1768 return -1;
1769 }
1770 }
1771 return 0;
1772}
1773
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001774int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001775Channel::GetRecPayloadType(CodecInst& codec)
1776{
1777 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1778 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001779 int8_t payloadType(-1);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001780 if (_rtpRtcpModule->ReceivePayloadType(codec, &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 {
1782 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001783 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001784 "GetRecPayloadType() failed to retrieve RX payload type");
1785 return -1;
1786 }
1787 codec.pltype = payloadType;
1788 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1789 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1790 return 0;
1791}
1792
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001793int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001794Channel::SetAMREncFormat(AmrMode mode)
1795{
1796 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1797 "Channel::SetAMREncFormat()");
1798
1799 // ACM doesn't support AMR
1800 return -1;
1801}
1802
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001803int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001804Channel::SetAMRDecFormat(AmrMode mode)
1805{
1806 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1807 "Channel::SetAMRDecFormat()");
1808
1809 // ACM doesn't support AMR
1810 return -1;
1811}
1812
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001813int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001814Channel::SetAMRWbEncFormat(AmrMode mode)
1815{
1816 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1817 "Channel::SetAMRWbEncFormat()");
1818
1819 // ACM doesn't support AMR
1820 return -1;
1821
1822}
1823
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001824int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001825Channel::SetAMRWbDecFormat(AmrMode mode)
1826{
1827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1828 "Channel::SetAMRWbDecFormat()");
1829
1830 // ACM doesn't support AMR
1831 return -1;
1832}
1833
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001834int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001835Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1836{
1837 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1838 "Channel::SetSendCNPayloadType()");
1839
1840 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001841 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001842 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001843 if (frequency == kFreq32000Hz)
1844 samplingFreqHz = 32000;
1845 else if (frequency == kFreq16000Hz)
1846 samplingFreqHz = 16000;
1847
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001848 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001849 {
1850 _engineStatisticsPtr->SetLastError(
1851 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1852 "SetSendCNPayloadType() failed to retrieve default CN codec "
1853 "settings");
1854 return -1;
1855 }
1856
1857 // Modify the payload type (must be set to dynamic range)
1858 codec.pltype = type;
1859
1860 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1861 {
1862 _engineStatisticsPtr->SetLastError(
1863 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1864 "SetSendCNPayloadType() failed to register CN to ACM");
1865 return -1;
1866 }
1867
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001868 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001869 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001870 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1871 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001872 {
1873 _engineStatisticsPtr->SetLastError(
1874 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1875 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1876 "module");
1877 return -1;
1878 }
1879 }
1880 return 0;
1881}
1882
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001883int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001884Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1885{
1886 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1887 "Channel::SetISACInitTargetRate()");
1888
1889 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001890 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001891 {
1892 _engineStatisticsPtr->SetLastError(
1893 VE_CODEC_ERROR, kTraceError,
1894 "SetISACInitTargetRate() failed to retrieve send codec");
1895 return -1;
1896 }
1897 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1898 {
1899 // This API is only valid if iSAC is setup to run in channel-adaptive
1900 // mode.
1901 // We do not validate the adaptive mode here. It is done later in the
1902 // ConfigISACBandwidthEstimator() API.
1903 _engineStatisticsPtr->SetLastError(
1904 VE_CODEC_ERROR, kTraceError,
1905 "SetISACInitTargetRate() send codec is not iSAC");
1906 return -1;
1907 }
1908
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001909 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001910 if (16000 == sendCodec.plfreq)
1911 {
1912 // Note that 0 is a valid and corresponds to "use default
1913 if ((rateBps != 0 &&
1914 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1915 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1916 {
1917 _engineStatisticsPtr->SetLastError(
1918 VE_INVALID_ARGUMENT, kTraceError,
1919 "SetISACInitTargetRate() invalid target rate - 1");
1920 return -1;
1921 }
1922 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001923 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001924 }
1925 else if (32000 == sendCodec.plfreq)
1926 {
1927 if ((rateBps != 0 &&
1928 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1929 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1930 {
1931 _engineStatisticsPtr->SetLastError(
1932 VE_INVALID_ARGUMENT, kTraceError,
1933 "SetISACInitTargetRate() invalid target rate - 2");
1934 return -1;
1935 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001936 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001937 }
1938
1939 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1940 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1941 {
1942 _engineStatisticsPtr->SetLastError(
1943 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1944 "SetISACInitTargetRate() iSAC BWE config failed");
1945 return -1;
1946 }
1947
1948 return 0;
1949}
1950
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001951int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001952Channel::SetISACMaxRate(int rateBps)
1953{
1954 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1955 "Channel::SetISACMaxRate()");
1956
1957 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001958 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001959 {
1960 _engineStatisticsPtr->SetLastError(
1961 VE_CODEC_ERROR, kTraceError,
1962 "SetISACMaxRate() failed to retrieve send codec");
1963 return -1;
1964 }
1965 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1966 {
1967 // This API is only valid if iSAC is selected as sending codec.
1968 _engineStatisticsPtr->SetLastError(
1969 VE_CODEC_ERROR, kTraceError,
1970 "SetISACMaxRate() send codec is not iSAC");
1971 return -1;
1972 }
1973 if (16000 == sendCodec.plfreq)
1974 {
1975 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1976 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1977 {
1978 _engineStatisticsPtr->SetLastError(
1979 VE_INVALID_ARGUMENT, kTraceError,
1980 "SetISACMaxRate() invalid max rate - 1");
1981 return -1;
1982 }
1983 }
1984 else if (32000 == sendCodec.plfreq)
1985 {
1986 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1987 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1988 {
1989 _engineStatisticsPtr->SetLastError(
1990 VE_INVALID_ARGUMENT, kTraceError,
1991 "SetISACMaxRate() invalid max rate - 2");
1992 return -1;
1993 }
1994 }
1995 if (_sending)
1996 {
1997 _engineStatisticsPtr->SetLastError(
1998 VE_SENDING, kTraceError,
1999 "SetISACMaxRate() unable to set max rate while sending");
2000 return -1;
2001 }
2002
2003 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2004 // and non-adaptive mode)
2005 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2006 {
2007 _engineStatisticsPtr->SetLastError(
2008 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2009 "SetISACMaxRate() failed to set max rate");
2010 return -1;
2011 }
2012
2013 return 0;
2014}
2015
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002016int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002017Channel::SetISACMaxPayloadSize(int sizeBytes)
2018{
2019 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2020 "Channel::SetISACMaxPayloadSize()");
2021 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002022 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002023 {
2024 _engineStatisticsPtr->SetLastError(
2025 VE_CODEC_ERROR, kTraceError,
2026 "SetISACMaxPayloadSize() failed to retrieve send codec");
2027 return -1;
2028 }
2029 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2030 {
2031 _engineStatisticsPtr->SetLastError(
2032 VE_CODEC_ERROR, kTraceError,
2033 "SetISACMaxPayloadSize() send codec is not iSAC");
2034 return -1;
2035 }
2036 if (16000 == sendCodec.plfreq)
2037 {
2038 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2039 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2040 {
2041 _engineStatisticsPtr->SetLastError(
2042 VE_INVALID_ARGUMENT, kTraceError,
2043 "SetISACMaxPayloadSize() invalid max payload - 1");
2044 return -1;
2045 }
2046 }
2047 else if (32000 == sendCodec.plfreq)
2048 {
2049 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2050 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2051 {
2052 _engineStatisticsPtr->SetLastError(
2053 VE_INVALID_ARGUMENT, kTraceError,
2054 "SetISACMaxPayloadSize() invalid max payload - 2");
2055 return -1;
2056 }
2057 }
2058 if (_sending)
2059 {
2060 _engineStatisticsPtr->SetLastError(
2061 VE_SENDING, kTraceError,
2062 "SetISACMaxPayloadSize() unable to set max rate while sending");
2063 return -1;
2064 }
2065
2066 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2067 {
2068 _engineStatisticsPtr->SetLastError(
2069 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2070 "SetISACMaxPayloadSize() failed to set max payload size");
2071 return -1;
2072 }
2073 return 0;
2074}
2075
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002076int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002077{
2078 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2079 "Channel::RegisterExternalTransport()");
2080
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002081 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002082
niklase@google.com470e71d2011-07-07 08:21:25 +00002083 if (_externalTransport)
2084 {
2085 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2086 kTraceError,
2087 "RegisterExternalTransport() external transport already enabled");
2088 return -1;
2089 }
2090 _externalTransport = true;
2091 _transportPtr = &transport;
2092 return 0;
2093}
2094
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002095int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002096Channel::DeRegisterExternalTransport()
2097{
2098 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2099 "Channel::DeRegisterExternalTransport()");
2100
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002101 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002102
niklase@google.com470e71d2011-07-07 08:21:25 +00002103 if (!_transportPtr)
2104 {
2105 _engineStatisticsPtr->SetLastError(
2106 VE_INVALID_OPERATION, kTraceWarning,
2107 "DeRegisterExternalTransport() external transport already "
2108 "disabled");
2109 return 0;
2110 }
2111 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002112 _transportPtr = NULL;
2113 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2114 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002115 return 0;
2116}
2117
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002118int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002119 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2120 "Channel::ReceivedRTPPacket()");
2121
2122 // Store playout timestamp for the received RTP packet
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002123 uint32_t playoutTimestamp(0);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002124 if (GetPlayoutTimeStamp(playoutTimestamp) == 0) {
2125 _playoutTimeStampRTP = playoutTimestamp;
2126 }
2127
2128 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002129 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2130 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002131 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2132 VoEId(_instanceId,_channelId),
2133 "Channel::SendPacket() RTP dump to input file failed");
2134 }
2135
2136 // Deliver RTP packet to RTP/RTCP module for parsing
2137 // The packet will be pushed back to the channel thru the
2138 // OnReceivedPayloadData callback so we don't push it to the ACM here
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002139 if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
2140 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002141 _engineStatisticsPtr->SetLastError(
2142 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2143 "Channel::IncomingRTPPacket() RTP packet is invalid");
2144 }
2145 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002146}
2147
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002148int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002149 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2150 "Channel::ReceivedRTCPPacket()");
2151 // Store playout timestamp for the received RTCP packet
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002152 uint32_t playoutTimestamp(0);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002153 if (GetPlayoutTimeStamp(playoutTimestamp) == 0) {
2154 _playoutTimeStampRTCP = playoutTimestamp;
2155 }
2156
2157 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002158 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2159 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002160 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2161 VoEId(_instanceId,_channelId),
2162 "Channel::SendPacket() RTCP dump to input file failed");
2163 }
2164
2165 // Deliver RTCP packet to RTP/RTCP module for parsing
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002166 if (_rtpRtcpModule->IncomingPacket((const uint8_t*)data,
2167 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002168 _engineStatisticsPtr->SetLastError(
2169 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2170 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2171 }
2172 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002173}
2174
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002175int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002176Channel::SetPacketTimeoutNotification(bool enable, int timeoutSeconds)
2177{
2178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2179 "Channel::SetPacketTimeoutNotification()");
2180 if (enable)
2181 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002182 const uint32_t RTPtimeoutMS = 1000*timeoutSeconds;
2183 const uint32_t RTCPtimeoutMS = 0;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002184 _rtpRtcpModule->SetPacketTimeout(RTPtimeoutMS, RTCPtimeoutMS);
niklase@google.com470e71d2011-07-07 08:21:25 +00002185 _rtpPacketTimeOutIsEnabled = true;
2186 _rtpTimeOutSeconds = timeoutSeconds;
2187 }
2188 else
2189 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002190 _rtpRtcpModule->SetPacketTimeout(0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002191 _rtpPacketTimeOutIsEnabled = false;
2192 _rtpTimeOutSeconds = 0;
2193 }
2194 return 0;
2195}
2196
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002197int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002198Channel::GetPacketTimeoutNotification(bool& enabled, int& timeoutSeconds)
2199{
2200 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2201 "Channel::GetPacketTimeoutNotification()");
2202 enabled = _rtpPacketTimeOutIsEnabled;
2203 if (enabled)
2204 {
2205 timeoutSeconds = _rtpTimeOutSeconds;
2206 }
2207 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2208 "GetPacketTimeoutNotification() => enabled=%d,"
2209 " timeoutSeconds=%d",
2210 enabled, timeoutSeconds);
2211 return 0;
2212}
2213
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002214int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002215Channel::RegisterDeadOrAliveObserver(VoEConnectionObserver& observer)
2216{
2217 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2218 "Channel::RegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002219 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002220
2221 if (_connectionObserverPtr)
2222 {
2223 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION, kTraceError,
2224 "RegisterDeadOrAliveObserver() observer already enabled");
2225 return -1;
2226 }
2227
2228 _connectionObserverPtr = &observer;
2229 _connectionObserver = true;
2230
2231 return 0;
2232}
2233
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002234int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002235Channel::DeRegisterDeadOrAliveObserver()
2236{
2237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2238 "Channel::DeRegisterDeadOrAliveObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002239 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002240
2241 if (!_connectionObserverPtr)
2242 {
2243 _engineStatisticsPtr->SetLastError(
2244 VE_INVALID_OPERATION, kTraceWarning,
2245 "DeRegisterDeadOrAliveObserver() observer already disabled");
2246 return 0;
2247 }
2248
2249 _connectionObserver = false;
2250 _connectionObserverPtr = NULL;
2251
2252 return 0;
2253}
2254
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002255int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002256Channel::SetPeriodicDeadOrAliveStatus(bool enable, int sampleTimeSeconds)
2257{
2258 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2259 "Channel::SetPeriodicDeadOrAliveStatus()");
2260 if (!_connectionObserverPtr)
2261 {
2262 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
2263 "SetPeriodicDeadOrAliveStatus() connection observer has"
2264 " not been registered");
2265 }
2266 if (enable)
2267 {
2268 ResetDeadOrAliveCounters();
2269 }
2270 bool enabled(false);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002271 uint8_t currentSampleTimeSec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002272 // Store last state (will be used later if dead-or-alive is disabled).
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002273 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, currentSampleTimeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00002274 // Update the dead-or-alive state.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002275 if (_rtpRtcpModule->SetPeriodicDeadOrAliveStatus(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002276 enable, (uint8_t)sampleTimeSeconds) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002277 {
2278 _engineStatisticsPtr->SetLastError(
2279 VE_RTP_RTCP_MODULE_ERROR,
2280 kTraceError,
2281 "SetPeriodicDeadOrAliveStatus() failed to set dead-or-alive "
2282 "status");
2283 return -1;
2284 }
2285 if (!enable)
2286 {
2287 // Restore last utilized sample time.
2288 // Without this, the sample time would always be reset to default
2289 // (2 sec), each time dead-or-alived was disabled without sample-time
2290 // parameter.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002291 _rtpRtcpModule->SetPeriodicDeadOrAliveStatus(enable,
niklase@google.com470e71d2011-07-07 08:21:25 +00002292 currentSampleTimeSec);
2293 }
2294 return 0;
2295}
2296
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002297int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002298Channel::GetPeriodicDeadOrAliveStatus(bool& enabled, int& sampleTimeSeconds)
2299{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002300 _rtpRtcpModule->PeriodicDeadOrAliveStatus(
niklase@google.com470e71d2011-07-07 08:21:25 +00002301 enabled,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002302 (uint8_t&)sampleTimeSeconds);
niklase@google.com470e71d2011-07-07 08:21:25 +00002303 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
2304 "GetPeriodicDeadOrAliveStatus() => enabled=%d,"
2305 " sampleTimeSeconds=%d",
2306 enabled, sampleTimeSeconds);
2307 return 0;
2308}
2309
niklase@google.com470e71d2011-07-07 08:21:25 +00002310int Channel::StartPlayingFileLocally(const char* fileName,
2311 const bool loop,
2312 const FileFormats format,
2313 const int startPosition,
2314 const float volumeScaling,
2315 const int stopPosition,
2316 const CodecInst* codecInst)
2317{
2318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2319 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2320 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2321 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2322 startPosition, stopPosition);
2323
2324 if (_outputFilePlaying)
2325 {
2326 _engineStatisticsPtr->SetLastError(
2327 VE_ALREADY_PLAYING, kTraceError,
2328 "StartPlayingFileLocally() is already playing");
2329 return -1;
2330 }
2331
niklase@google.com470e71d2011-07-07 08:21:25 +00002332 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002333 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002334
2335 if (_outputFilePlayerPtr)
2336 {
2337 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2338 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2339 _outputFilePlayerPtr = NULL;
2340 }
2341
2342 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2343 _outputFilePlayerId, (const FileFormats)format);
2344
2345 if (_outputFilePlayerPtr == NULL)
2346 {
2347 _engineStatisticsPtr->SetLastError(
2348 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002349 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002350 return -1;
2351 }
2352
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002353 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002354
2355 if (_outputFilePlayerPtr->StartPlayingFile(
2356 fileName,
2357 loop,
2358 startPosition,
2359 volumeScaling,
2360 notificationTime,
2361 stopPosition,
2362 (const CodecInst*)codecInst) != 0)
2363 {
2364 _engineStatisticsPtr->SetLastError(
2365 VE_BAD_FILE, kTraceError,
2366 "StartPlayingFile() failed to start file playout");
2367 _outputFilePlayerPtr->StopPlayingFile();
2368 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2369 _outputFilePlayerPtr = NULL;
2370 return -1;
2371 }
2372 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2373 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002374 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002375
2376 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002377 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002378
2379 return 0;
2380}
2381
2382int Channel::StartPlayingFileLocally(InStream* stream,
2383 const FileFormats format,
2384 const int startPosition,
2385 const float volumeScaling,
2386 const int stopPosition,
2387 const CodecInst* codecInst)
2388{
2389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2390 "Channel::StartPlayingFileLocally(format=%d,"
2391 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2392 format, volumeScaling, startPosition, stopPosition);
2393
2394 if(stream == NULL)
2395 {
2396 _engineStatisticsPtr->SetLastError(
2397 VE_BAD_FILE, kTraceError,
2398 "StartPlayingFileLocally() NULL as input stream");
2399 return -1;
2400 }
2401
2402
2403 if (_outputFilePlaying)
2404 {
2405 _engineStatisticsPtr->SetLastError(
2406 VE_ALREADY_PLAYING, kTraceError,
2407 "StartPlayingFileLocally() is already playing");
2408 return -1;
2409 }
2410
niklase@google.com470e71d2011-07-07 08:21:25 +00002411 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002412 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002413
2414 // Destroy the old instance
2415 if (_outputFilePlayerPtr)
2416 {
2417 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2418 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2419 _outputFilePlayerPtr = NULL;
2420 }
2421
2422 // Create the instance
2423 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2424 _outputFilePlayerId,
2425 (const FileFormats)format);
2426
2427 if (_outputFilePlayerPtr == NULL)
2428 {
2429 _engineStatisticsPtr->SetLastError(
2430 VE_INVALID_ARGUMENT, kTraceError,
2431 "StartPlayingFileLocally() filePlayer format isnot correct");
2432 return -1;
2433 }
2434
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002435 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002436
2437 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2438 volumeScaling,
2439 notificationTime,
2440 stopPosition, codecInst) != 0)
2441 {
2442 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2443 "StartPlayingFile() failed to "
2444 "start file playout");
2445 _outputFilePlayerPtr->StopPlayingFile();
2446 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2447 _outputFilePlayerPtr = NULL;
2448 return -1;
2449 }
2450 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2451 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002452 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002453
2454 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002455 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002456
niklase@google.com470e71d2011-07-07 08:21:25 +00002457 return 0;
2458}
2459
2460int Channel::StopPlayingFileLocally()
2461{
2462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2463 "Channel::StopPlayingFileLocally()");
2464
2465 if (!_outputFilePlaying)
2466 {
2467 _engineStatisticsPtr->SetLastError(
2468 VE_INVALID_OPERATION, kTraceWarning,
2469 "StopPlayingFileLocally() isnot playing");
2470 return 0;
2471 }
2472
niklase@google.com470e71d2011-07-07 08:21:25 +00002473 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002474 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002475
2476 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2477 {
2478 _engineStatisticsPtr->SetLastError(
2479 VE_STOP_RECORDING_FAILED, kTraceError,
2480 "StopPlayingFile() could not stop playing");
2481 return -1;
2482 }
2483 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2484 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2485 _outputFilePlayerPtr = NULL;
2486 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002487 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002488 // _fileCritSect cannot be taken while calling
2489 // SetAnonymousMixibilityStatus. Refer to comments in
2490 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002491 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2492 {
2493 _engineStatisticsPtr->SetLastError(
2494 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002495 "StopPlayingFile() failed to stop participant from playing as"
2496 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002497 return -1;
2498 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002499
2500 return 0;
2501}
2502
2503int Channel::IsPlayingFileLocally() const
2504{
2505 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2506 "Channel::IsPlayingFileLocally()");
2507
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002508 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002509}
2510
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002511int Channel::RegisterFilePlayingToMixer()
2512{
2513 // Return success for not registering for file playing to mixer if:
2514 // 1. playing file before playout is started on that channel.
2515 // 2. starting playout without file playing on that channel.
2516 if (!_playing || !_outputFilePlaying)
2517 {
2518 return 0;
2519 }
2520
2521 // |_fileCritSect| cannot be taken while calling
2522 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2523 // frames can be pulled by the mixer. Since the frames are generated from
2524 // the file, _fileCritSect will be taken. This would result in a deadlock.
2525 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2526 {
2527 CriticalSectionScoped cs(&_fileCritSect);
2528 _outputFilePlaying = false;
2529 _engineStatisticsPtr->SetLastError(
2530 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2531 "StartPlayingFile() failed to add participant as file to mixer");
2532 _outputFilePlayerPtr->StopPlayingFile();
2533 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2534 _outputFilePlayerPtr = NULL;
2535 return -1;
2536 }
2537
2538 return 0;
2539}
2540
niklase@google.com470e71d2011-07-07 08:21:25 +00002541int Channel::ScaleLocalFilePlayout(const float scale)
2542{
2543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2544 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2545
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002546 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002547
2548 if (!_outputFilePlaying)
2549 {
2550 _engineStatisticsPtr->SetLastError(
2551 VE_INVALID_OPERATION, kTraceError,
2552 "ScaleLocalFilePlayout() isnot playing");
2553 return -1;
2554 }
2555 if ((_outputFilePlayerPtr == NULL) ||
2556 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2557 {
2558 _engineStatisticsPtr->SetLastError(
2559 VE_BAD_ARGUMENT, kTraceError,
2560 "SetAudioScaling() failed to scale the playout");
2561 return -1;
2562 }
2563
2564 return 0;
2565}
2566
2567int Channel::GetLocalPlayoutPosition(int& positionMs)
2568{
2569 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2570 "Channel::GetLocalPlayoutPosition(position=?)");
2571
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002572 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002573
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002574 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002575
2576 if (_outputFilePlayerPtr == NULL)
2577 {
2578 _engineStatisticsPtr->SetLastError(
2579 VE_INVALID_OPERATION, kTraceError,
2580 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2581 return -1;
2582 }
2583
2584 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2585 {
2586 _engineStatisticsPtr->SetLastError(
2587 VE_BAD_FILE, kTraceError,
2588 "GetLocalPlayoutPosition() failed");
2589 return -1;
2590 }
2591 positionMs = position;
2592
2593 return 0;
2594}
2595
2596int Channel::StartPlayingFileAsMicrophone(const char* fileName,
2597 const bool loop,
2598 const FileFormats format,
2599 const int startPosition,
2600 const float volumeScaling,
2601 const int stopPosition,
2602 const CodecInst* codecInst)
2603{
2604 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2605 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2606 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2607 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2608 startPosition, stopPosition);
2609
2610 if (_inputFilePlaying)
2611 {
2612 _engineStatisticsPtr->SetLastError(
2613 VE_ALREADY_PLAYING, kTraceWarning,
2614 "StartPlayingFileAsMicrophone() filePlayer is playing");
2615 return 0;
2616 }
2617
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002618 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002619
2620 // Destroy the old instance
2621 if (_inputFilePlayerPtr)
2622 {
2623 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2624 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2625 _inputFilePlayerPtr = NULL;
2626 }
2627
2628 // Create the instance
2629 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2630 _inputFilePlayerId, (const FileFormats)format);
2631
2632 if (_inputFilePlayerPtr == NULL)
2633 {
2634 _engineStatisticsPtr->SetLastError(
2635 VE_INVALID_ARGUMENT, kTraceError,
2636 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2637 return -1;
2638 }
2639
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002640 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002641
2642 if (_inputFilePlayerPtr->StartPlayingFile(
2643 fileName,
2644 loop,
2645 startPosition,
2646 volumeScaling,
2647 notificationTime,
2648 stopPosition,
2649 (const CodecInst*)codecInst) != 0)
2650 {
2651 _engineStatisticsPtr->SetLastError(
2652 VE_BAD_FILE, kTraceError,
2653 "StartPlayingFile() failed to start file playout");
2654 _inputFilePlayerPtr->StopPlayingFile();
2655 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2656 _inputFilePlayerPtr = NULL;
2657 return -1;
2658 }
2659 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2660 _inputFilePlaying = true;
2661
2662 return 0;
2663}
2664
2665int Channel::StartPlayingFileAsMicrophone(InStream* stream,
2666 const FileFormats format,
2667 const int startPosition,
2668 const float volumeScaling,
2669 const int stopPosition,
2670 const CodecInst* codecInst)
2671{
2672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2673 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2674 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2675 format, volumeScaling, startPosition, stopPosition);
2676
2677 if(stream == NULL)
2678 {
2679 _engineStatisticsPtr->SetLastError(
2680 VE_BAD_FILE, kTraceError,
2681 "StartPlayingFileAsMicrophone NULL as input stream");
2682 return -1;
2683 }
2684
2685 if (_inputFilePlaying)
2686 {
2687 _engineStatisticsPtr->SetLastError(
2688 VE_ALREADY_PLAYING, kTraceWarning,
2689 "StartPlayingFileAsMicrophone() is playing");
2690 return 0;
2691 }
2692
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002693 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002694
2695 // Destroy the old instance
2696 if (_inputFilePlayerPtr)
2697 {
2698 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2699 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2700 _inputFilePlayerPtr = NULL;
2701 }
2702
2703 // Create the instance
2704 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2705 _inputFilePlayerId, (const FileFormats)format);
2706
2707 if (_inputFilePlayerPtr == NULL)
2708 {
2709 _engineStatisticsPtr->SetLastError(
2710 VE_INVALID_ARGUMENT, kTraceError,
2711 "StartPlayingInputFile() filePlayer format isnot correct");
2712 return -1;
2713 }
2714
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002715 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002716
2717 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2718 volumeScaling, notificationTime,
2719 stopPosition, codecInst) != 0)
2720 {
2721 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2722 "StartPlayingFile() failed to start "
2723 "file playout");
2724 _inputFilePlayerPtr->StopPlayingFile();
2725 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2726 _inputFilePlayerPtr = NULL;
2727 return -1;
2728 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002729
niklase@google.com470e71d2011-07-07 08:21:25 +00002730 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2731 _inputFilePlaying = true;
2732
2733 return 0;
2734}
2735
2736int Channel::StopPlayingFileAsMicrophone()
2737{
2738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2739 "Channel::StopPlayingFileAsMicrophone()");
2740
2741 if (!_inputFilePlaying)
2742 {
2743 _engineStatisticsPtr->SetLastError(
2744 VE_INVALID_OPERATION, kTraceWarning,
2745 "StopPlayingFileAsMicrophone() isnot playing");
2746 return 0;
2747 }
2748
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002749 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002750 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2751 {
2752 _engineStatisticsPtr->SetLastError(
2753 VE_STOP_RECORDING_FAILED, kTraceError,
2754 "StopPlayingFile() could not stop playing");
2755 return -1;
2756 }
2757 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2758 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2759 _inputFilePlayerPtr = NULL;
2760 _inputFilePlaying = false;
2761
2762 return 0;
2763}
2764
2765int Channel::IsPlayingFileAsMicrophone() const
2766{
2767 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2768 "Channel::IsPlayingFileAsMicrophone()");
2769
2770 return _inputFilePlaying;
2771}
2772
2773int Channel::ScaleFileAsMicrophonePlayout(const float scale)
2774{
2775 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2776 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2777
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002778 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002779
2780 if (!_inputFilePlaying)
2781 {
2782 _engineStatisticsPtr->SetLastError(
2783 VE_INVALID_OPERATION, kTraceError,
2784 "ScaleFileAsMicrophonePlayout() isnot playing");
2785 return -1;
2786 }
2787
2788 if ((_inputFilePlayerPtr == NULL) ||
2789 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2790 {
2791 _engineStatisticsPtr->SetLastError(
2792 VE_BAD_ARGUMENT, kTraceError,
2793 "SetAudioScaling() failed to scale playout");
2794 return -1;
2795 }
2796
2797 return 0;
2798}
2799
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002800int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002801 const CodecInst* codecInst)
2802{
2803 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2804 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2805
2806 if (_outputFileRecording)
2807 {
2808 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2809 "StartRecordingPlayout() is already recording");
2810 return 0;
2811 }
2812
2813 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002814 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002815 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2816
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002817 if ((codecInst != NULL) &&
2818 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002819 {
2820 _engineStatisticsPtr->SetLastError(
2821 VE_BAD_ARGUMENT, kTraceError,
2822 "StartRecordingPlayout() invalid compression");
2823 return(-1);
2824 }
2825 if(codecInst == NULL)
2826 {
2827 format = kFileFormatPcm16kHzFile;
2828 codecInst=&dummyCodec;
2829 }
2830 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2831 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2832 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2833 {
2834 format = kFileFormatWavFile;
2835 }
2836 else
2837 {
2838 format = kFileFormatCompressedFile;
2839 }
2840
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002841 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002842
2843 // Destroy the old instance
2844 if (_outputFileRecorderPtr)
2845 {
2846 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2847 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2848 _outputFileRecorderPtr = NULL;
2849 }
2850
2851 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2852 _outputFileRecorderId, (const FileFormats)format);
2853 if (_outputFileRecorderPtr == NULL)
2854 {
2855 _engineStatisticsPtr->SetLastError(
2856 VE_INVALID_ARGUMENT, kTraceError,
2857 "StartRecordingPlayout() fileRecorder format isnot correct");
2858 return -1;
2859 }
2860
2861 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2862 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2863 {
2864 _engineStatisticsPtr->SetLastError(
2865 VE_BAD_FILE, kTraceError,
2866 "StartRecordingAudioFile() failed to start file recording");
2867 _outputFileRecorderPtr->StopRecording();
2868 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2869 _outputFileRecorderPtr = NULL;
2870 return -1;
2871 }
2872 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2873 _outputFileRecording = true;
2874
2875 return 0;
2876}
2877
2878int Channel::StartRecordingPlayout(OutStream* stream,
2879 const CodecInst* codecInst)
2880{
2881 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2882 "Channel::StartRecordingPlayout()");
2883
2884 if (_outputFileRecording)
2885 {
2886 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2887 "StartRecordingPlayout() is already recording");
2888 return 0;
2889 }
2890
2891 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002892 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002893 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2894
2895 if (codecInst != NULL && codecInst->channels != 1)
2896 {
2897 _engineStatisticsPtr->SetLastError(
2898 VE_BAD_ARGUMENT, kTraceError,
2899 "StartRecordingPlayout() invalid compression");
2900 return(-1);
2901 }
2902 if(codecInst == NULL)
2903 {
2904 format = kFileFormatPcm16kHzFile;
2905 codecInst=&dummyCodec;
2906 }
2907 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2908 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2909 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2910 {
2911 format = kFileFormatWavFile;
2912 }
2913 else
2914 {
2915 format = kFileFormatCompressedFile;
2916 }
2917
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002918 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002919
2920 // Destroy the old instance
2921 if (_outputFileRecorderPtr)
2922 {
2923 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2924 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2925 _outputFileRecorderPtr = NULL;
2926 }
2927
2928 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2929 _outputFileRecorderId, (const FileFormats)format);
2930 if (_outputFileRecorderPtr == NULL)
2931 {
2932 _engineStatisticsPtr->SetLastError(
2933 VE_INVALID_ARGUMENT, kTraceError,
2934 "StartRecordingPlayout() fileRecorder format isnot correct");
2935 return -1;
2936 }
2937
2938 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2939 notificationTime) != 0)
2940 {
2941 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2942 "StartRecordingPlayout() failed to "
2943 "start file recording");
2944 _outputFileRecorderPtr->StopRecording();
2945 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2946 _outputFileRecorderPtr = NULL;
2947 return -1;
2948 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002949
niklase@google.com470e71d2011-07-07 08:21:25 +00002950 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2951 _outputFileRecording = true;
2952
2953 return 0;
2954}
2955
2956int Channel::StopRecordingPlayout()
2957{
2958 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2959 "Channel::StopRecordingPlayout()");
2960
2961 if (!_outputFileRecording)
2962 {
2963 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2964 "StopRecordingPlayout() isnot recording");
2965 return -1;
2966 }
2967
2968
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002969 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002970
2971 if (_outputFileRecorderPtr->StopRecording() != 0)
2972 {
2973 _engineStatisticsPtr->SetLastError(
2974 VE_STOP_RECORDING_FAILED, kTraceError,
2975 "StopRecording() could not stop recording");
2976 return(-1);
2977 }
2978 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2979 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2980 _outputFileRecorderPtr = NULL;
2981 _outputFileRecording = false;
2982
2983 return 0;
2984}
2985
2986void
2987Channel::SetMixWithMicStatus(bool mix)
2988{
2989 _mixFileWithMicrophone=mix;
2990}
2991
2992int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002993Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002994{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002995 int8_t currentLevel = _outputAudioLevel.Level();
2996 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002997 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2998 VoEId(_instanceId,_channelId),
2999 "GetSpeechOutputLevel() => level=%u", level);
3000 return 0;
3001}
3002
3003int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003004Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003005{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003006 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
3007 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00003008 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3009 VoEId(_instanceId,_channelId),
3010 "GetSpeechOutputLevelFullRange() => level=%u", level);
3011 return 0;
3012}
3013
3014int
3015Channel::SetMute(bool enable)
3016{
3017 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3018 "Channel::SetMute(enable=%d)", enable);
3019 _mute = enable;
3020 return 0;
3021}
3022
3023bool
3024Channel::Mute() const
3025{
3026 return _mute;
3027}
3028
3029int
3030Channel::SetOutputVolumePan(float left, float right)
3031{
3032 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3033 "Channel::SetOutputVolumePan()");
3034 _panLeft = left;
3035 _panRight = right;
3036 return 0;
3037}
3038
3039int
3040Channel::GetOutputVolumePan(float& left, float& right) const
3041{
3042 left = _panLeft;
3043 right = _panRight;
3044 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3045 VoEId(_instanceId,_channelId),
3046 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3047 return 0;
3048}
3049
3050int
3051Channel::SetChannelOutputVolumeScaling(float scaling)
3052{
3053 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3054 "Channel::SetChannelOutputVolumeScaling()");
3055 _outputGain = scaling;
3056 return 0;
3057}
3058
3059int
3060Channel::GetChannelOutputVolumeScaling(float& scaling) const
3061{
3062 scaling = _outputGain;
3063 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3064 VoEId(_instanceId,_channelId),
3065 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3066 return 0;
3067}
3068
niklase@google.com470e71d2011-07-07 08:21:25 +00003069int
3070Channel::RegisterExternalEncryption(Encryption& encryption)
3071{
3072 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3073 "Channel::RegisterExternalEncryption()");
3074
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003075 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003076
3077 if (_encryptionPtr)
3078 {
3079 _engineStatisticsPtr->SetLastError(
3080 VE_INVALID_OPERATION, kTraceError,
3081 "RegisterExternalEncryption() encryption already enabled");
3082 return -1;
3083 }
3084
3085 _encryptionPtr = &encryption;
3086
3087 _decrypting = true;
3088 _encrypting = true;
3089
3090 return 0;
3091}
3092
3093int
3094Channel::DeRegisterExternalEncryption()
3095{
3096 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3097 "Channel::DeRegisterExternalEncryption()");
3098
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003099 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003100
3101 if (!_encryptionPtr)
3102 {
3103 _engineStatisticsPtr->SetLastError(
3104 VE_INVALID_OPERATION, kTraceWarning,
3105 "DeRegisterExternalEncryption() encryption already disabled");
3106 return 0;
3107 }
3108
3109 _decrypting = false;
3110 _encrypting = false;
3111
3112 _encryptionPtr = NULL;
3113
3114 return 0;
3115}
3116
3117int Channel::SendTelephoneEventOutband(unsigned char eventCode,
3118 int lengthMs, int attenuationDb,
3119 bool playDtmfEvent)
3120{
3121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3122 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3123 playDtmfEvent);
3124
3125 _playOutbandDtmfEvent = playDtmfEvent;
3126
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003127 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003128 attenuationDb) != 0)
3129 {
3130 _engineStatisticsPtr->SetLastError(
3131 VE_SEND_DTMF_FAILED,
3132 kTraceWarning,
3133 "SendTelephoneEventOutband() failed to send event");
3134 return -1;
3135 }
3136 return 0;
3137}
3138
3139int Channel::SendTelephoneEventInband(unsigned char eventCode,
3140 int lengthMs,
3141 int attenuationDb,
3142 bool playDtmfEvent)
3143{
3144 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3145 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3146 playDtmfEvent);
3147
3148 _playInbandDtmfEvent = playDtmfEvent;
3149 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3150
3151 return 0;
3152}
3153
3154int
3155Channel::SetDtmfPlayoutStatus(bool enable)
3156{
3157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3158 "Channel::SetDtmfPlayoutStatus()");
3159 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3160 {
3161 _engineStatisticsPtr->SetLastError(
3162 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3163 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3164 return -1;
3165 }
3166 return 0;
3167}
3168
3169bool
3170Channel::DtmfPlayoutStatus() const
3171{
3172 return _audioCodingModule.DtmfPlayoutStatus();
3173}
3174
3175int
3176Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3177{
3178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3179 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003180 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003181 {
3182 _engineStatisticsPtr->SetLastError(
3183 VE_INVALID_ARGUMENT, kTraceError,
3184 "SetSendTelephoneEventPayloadType() invalid type");
3185 return -1;
3186 }
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003187 CodecInst codec;
3188 codec.plfreq = 8000;
3189 codec.pltype = type;
3190 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003191 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003192 {
3193 _engineStatisticsPtr->SetLastError(
3194 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3195 "SetSendTelephoneEventPayloadType() failed to register send"
3196 "payload type");
3197 return -1;
3198 }
3199 _sendTelephoneEventPayloadType = type;
3200 return 0;
3201}
3202
3203int
3204Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3205{
3206 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3207 "Channel::GetSendTelephoneEventPayloadType()");
3208 type = _sendTelephoneEventPayloadType;
3209 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3210 VoEId(_instanceId,_channelId),
3211 "GetSendTelephoneEventPayloadType() => type=%u", type);
3212 return 0;
3213}
3214
niklase@google.com470e71d2011-07-07 08:21:25 +00003215int
3216Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3217{
3218 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3219 "Channel::UpdateRxVadDetection()");
3220
3221 int vadDecision = 1;
3222
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003223 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003224
3225 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3226 {
3227 OnRxVadDetected(vadDecision);
3228 _oldVadDecision = vadDecision;
3229 }
3230
3231 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3232 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3233 vadDecision);
3234 return 0;
3235}
3236
3237int
3238Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3239{
3240 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3241 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003242 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003243
3244 if (_rxVadObserverPtr)
3245 {
3246 _engineStatisticsPtr->SetLastError(
3247 VE_INVALID_OPERATION, kTraceError,
3248 "RegisterRxVadObserver() observer already enabled");
3249 return -1;
3250 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003251 _rxVadObserverPtr = &observer;
3252 _RxVadDetection = true;
3253 return 0;
3254}
3255
3256int
3257Channel::DeRegisterRxVadObserver()
3258{
3259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3260 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003261 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003262
3263 if (!_rxVadObserverPtr)
3264 {
3265 _engineStatisticsPtr->SetLastError(
3266 VE_INVALID_OPERATION, kTraceWarning,
3267 "DeRegisterRxVadObserver() observer already disabled");
3268 return 0;
3269 }
3270 _rxVadObserverPtr = NULL;
3271 _RxVadDetection = false;
3272 return 0;
3273}
3274
3275int
3276Channel::VoiceActivityIndicator(int &activity)
3277{
3278 activity = _sendFrameType;
3279
3280 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3281 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3282 return 0;
3283}
3284
3285#ifdef WEBRTC_VOICE_ENGINE_AGC
3286
3287int
3288Channel::SetRxAgcStatus(const bool enable, const AgcModes mode)
3289{
3290 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3291 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3292 (int)enable, (int)mode);
3293
3294 GainControl::Mode agcMode(GainControl::kFixedDigital);
3295 switch (mode)
3296 {
3297 case kAgcDefault:
3298 agcMode = GainControl::kAdaptiveDigital;
3299 break;
3300 case kAgcUnchanged:
3301 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3302 break;
3303 case kAgcFixedDigital:
3304 agcMode = GainControl::kFixedDigital;
3305 break;
3306 case kAgcAdaptiveDigital:
3307 agcMode =GainControl::kAdaptiveDigital;
3308 break;
3309 default:
3310 _engineStatisticsPtr->SetLastError(
3311 VE_INVALID_ARGUMENT, kTraceError,
3312 "SetRxAgcStatus() invalid Agc mode");
3313 return -1;
3314 }
3315
3316 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3317 {
3318 _engineStatisticsPtr->SetLastError(
3319 VE_APM_ERROR, kTraceError,
3320 "SetRxAgcStatus() failed to set Agc mode");
3321 return -1;
3322 }
3323 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3324 {
3325 _engineStatisticsPtr->SetLastError(
3326 VE_APM_ERROR, kTraceError,
3327 "SetRxAgcStatus() failed to set Agc state");
3328 return -1;
3329 }
3330
3331 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003332 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3333
3334 return 0;
3335}
3336
3337int
3338Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3339{
3340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3341 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3342
3343 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3344 GainControl::Mode agcMode =
3345 _rxAudioProcessingModulePtr->gain_control()->mode();
3346
3347 enabled = enable;
3348
3349 switch (agcMode)
3350 {
3351 case GainControl::kFixedDigital:
3352 mode = kAgcFixedDigital;
3353 break;
3354 case GainControl::kAdaptiveDigital:
3355 mode = kAgcAdaptiveDigital;
3356 break;
3357 default:
3358 _engineStatisticsPtr->SetLastError(
3359 VE_APM_ERROR, kTraceError,
3360 "GetRxAgcStatus() invalid Agc mode");
3361 return -1;
3362 }
3363
3364 return 0;
3365}
3366
3367int
3368Channel::SetRxAgcConfig(const AgcConfig config)
3369{
3370 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3371 "Channel::SetRxAgcConfig()");
3372
3373 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3374 config.targetLeveldBOv) != 0)
3375 {
3376 _engineStatisticsPtr->SetLastError(
3377 VE_APM_ERROR, kTraceError,
3378 "SetRxAgcConfig() failed to set target peak |level|"
3379 "(or envelope) of the Agc");
3380 return -1;
3381 }
3382 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3383 config.digitalCompressionGaindB) != 0)
3384 {
3385 _engineStatisticsPtr->SetLastError(
3386 VE_APM_ERROR, kTraceError,
3387 "SetRxAgcConfig() failed to set the range in |gain| the"
3388 " digital compression stage may apply");
3389 return -1;
3390 }
3391 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3392 config.limiterEnable) != 0)
3393 {
3394 _engineStatisticsPtr->SetLastError(
3395 VE_APM_ERROR, kTraceError,
3396 "SetRxAgcConfig() failed to set hard limiter to the signal");
3397 return -1;
3398 }
3399
3400 return 0;
3401}
3402
3403int
3404Channel::GetRxAgcConfig(AgcConfig& config)
3405{
3406 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3407 "Channel::GetRxAgcConfig(config=%?)");
3408
3409 config.targetLeveldBOv =
3410 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3411 config.digitalCompressionGaindB =
3412 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3413 config.limiterEnable =
3414 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3415
3416 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3417 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3418 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3419 " limiterEnable=%d",
3420 config.targetLeveldBOv,
3421 config.digitalCompressionGaindB,
3422 config.limiterEnable);
3423
3424 return 0;
3425}
3426
3427#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3428
3429#ifdef WEBRTC_VOICE_ENGINE_NR
3430
3431int
3432Channel::SetRxNsStatus(const bool enable, const NsModes mode)
3433{
3434 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3435 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3436 (int)enable, (int)mode);
3437
3438 NoiseSuppression::Level nsLevel(
3439 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3440 switch (mode)
3441 {
3442
3443 case kNsDefault:
3444 nsLevel = (NoiseSuppression::Level)
3445 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3446 break;
3447 case kNsUnchanged:
3448 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3449 break;
3450 case kNsConference:
3451 nsLevel = NoiseSuppression::kHigh;
3452 break;
3453 case kNsLowSuppression:
3454 nsLevel = NoiseSuppression::kLow;
3455 break;
3456 case kNsModerateSuppression:
3457 nsLevel = NoiseSuppression::kModerate;
3458 break;
3459 case kNsHighSuppression:
3460 nsLevel = NoiseSuppression::kHigh;
3461 break;
3462 case kNsVeryHighSuppression:
3463 nsLevel = NoiseSuppression::kVeryHigh;
3464 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003465 }
3466
3467 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3468 != 0)
3469 {
3470 _engineStatisticsPtr->SetLastError(
3471 VE_APM_ERROR, kTraceError,
3472 "SetRxAgcStatus() failed to set Ns level");
3473 return -1;
3474 }
3475 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3476 {
3477 _engineStatisticsPtr->SetLastError(
3478 VE_APM_ERROR, kTraceError,
3479 "SetRxAgcStatus() failed to set Agc state");
3480 return -1;
3481 }
3482
3483 _rxNsIsEnabled = enable;
3484 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3485
3486 return 0;
3487}
3488
3489int
3490Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3491{
3492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3493 "Channel::GetRxNsStatus(enable=?, mode=?)");
3494
3495 bool enable =
3496 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3497 NoiseSuppression::Level ncLevel =
3498 _rxAudioProcessingModulePtr->noise_suppression()->level();
3499
3500 enabled = enable;
3501
3502 switch (ncLevel)
3503 {
3504 case NoiseSuppression::kLow:
3505 mode = kNsLowSuppression;
3506 break;
3507 case NoiseSuppression::kModerate:
3508 mode = kNsModerateSuppression;
3509 break;
3510 case NoiseSuppression::kHigh:
3511 mode = kNsHighSuppression;
3512 break;
3513 case NoiseSuppression::kVeryHigh:
3514 mode = kNsVeryHighSuppression;
3515 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003516 }
3517
3518 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3519 VoEId(_instanceId,_channelId),
3520 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3521 return 0;
3522}
3523
3524#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3525
3526int
3527Channel::RegisterRTPObserver(VoERTPObserver& observer)
3528{
3529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3530 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003531 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003532
3533 if (_rtpObserverPtr)
3534 {
3535 _engineStatisticsPtr->SetLastError(
3536 VE_INVALID_OPERATION, kTraceError,
3537 "RegisterRTPObserver() observer already enabled");
3538 return -1;
3539 }
3540
3541 _rtpObserverPtr = &observer;
3542 _rtpObserver = true;
3543
3544 return 0;
3545}
3546
3547int
3548Channel::DeRegisterRTPObserver()
3549{
3550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3551 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003552 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003553
3554 if (!_rtpObserverPtr)
3555 {
3556 _engineStatisticsPtr->SetLastError(
3557 VE_INVALID_OPERATION, kTraceWarning,
3558 "DeRegisterRTPObserver() observer already disabled");
3559 return 0;
3560 }
3561
3562 _rtpObserver = false;
3563 _rtpObserverPtr = NULL;
3564
3565 return 0;
3566}
3567
3568int
3569Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3570{
3571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3572 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003573 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003574
3575 if (_rtcpObserverPtr)
3576 {
3577 _engineStatisticsPtr->SetLastError(
3578 VE_INVALID_OPERATION, kTraceError,
3579 "RegisterRTCPObserver() observer already enabled");
3580 return -1;
3581 }
3582
3583 _rtcpObserverPtr = &observer;
3584 _rtcpObserver = true;
3585
3586 return 0;
3587}
3588
3589int
3590Channel::DeRegisterRTCPObserver()
3591{
3592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3593 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003594 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003595
3596 if (!_rtcpObserverPtr)
3597 {
3598 _engineStatisticsPtr->SetLastError(
3599 VE_INVALID_OPERATION, kTraceWarning,
3600 "DeRegisterRTCPObserver() observer already disabled");
3601 return 0;
3602 }
3603
3604 _rtcpObserver = false;
3605 _rtcpObserverPtr = NULL;
3606
3607 return 0;
3608}
3609
3610int
3611Channel::SetLocalSSRC(unsigned int ssrc)
3612{
3613 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3614 "Channel::SetLocalSSRC()");
3615 if (_sending)
3616 {
3617 _engineStatisticsPtr->SetLastError(
3618 VE_ALREADY_SENDING, kTraceError,
3619 "SetLocalSSRC() already sending");
3620 return -1;
3621 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003622 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003623 {
3624 _engineStatisticsPtr->SetLastError(
3625 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3626 "SetLocalSSRC() failed to set SSRC");
3627 return -1;
3628 }
3629 return 0;
3630}
3631
3632int
3633Channel::GetLocalSSRC(unsigned int& ssrc)
3634{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003635 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003636 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3637 VoEId(_instanceId,_channelId),
3638 "GetLocalSSRC() => ssrc=%lu", ssrc);
3639 return 0;
3640}
3641
3642int
3643Channel::GetRemoteSSRC(unsigned int& ssrc)
3644{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003645 ssrc = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003646 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3647 VoEId(_instanceId,_channelId),
3648 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3649 return 0;
3650}
3651
3652int
3653Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3654{
3655 if (arrCSRC == NULL)
3656 {
3657 _engineStatisticsPtr->SetLastError(
3658 VE_INVALID_ARGUMENT, kTraceError,
3659 "GetRemoteCSRCs() invalid array argument");
3660 return -1;
3661 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003662 uint32_t arrOfCSRC[kRtpCsrcSize];
3663 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003664 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003665 if (CSRCs > 0)
3666 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003667 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003668 for (int i = 0; i < (int) CSRCs; i++)
3669 {
3670 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3671 VoEId(_instanceId, _channelId),
3672 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3673 }
3674 } else
3675 {
3676 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3677 VoEId(_instanceId, _channelId),
3678 "GetRemoteCSRCs() => list is empty!");
3679 }
3680 return CSRCs;
3681}
3682
3683int
3684Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3685{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003686 if (_rtpAudioProc.get() == NULL)
3687 {
3688 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3689 _channelId)));
3690 if (_rtpAudioProc.get() == NULL)
3691 {
3692 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3693 "Failed to create AudioProcessing");
3694 return -1;
3695 }
3696 }
3697
3698 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3699 AudioProcessing::kNoError)
3700 {
3701 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3702 "Failed to enable AudioProcessing::level_estimator()");
3703 }
3704
niklase@google.com470e71d2011-07-07 08:21:25 +00003705 _includeAudioLevelIndication = enable;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003706 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003707}
3708int
3709Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3710{
3711 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3712 VoEId(_instanceId,_channelId),
3713 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3714 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003715 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003716}
3717
3718int
3719Channel::SetRTCPStatus(bool enable)
3720{
3721 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3722 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003723 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 kRtcpCompound : kRtcpOff) != 0)
3725 {
3726 _engineStatisticsPtr->SetLastError(
3727 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3728 "SetRTCPStatus() failed to set RTCP status");
3729 return -1;
3730 }
3731 return 0;
3732}
3733
3734int
3735Channel::GetRTCPStatus(bool& enabled)
3736{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003737 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003738 enabled = (method != kRtcpOff);
3739 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3740 VoEId(_instanceId,_channelId),
3741 "GetRTCPStatus() => enabled=%d", enabled);
3742 return 0;
3743}
3744
3745int
3746Channel::SetRTCP_CNAME(const char cName[256])
3747{
3748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3749 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003750 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003751 {
3752 _engineStatisticsPtr->SetLastError(
3753 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3754 "SetRTCP_CNAME() failed to set RTCP CNAME");
3755 return -1;
3756 }
3757 return 0;
3758}
3759
3760int
3761Channel::GetRTCP_CNAME(char cName[256])
3762{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003763 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003764 {
3765 _engineStatisticsPtr->SetLastError(
3766 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3767 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3768 return -1;
3769 }
3770 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3771 VoEId(_instanceId, _channelId),
3772 "GetRTCP_CNAME() => cName=%s", cName);
3773 return 0;
3774}
3775
3776int
3777Channel::GetRemoteRTCP_CNAME(char cName[256])
3778{
3779 if (cName == NULL)
3780 {
3781 _engineStatisticsPtr->SetLastError(
3782 VE_INVALID_ARGUMENT, kTraceError,
3783 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3784 return -1;
3785 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003786 char cname[RTCP_CNAME_SIZE];
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003787 const uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003788 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003789 {
3790 _engineStatisticsPtr->SetLastError(
3791 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3792 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3793 return -1;
3794 }
3795 strcpy(cName, cname);
3796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3797 VoEId(_instanceId, _channelId),
3798 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3799 return 0;
3800}
3801
3802int
3803Channel::GetRemoteRTCPData(
3804 unsigned int& NTPHigh,
3805 unsigned int& NTPLow,
3806 unsigned int& timestamp,
3807 unsigned int& playoutTimestamp,
3808 unsigned int* jitter,
3809 unsigned short* fractionLost)
3810{
3811 // --- Information from sender info in received Sender Reports
3812
3813 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003814 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003815 {
3816 _engineStatisticsPtr->SetLastError(
3817 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003818 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003819 "side");
3820 return -1;
3821 }
3822
3823 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3824 // and octet count)
3825 NTPHigh = senderInfo.NTPseconds;
3826 NTPLow = senderInfo.NTPfraction;
3827 timestamp = senderInfo.RTPtimeStamp;
3828
3829 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3830 VoEId(_instanceId, _channelId),
3831 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3832 "timestamp=%lu",
3833 NTPHigh, NTPLow, timestamp);
3834
3835 // --- Locally derived information
3836
3837 // This value is updated on each incoming RTCP packet (0 when no packet
3838 // has been received)
3839 playoutTimestamp = _playoutTimeStampRTCP;
3840
3841 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3842 VoEId(_instanceId, _channelId),
3843 "GetRemoteRTCPData() => playoutTimestamp=%lu",
3844 _playoutTimeStampRTCP);
3845
3846 if (NULL != jitter || NULL != fractionLost)
3847 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003848 // Get all RTCP receiver report blocks that have been received on this
3849 // channel. If we receive RTP packets from a remote source we know the
3850 // remote SSRC and use the report block from him.
3851 // Otherwise use the first report block.
3852 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003853 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003854 remote_stats.empty()) {
3855 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3856 VoEId(_instanceId, _channelId),
3857 "GetRemoteRTCPData() failed to measure statistics due"
3858 " to lack of received RTP and/or RTCP packets");
3859 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003860 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003861
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003862 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003863 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3864 for (; it != remote_stats.end(); ++it) {
3865 if (it->remoteSSRC == remoteSSRC)
3866 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003867 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003868
3869 if (it == remote_stats.end()) {
3870 // If we have not received any RTCP packets from this SSRC it probably
3871 // means that we have not received any RTP packets.
3872 // Use the first received report block instead.
3873 it = remote_stats.begin();
3874 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003875 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003876
xians@webrtc.org79af7342012-01-31 12:22:14 +00003877 if (jitter) {
3878 *jitter = it->jitter;
3879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3880 VoEId(_instanceId, _channelId),
3881 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3882 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003883
xians@webrtc.org79af7342012-01-31 12:22:14 +00003884 if (fractionLost) {
3885 *fractionLost = it->fractionLost;
3886 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3887 VoEId(_instanceId, _channelId),
3888 "GetRemoteRTCPData() => fractionLost = %lu",
3889 *fractionLost);
3890 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003891 }
3892 return 0;
3893}
3894
3895int
3896Channel::SendApplicationDefinedRTCPPacket(const unsigned char subType,
3897 unsigned int name,
3898 const char* data,
3899 unsigned short dataLengthInBytes)
3900{
3901 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3902 "Channel::SendApplicationDefinedRTCPPacket()");
3903 if (!_sending)
3904 {
3905 _engineStatisticsPtr->SetLastError(
3906 VE_NOT_SENDING, kTraceError,
3907 "SendApplicationDefinedRTCPPacket() not sending");
3908 return -1;
3909 }
3910 if (NULL == data)
3911 {
3912 _engineStatisticsPtr->SetLastError(
3913 VE_INVALID_ARGUMENT, kTraceError,
3914 "SendApplicationDefinedRTCPPacket() invalid data value");
3915 return -1;
3916 }
3917 if (dataLengthInBytes % 4 != 0)
3918 {
3919 _engineStatisticsPtr->SetLastError(
3920 VE_INVALID_ARGUMENT, kTraceError,
3921 "SendApplicationDefinedRTCPPacket() invalid length value");
3922 return -1;
3923 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003924 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003925 if (status == kRtcpOff)
3926 {
3927 _engineStatisticsPtr->SetLastError(
3928 VE_RTCP_ERROR, kTraceError,
3929 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3930 return -1;
3931 }
3932
3933 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003934 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003935 subType,
3936 name,
3937 (const unsigned char*) data,
3938 dataLengthInBytes) != 0)
3939 {
3940 _engineStatisticsPtr->SetLastError(
3941 VE_SEND_ERROR, kTraceError,
3942 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3943 return -1;
3944 }
3945 return 0;
3946}
3947
3948int
3949Channel::GetRTPStatistics(
3950 unsigned int& averageJitterMs,
3951 unsigned int& maxJitterMs,
3952 unsigned int& discardedPackets)
3953{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003954 uint8_t fraction_lost(0);
3955 uint32_t cum_lost(0);
3956 uint32_t ext_max(0);
3957 uint32_t jitter(0);
3958 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003959
3960 // The jitter statistics is updated for each received RTP packet and is
3961 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003962 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00003963 &cum_lost,
3964 &ext_max,
3965 &jitter,
3966 &max_jitter) != 0)
3967 {
3968 _engineStatisticsPtr->SetLastError(
3969 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003970 "GetRTPStatistics() failed to read RTP statistics from the "
niklase@google.com470e71d2011-07-07 08:21:25 +00003971 "RTP/RTCP module");
3972 }
3973
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003974 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00003975 _audioCodingModule.PlayoutFrequency();
3976 if (playoutFrequency > 0)
3977 {
3978 // Scale RTP statistics given the current playout frequency
3979 maxJitterMs = max_jitter / (playoutFrequency / 1000);
3980 averageJitterMs = jitter / (playoutFrequency / 1000);
3981 }
3982
3983 discardedPackets = _numberOfDiscardedPackets;
3984
3985 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3986 VoEId(_instanceId, _channelId),
3987 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003988 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003989 averageJitterMs, maxJitterMs, discardedPackets);
3990 return 0;
3991}
3992
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003993int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3994 if (sender_info == NULL) {
3995 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3996 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3997 return -1;
3998 }
3999
4000 // Get the sender info from the latest received RTCP Sender Report.
4001 RTCPSenderInfo rtcp_sender_info;
4002 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
4003 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4004 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
4005 return -1;
4006 }
4007
4008 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
4009 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
4010 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
4011 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
4012 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
4013 return 0;
4014}
4015
4016int Channel::GetRemoteRTCPReportBlocks(
4017 std::vector<ReportBlock>* report_blocks) {
4018 if (report_blocks == NULL) {
4019 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
4020 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
4021 return -1;
4022 }
4023
4024 // Get the report blocks from the latest received RTCP Sender or Receiver
4025 // Report. Each element in the vector contains the sender's SSRC and a
4026 // report block according to RFC 3550.
4027 std::vector<RTCPReportBlock> rtcp_report_blocks;
4028 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
4029 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4030 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
4031 return -1;
4032 }
4033
4034 if (rtcp_report_blocks.empty())
4035 return 0;
4036
4037 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4038 for (; it != rtcp_report_blocks.end(); ++it) {
4039 ReportBlock report_block;
4040 report_block.sender_SSRC = it->remoteSSRC;
4041 report_block.source_SSRC = it->sourceSSRC;
4042 report_block.fraction_lost = it->fractionLost;
4043 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4044 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4045 report_block.interarrival_jitter = it->jitter;
4046 report_block.last_SR_timestamp = it->lastSR;
4047 report_block.delay_since_last_SR = it->delaySinceLastSR;
4048 report_blocks->push_back(report_block);
4049 }
4050 return 0;
4051}
4052
niklase@google.com470e71d2011-07-07 08:21:25 +00004053int
4054Channel::GetRTPStatistics(CallStatistics& stats)
4055{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004056 uint8_t fraction_lost(0);
4057 uint32_t cum_lost(0);
4058 uint32_t ext_max(0);
4059 uint32_t jitter(0);
4060 uint32_t max_jitter(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004061
4062 // --- Part one of the final structure (four values)
4063
4064 // The jitter statistics is updated for each received RTP packet and is
4065 // based on received packets.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004066 if (_rtpRtcpModule->StatisticsRTP(&fraction_lost,
niklase@google.com470e71d2011-07-07 08:21:25 +00004067 &cum_lost,
4068 &ext_max,
4069 &jitter,
4070 &max_jitter) != 0)
4071 {
4072 _engineStatisticsPtr->SetLastError(
4073 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4074 "GetRTPStatistics() failed to read RTP statistics from the "
4075 "RTP/RTCP module");
4076 }
4077
4078 stats.fractionLost = fraction_lost;
4079 stats.cumulativeLost = cum_lost;
4080 stats.extendedMax = ext_max;
4081 stats.jitterSamples = jitter;
4082
4083 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4084 VoEId(_instanceId, _channelId),
4085 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004086 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004087 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4088 stats.jitterSamples);
4089
4090 // --- Part two of the final structure (one value)
4091
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004092 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004093 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004094 if (method == kRtcpOff)
4095 {
4096 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4097 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004098 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004099 "measurements cannot be retrieved");
4100 } else
4101 {
4102 // The remote SSRC will be zero if no RTP packet has been received.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004103 uint32_t remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004104 if (remoteSSRC > 0)
4105 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004106 uint16_t avgRTT(0);
4107 uint16_t maxRTT(0);
4108 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004109
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004110 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004111 != 0)
4112 {
4113 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4114 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004115 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004116 "the RTP/RTCP module");
4117 }
4118 } else
4119 {
4120 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4121 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004122 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004123 "RTP packets have been received yet");
4124 }
4125 }
4126
4127 stats.rttMs = static_cast<int> (RTT);
4128
4129 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4130 VoEId(_instanceId, _channelId),
4131 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4132
4133 // --- Part three of the final structure (four values)
4134
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004135 uint32_t bytesSent(0);
4136 uint32_t packetsSent(0);
4137 uint32_t bytesReceived(0);
4138 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004139
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004140 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
niklase@google.com470e71d2011-07-07 08:21:25 +00004141 &packetsSent,
4142 &bytesReceived,
4143 &packetsReceived) != 0)
4144 {
4145 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4146 VoEId(_instanceId, _channelId),
4147 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004148 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004149 }
4150
4151 stats.bytesSent = bytesSent;
4152 stats.packetsSent = packetsSent;
4153 stats.bytesReceived = bytesReceived;
4154 stats.packetsReceived = packetsReceived;
4155
4156 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4157 VoEId(_instanceId, _channelId),
4158 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004159 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004160 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4161 stats.packetsReceived);
4162
4163 return 0;
4164}
4165
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004166int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4167 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4168 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004169
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004170 if (enable) {
4171 if (redPayloadtype < 0 || redPayloadtype > 127) {
4172 _engineStatisticsPtr->SetLastError(
4173 VE_PLTYPE_ERROR, kTraceError,
4174 "SetFECStatus() invalid RED payload type");
4175 return -1;
4176 }
4177
4178 if (SetRedPayloadType(redPayloadtype) < 0) {
4179 _engineStatisticsPtr->SetLastError(
4180 VE_CODEC_ERROR, kTraceError,
4181 "SetSecondarySendCodec() Failed to register RED ACM");
4182 return -1;
4183 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004184 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004185
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004186 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4187 _engineStatisticsPtr->SetLastError(
4188 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4189 "SetFECStatus() failed to set FEC state in the ACM");
4190 return -1;
4191 }
4192 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004193}
4194
4195int
4196Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4197{
4198 enabled = _audioCodingModule.FECStatus();
4199 if (enabled)
4200 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004201 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004202 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004203 {
4204 _engineStatisticsPtr->SetLastError(
4205 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4206 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4207 "module");
4208 return -1;
4209 }
4210 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4211 VoEId(_instanceId, _channelId),
4212 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4213 enabled, redPayloadtype);
4214 return 0;
4215 }
4216 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4217 VoEId(_instanceId, _channelId),
4218 "GetFECStatus() => enabled=%d", enabled);
4219 return 0;
4220}
4221
4222int
niklase@google.com470e71d2011-07-07 08:21:25 +00004223Channel::StartRTPDump(const char fileNameUTF8[1024],
4224 RTPDirections direction)
4225{
4226 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4227 "Channel::StartRTPDump()");
4228 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4229 {
4230 _engineStatisticsPtr->SetLastError(
4231 VE_INVALID_ARGUMENT, kTraceError,
4232 "StartRTPDump() invalid RTP direction");
4233 return -1;
4234 }
4235 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4236 &_rtpDumpIn : &_rtpDumpOut;
4237 if (rtpDumpPtr == NULL)
4238 {
4239 assert(false);
4240 return -1;
4241 }
4242 if (rtpDumpPtr->IsActive())
4243 {
4244 rtpDumpPtr->Stop();
4245 }
4246 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4247 {
4248 _engineStatisticsPtr->SetLastError(
4249 VE_BAD_FILE, kTraceError,
4250 "StartRTPDump() failed to create file");
4251 return -1;
4252 }
4253 return 0;
4254}
4255
4256int
4257Channel::StopRTPDump(RTPDirections direction)
4258{
4259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4260 "Channel::StopRTPDump()");
4261 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4262 {
4263 _engineStatisticsPtr->SetLastError(
4264 VE_INVALID_ARGUMENT, kTraceError,
4265 "StopRTPDump() invalid RTP direction");
4266 return -1;
4267 }
4268 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4269 &_rtpDumpIn : &_rtpDumpOut;
4270 if (rtpDumpPtr == NULL)
4271 {
4272 assert(false);
4273 return -1;
4274 }
4275 if (!rtpDumpPtr->IsActive())
4276 {
4277 return 0;
4278 }
4279 return rtpDumpPtr->Stop();
4280}
4281
4282bool
4283Channel::RTPDumpIsActive(RTPDirections direction)
4284{
4285 if ((direction != kRtpIncoming) &&
4286 (direction != kRtpOutgoing))
4287 {
4288 _engineStatisticsPtr->SetLastError(
4289 VE_INVALID_ARGUMENT, kTraceError,
4290 "RTPDumpIsActive() invalid RTP direction");
4291 return false;
4292 }
4293 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4294 &_rtpDumpIn : &_rtpDumpOut;
4295 return rtpDumpPtr->IsActive();
4296}
4297
4298int
4299Channel::InsertExtraRTPPacket(unsigned char payloadType,
4300 bool markerBit,
4301 const char* payloadData,
4302 unsigned short payloadSize)
4303{
4304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4305 "Channel::InsertExtraRTPPacket()");
4306 if (payloadType > 127)
4307 {
4308 _engineStatisticsPtr->SetLastError(
4309 VE_INVALID_PLTYPE, kTraceError,
4310 "InsertExtraRTPPacket() invalid payload type");
4311 return -1;
4312 }
4313 if (payloadData == NULL)
4314 {
4315 _engineStatisticsPtr->SetLastError(
4316 VE_INVALID_ARGUMENT, kTraceError,
4317 "InsertExtraRTPPacket() invalid payload data");
4318 return -1;
4319 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004320 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004321 {
4322 _engineStatisticsPtr->SetLastError(
4323 VE_INVALID_ARGUMENT, kTraceError,
4324 "InsertExtraRTPPacket() invalid payload size");
4325 return -1;
4326 }
4327 if (!_sending)
4328 {
4329 _engineStatisticsPtr->SetLastError(
4330 VE_NOT_SENDING, kTraceError,
4331 "InsertExtraRTPPacket() not sending");
4332 return -1;
4333 }
4334
4335 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4336 // Transport::SendPacket() will be called by the module when the RTP packet
4337 // is created.
4338 // The call to SendOutgoingData() does *not* modify the timestamp and
4339 // payloadtype to ensure that the RTP module generates a valid RTP packet
4340 // (user might utilize a non-registered payload type).
4341 // The marker bit and payload type will be replaced just before the actual
4342 // transmission, i.e., the actual modification is done *after* the RTP
4343 // module has delivered its RTP packet back to the VoE.
4344 // We will use the stored values above when the packet is modified
4345 // (see Channel::SendPacket()).
4346
4347 _extraPayloadType = payloadType;
4348 _extraMarkerBit = markerBit;
4349 _insertExtraRTPPacket = true;
4350
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004351 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004352 _lastPayloadType,
4353 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004354 // Leaving the time when this frame was
4355 // received from the capture device as
4356 // undefined for voice for now.
4357 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004358 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004359 payloadSize) != 0)
4360 {
4361 _engineStatisticsPtr->SetLastError(
4362 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4363 "InsertExtraRTPPacket() failed to send extra RTP packet");
4364 return -1;
4365 }
4366
4367 return 0;
4368}
4369
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004370uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004371Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004372{
4373 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004374 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004375 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004376 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004377 return 0;
4378}
4379
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004380uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004381Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004382{
4383 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4384 "Channel::PrepareEncodeAndSend()");
4385
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004386 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004387 {
4388 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4389 "Channel::PrepareEncodeAndSend() invalid audio frame");
4390 return -1;
4391 }
4392
4393 if (_inputFilePlaying)
4394 {
4395 MixOrReplaceAudioWithFile(mixingFrequency);
4396 }
4397
4398 if (_mute)
4399 {
4400 AudioFrameOperations::Mute(_audioFrame);
4401 }
4402
4403 if (_inputExternalMedia)
4404 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004405 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004406 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004407 if (_inputExternalMediaCallbackPtr)
4408 {
4409 _inputExternalMediaCallbackPtr->Process(
4410 _channelId,
4411 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004412 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004413 _audioFrame.samples_per_channel_,
4414 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004415 isStereo);
4416 }
4417 }
4418
4419 InsertInbandDtmfTone();
4420
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004421 if (_includeAudioLevelIndication)
4422 {
4423 assert(_rtpAudioProc.get() != NULL);
4424
4425 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004426 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004427 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004428 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004429 AudioProcessing::kNoError)
4430 {
4431 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4432 VoEId(_instanceId, _channelId),
4433 "Error setting AudioProcessing sample rate");
4434 return -1;
4435 }
4436 }
4437
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004438 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004439 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004440 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4441 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004442 != AudioProcessing::kNoError)
4443 {
4444 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4445 VoEId(_instanceId, _channelId),
4446 "Error setting AudioProcessing channels");
4447 return -1;
4448 }
4449 }
4450
4451 // Performs level analysis only; does not affect the signal.
4452 _rtpAudioProc->ProcessStream(&_audioFrame);
4453 }
4454
niklase@google.com470e71d2011-07-07 08:21:25 +00004455 return 0;
4456}
4457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004458uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004459Channel::EncodeAndSend()
4460{
4461 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4462 "Channel::EncodeAndSend()");
4463
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004464 assert(_audioFrame.num_channels_ <= 2);
4465 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004466 {
4467 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4468 "Channel::EncodeAndSend() invalid audio frame");
4469 return -1;
4470 }
4471
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004472 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004473
4474 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4475
4476 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004477 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004478 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4479 {
4480 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4481 "Channel::EncodeAndSend() ACM encoding failed");
4482 return -1;
4483 }
4484
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004485 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004486
4487 // --- Encode if complete frame is ready
4488
4489 // This call will trigger AudioPacketizationCallback::SendData if encoding
4490 // is done and payload is ready for packetization and transmission.
4491 return _audioCodingModule.Process();
4492}
4493
4494int Channel::RegisterExternalMediaProcessing(
4495 ProcessingTypes type,
4496 VoEMediaProcess& processObject)
4497{
4498 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4499 "Channel::RegisterExternalMediaProcessing()");
4500
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004501 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004502
4503 if (kPlaybackPerChannel == type)
4504 {
4505 if (_outputExternalMediaCallbackPtr)
4506 {
4507 _engineStatisticsPtr->SetLastError(
4508 VE_INVALID_OPERATION, kTraceError,
4509 "Channel::RegisterExternalMediaProcessing() "
4510 "output external media already enabled");
4511 return -1;
4512 }
4513 _outputExternalMediaCallbackPtr = &processObject;
4514 _outputExternalMedia = true;
4515 }
4516 else if (kRecordingPerChannel == type)
4517 {
4518 if (_inputExternalMediaCallbackPtr)
4519 {
4520 _engineStatisticsPtr->SetLastError(
4521 VE_INVALID_OPERATION, kTraceError,
4522 "Channel::RegisterExternalMediaProcessing() "
4523 "output external media already enabled");
4524 return -1;
4525 }
4526 _inputExternalMediaCallbackPtr = &processObject;
4527 _inputExternalMedia = true;
4528 }
4529 return 0;
4530}
4531
4532int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4533{
4534 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4535 "Channel::DeRegisterExternalMediaProcessing()");
4536
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004537 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004538
4539 if (kPlaybackPerChannel == type)
4540 {
4541 if (!_outputExternalMediaCallbackPtr)
4542 {
4543 _engineStatisticsPtr->SetLastError(
4544 VE_INVALID_OPERATION, kTraceWarning,
4545 "Channel::DeRegisterExternalMediaProcessing() "
4546 "output external media already disabled");
4547 return 0;
4548 }
4549 _outputExternalMedia = false;
4550 _outputExternalMediaCallbackPtr = NULL;
4551 }
4552 else if (kRecordingPerChannel == type)
4553 {
4554 if (!_inputExternalMediaCallbackPtr)
4555 {
4556 _engineStatisticsPtr->SetLastError(
4557 VE_INVALID_OPERATION, kTraceWarning,
4558 "Channel::DeRegisterExternalMediaProcessing() "
4559 "input external media already disabled");
4560 return 0;
4561 }
4562 _inputExternalMedia = false;
4563 _inputExternalMediaCallbackPtr = NULL;
4564 }
4565
4566 return 0;
4567}
4568
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004569int Channel::SetExternalMixing(bool enabled) {
4570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4571 "Channel::SetExternalMixing(enabled=%d)", enabled);
4572
4573 if (_playing)
4574 {
4575 _engineStatisticsPtr->SetLastError(
4576 VE_INVALID_OPERATION, kTraceError,
4577 "Channel::SetExternalMixing() "
4578 "external mixing cannot be changed while playing.");
4579 return -1;
4580 }
4581
4582 _externalMixing = enabled;
4583
4584 return 0;
4585}
4586
niklase@google.com470e71d2011-07-07 08:21:25 +00004587int
4588Channel::ResetRTCPStatistics()
4589{
4590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4591 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004592 uint32_t remoteSSRC(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004593 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
4594 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004595}
4596
4597int
4598Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4599{
4600 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4601 "Channel::GetRoundTripTimeSummary()");
4602 // Override default module outputs for the case when RTCP is disabled.
4603 // This is done to ensure that we are backward compatible with the
4604 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004605 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004606 {
4607 delaysMs.min = -1;
4608 delaysMs.max = -1;
4609 delaysMs.average = -1;
4610 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4611 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4612 " valid RTT measurements cannot be retrieved");
4613 return 0;
4614 }
4615
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004616 uint32_t remoteSSRC;
4617 uint16_t RTT;
4618 uint16_t avgRTT;
4619 uint16_t maxRTT;
4620 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004621 // The remote SSRC will be zero if no RTP packet has been received.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004622 remoteSSRC = _rtpRtcpModule->RemoteSSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004623 if (remoteSSRC == 0)
4624 {
4625 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4626 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4627 " since no RTP packet has been received yet");
4628 }
4629
4630 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4631 // channel and SSRC. The SSRC is required to parse out the correct source
4632 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004633 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004634 {
4635 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4636 "GetRoundTripTimeSummary unable to retrieve RTT values"
4637 " from the RTCP layer");
4638 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4639 }
4640 else
4641 {
4642 delaysMs.min = minRTT;
4643 delaysMs.max = maxRTT;
4644 delaysMs.average = avgRTT;
4645 }
4646 return 0;
4647}
4648
4649int
4650Channel::GetNetworkStatistics(NetworkStatistics& stats)
4651{
4652 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4653 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004654 ACMNetworkStatistics acm_stats;
4655 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4656 if (return_value >= 0) {
4657 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4658 }
4659 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004660}
4661
4662int
niklase@google.com470e71d2011-07-07 08:21:25 +00004663Channel::GetDelayEstimate(int& delayMs) const
4664{
4665 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4666 "Channel::GetDelayEstimate()");
4667 delayMs = (_averageDelayMs + 5) / 10 + _recPacketDelayMs;
4668 return 0;
4669}
4670
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004671int Channel::SetInitialPlayoutDelay(int delay_ms)
4672{
4673 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4674 "Channel::SetInitialPlayoutDelay()");
4675 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4676 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4677 {
4678 _engineStatisticsPtr->SetLastError(
4679 VE_INVALID_ARGUMENT, kTraceError,
4680 "SetInitialPlayoutDelay() invalid min delay");
4681 return -1;
4682 }
4683 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4684 {
4685 _engineStatisticsPtr->SetLastError(
4686 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4687 "SetInitialPlayoutDelay() failed to set min playout delay");
4688 return -1;
4689 }
4690 return 0;
4691}
4692
4693
niklase@google.com470e71d2011-07-07 08:21:25 +00004694int
4695Channel::SetMinimumPlayoutDelay(int delayMs)
4696{
4697 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4698 "Channel::SetMinimumPlayoutDelay()");
4699 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4700 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4701 {
4702 _engineStatisticsPtr->SetLastError(
4703 VE_INVALID_ARGUMENT, kTraceError,
4704 "SetMinimumPlayoutDelay() invalid min delay");
4705 return -1;
4706 }
4707 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4708 {
4709 _engineStatisticsPtr->SetLastError(
4710 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4711 "SetMinimumPlayoutDelay() failed to set min playout delay");
4712 return -1;
4713 }
4714 return 0;
4715}
4716
4717int
4718Channel::GetPlayoutTimestamp(unsigned int& timestamp)
4719{
4720 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4721 "Channel::GetPlayoutTimestamp()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004722 uint32_t playoutTimestamp(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004723 if (GetPlayoutTimeStamp(playoutTimestamp) != 0)
4724 {
4725 _engineStatisticsPtr->SetLastError(
4726 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4727 "GetPlayoutTimestamp() failed to retrieve timestamp");
4728 return -1;
4729 }
4730 timestamp = playoutTimestamp;
4731 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4732 VoEId(_instanceId,_channelId),
4733 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4734 return 0;
4735}
4736
4737int
4738Channel::SetInitTimestamp(unsigned int timestamp)
4739{
4740 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4741 "Channel::SetInitTimestamp()");
4742 if (_sending)
4743 {
4744 _engineStatisticsPtr->SetLastError(
4745 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4746 return -1;
4747 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004748 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004749 {
4750 _engineStatisticsPtr->SetLastError(
4751 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4752 "SetInitTimestamp() failed to set timestamp");
4753 return -1;
4754 }
4755 return 0;
4756}
4757
4758int
4759Channel::SetInitSequenceNumber(short sequenceNumber)
4760{
4761 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4762 "Channel::SetInitSequenceNumber()");
4763 if (_sending)
4764 {
4765 _engineStatisticsPtr->SetLastError(
4766 VE_SENDING, kTraceError,
4767 "SetInitSequenceNumber() already sending");
4768 return -1;
4769 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004770 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004771 {
4772 _engineStatisticsPtr->SetLastError(
4773 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4774 "SetInitSequenceNumber() failed to set sequence number");
4775 return -1;
4776 }
4777 return 0;
4778}
4779
4780int
4781Channel::GetRtpRtcp(RtpRtcp* &rtpRtcpModule) const
4782{
4783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4784 "Channel::GetRtpRtcp()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004785 rtpRtcpModule = _rtpRtcpModule.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004786 return 0;
4787}
4788
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004789// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4790// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004791int32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004792Channel::MixOrReplaceAudioWithFile(const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004793{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004794 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004795 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004796
4797 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004798 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004799
4800 if (_inputFilePlayerPtr == NULL)
4801 {
4802 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4803 VoEId(_instanceId, _channelId),
4804 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4805 " doesnt exist");
4806 return -1;
4807 }
4808
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004809 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004810 fileSamples,
4811 mixingFrequency) == -1)
4812 {
4813 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4814 VoEId(_instanceId, _channelId),
4815 "Channel::MixOrReplaceAudioWithFile() file mixing "
4816 "failed");
4817 return -1;
4818 }
4819 if (fileSamples == 0)
4820 {
4821 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4822 VoEId(_instanceId, _channelId),
4823 "Channel::MixOrReplaceAudioWithFile() file is ended");
4824 return 0;
4825 }
4826 }
4827
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004828 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004829
4830 if (_mixFileWithMicrophone)
4831 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004832 // Currently file stream is always mono.
4833 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004834 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004835 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004836 fileBuffer.get(),
4837 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004838 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004839 }
4840 else
4841 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004842 // Replace ACM audio with file.
4843 // Currently file stream is always mono.
4844 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004845 _audioFrame.UpdateFrame(_channelId,
4846 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004847 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004848 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004849 mixingFrequency,
4850 AudioFrame::kNormalSpeech,
4851 AudioFrame::kVadUnknown,
4852 1);
4853
4854 }
4855 return 0;
4856}
4857
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004858int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004859Channel::MixAudioWithFile(AudioFrame& audioFrame,
xians@google.com0b0665a2011-08-08 08:18:44 +00004860 const int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004861{
4862 assert(mixingFrequency <= 32000);
4863
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004864 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004865 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004866
4867 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004868 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004869
4870 if (_outputFilePlayerPtr == NULL)
4871 {
4872 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4873 VoEId(_instanceId, _channelId),
4874 "Channel::MixAudioWithFile() file mixing failed");
4875 return -1;
4876 }
4877
4878 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004879 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004880 fileSamples,
4881 mixingFrequency) == -1)
4882 {
4883 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4884 VoEId(_instanceId, _channelId),
4885 "Channel::MixAudioWithFile() file mixing failed");
4886 return -1;
4887 }
4888 }
4889
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004890 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004891 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004892 // Currently file stream is always mono.
4893 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004894 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004895 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004896 fileBuffer.get(),
4897 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004898 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004899 }
4900 else
4901 {
4902 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004903 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004904 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004905 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004906 return -1;
4907 }
4908
4909 return 0;
4910}
4911
4912int
4913Channel::InsertInbandDtmfTone()
4914{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004915 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004916 if (_inbandDtmfQueue.PendingDtmf() &&
4917 !_inbandDtmfGenerator.IsAddingTone() &&
4918 _inbandDtmfGenerator.DelaySinceLastTone() >
4919 kMinTelephoneEventSeparationMs)
4920 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004921 int8_t eventCode(0);
4922 uint16_t lengthMs(0);
4923 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004924
4925 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4926 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4927 if (_playInbandDtmfEvent)
4928 {
4929 // Add tone to output mixer using a reduced length to minimize
4930 // risk of echo.
4931 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4932 attenuationDb);
4933 }
4934 }
4935
4936 if (_inbandDtmfGenerator.IsAddingTone())
4937 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004938 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004939 _inbandDtmfGenerator.GetSampleRate(frequency);
4940
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004941 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004942 {
4943 // Update sample rate of Dtmf tone since the mixing frequency
4944 // has changed.
4945 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004946 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004947 // Reset the tone to be added taking the new sample rate into
4948 // account.
4949 _inbandDtmfGenerator.ResetTone();
4950 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004951
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004952 int16_t toneBuffer[320];
4953 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004954 // Get 10ms tone segment and set time since last tone to zero
4955 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4956 {
4957 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4958 VoEId(_instanceId, _channelId),
4959 "Channel::EncodeAndSend() inserting Dtmf failed");
4960 return -1;
4961 }
4962
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004963 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004964 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004965 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004966 sample++)
4967 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004968 for (int channel = 0;
4969 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004970 channel++)
4971 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004972 const int index = sample * _audioFrame.num_channels_ + channel;
4973 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004974 }
4975 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004976
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004977 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004978 } else
4979 {
4980 // Add 10ms to "delay-since-last-tone" counter
4981 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4982 }
4983 return 0;
4984}
4985
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004986int32_t
4987Channel::GetPlayoutTimeStamp(uint32_t& playoutTimestamp)
niklase@google.com470e71d2011-07-07 08:21:25 +00004988{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004989 uint32_t timestamp(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004990 CodecInst currRecCodec;
4991
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004992 if (_audioCodingModule.PlayoutTimestamp(&timestamp) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00004993 {
4994 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4995 "Channel::GetPlayoutTimeStamp() failed to read playout"
4996 " timestamp from the ACM");
4997 return -1;
4998 }
4999
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005000 uint16_t delayMS(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005001 if (_audioDeviceModulePtr->PlayoutDelay(&delayMS) == -1)
5002 {
5003 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
5004 "Channel::GetPlayoutTimeStamp() failed to read playout"
5005 " delay from the ADM");
5006 return -1;
5007 }
5008
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005009 int32_t playoutFrequency = _audioCodingModule.PlayoutFrequency();
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005010 if (_audioCodingModule.ReceiveCodec(&currRecCodec) == 0) {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005011 if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) {
5012 playoutFrequency = 8000;
5013 } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) {
5014 playoutFrequency = 48000;
5015 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005016 }
5017 timestamp -= (delayMS * (playoutFrequency/1000));
5018
5019 playoutTimestamp = timestamp;
5020
5021 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5022 "Channel::GetPlayoutTimeStamp() => playoutTimestamp = %lu",
5023 playoutTimestamp);
5024 return 0;
5025}
5026
5027void
5028Channel::ResetDeadOrAliveCounters()
5029{
5030 _countDeadDetections = 0;
5031 _countAliveDetections = 0;
5032}
5033
5034void
5035Channel::UpdateDeadOrAliveCounters(bool alive)
5036{
5037 if (alive)
5038 _countAliveDetections++;
5039 else
5040 _countDeadDetections++;
5041}
5042
5043int
5044Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5045{
5046 bool enabled;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005047 uint8_t timeSec;
niklase@google.com470e71d2011-07-07 08:21:25 +00005048
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005049 _rtpRtcpModule->PeriodicDeadOrAliveStatus(enabled, timeSec);
niklase@google.com470e71d2011-07-07 08:21:25 +00005050 if (!enabled)
5051 return (-1);
5052
5053 countDead = static_cast<int> (_countDeadDetections);
5054 countAlive = static_cast<int> (_countAliveDetections);
5055 return 0;
5056}
5057
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005058int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005059Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5060{
5061 if (_transportPtr == NULL)
5062 {
5063 return -1;
5064 }
5065 if (!RTCP)
5066 {
5067 return _transportPtr->SendPacket(_channelId, data, len);
5068 }
5069 else
5070 {
5071 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5072 }
5073}
5074
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005075int32_t
5076Channel::UpdatePacketDelay(const uint32_t timestamp,
5077 const uint16_t sequenceNumber)
niklase@google.com470e71d2011-07-07 08:21:25 +00005078{
5079 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5080 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5081 timestamp, sequenceNumber);
5082
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005083 int32_t rtpReceiveFrequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005084
5085 // Get frequency of last received payload
5086 rtpReceiveFrequency = _audioCodingModule.ReceiveFrequency();
5087
5088 CodecInst currRecCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005089 if (_audioCodingModule.ReceiveCodec(&currRecCodec) == 0) {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005090 if (STR_CASE_CMP("G722", currRecCodec.plname) == 0) {
5091 // Even though the actual sampling rate for G.722 audio is
5092 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5093 // 8,000 Hz because that value was erroneously assigned in
5094 // RFC 1890 and must remain unchanged for backward compatibility.
5095 rtpReceiveFrequency = 8000;
5096 } else if (STR_CASE_CMP("opus", currRecCodec.plname) == 0) {
5097 // We are resampling Opus internally to 32,000 Hz until all our
5098 // DSP routines can operate at 48,000 Hz, but the RTP clock
5099 // rate for the Opus payload format is standardized to 48,000 Hz,
5100 // because that is the maximum supported decoding sampling rate.
5101 rtpReceiveFrequency = 48000;
5102 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005103 }
5104
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005105 const uint32_t timeStampDiff = timestamp - _playoutTimeStampRTP;
5106 uint32_t timeStampDiffMs(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005107
5108 if (timeStampDiff > 0)
5109 {
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005110 switch (rtpReceiveFrequency) {
5111 case 8000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005112 timeStampDiffMs = static_cast<uint32_t>(timeStampDiff >> 3);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005113 break;
5114 case 16000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005115 timeStampDiffMs = static_cast<uint32_t>(timeStampDiff >> 4);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005116 break;
5117 case 32000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005118 timeStampDiffMs = static_cast<uint32_t>(timeStampDiff >> 5);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005119 break;
5120 case 48000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005121 timeStampDiffMs = static_cast<uint32_t>(timeStampDiff / 48);
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005122 break;
5123 default:
5124 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5125 VoEId(_instanceId, _channelId),
5126 "Channel::UpdatePacketDelay() invalid sample rate");
5127 timeStampDiffMs = 0;
5128 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00005129 }
niklas.enbom@webrtc.org218c5422013-01-17 22:25:49 +00005130 if (timeStampDiffMs > (2 * kVoiceEngineMaxMinPlayoutDelayMs))
niklase@google.com470e71d2011-07-07 08:21:25 +00005131 {
5132 timeStampDiffMs = 0;
5133 }
5134
5135 if (_averageDelayMs == 0)
5136 {
niklas.enbom@webrtc.org218c5422013-01-17 22:25:49 +00005137 _averageDelayMs = timeStampDiffMs * 10;
niklase@google.com470e71d2011-07-07 08:21:25 +00005138 }
5139 else
5140 {
5141 // Filter average delay value using exponential filter (alpha is
5142 // 7/8). We derive 10*_averageDelayMs here (reduces risk of
5143 // rounding error) and compensate for it in GetDelayEstimate()
5144 // later. Adding 4/8 results in correct rounding.
5145 _averageDelayMs = ((_averageDelayMs*7 + 10*timeStampDiffMs + 4)>>3);
5146 }
5147
5148 if (sequenceNumber - _previousSequenceNumber == 1)
5149 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005150 uint16_t packetDelayMs = 0;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005151 switch (rtpReceiveFrequency) {
5152 case 8000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005153 packetDelayMs = static_cast<uint16_t>(
niklase@google.com470e71d2011-07-07 08:21:25 +00005154 (timestamp - _previousTimestamp) >> 3);
5155 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005156 case 16000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005157 packetDelayMs = static_cast<uint16_t>(
niklase@google.com470e71d2011-07-07 08:21:25 +00005158 (timestamp - _previousTimestamp) >> 4);
5159 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005160 case 32000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005161 packetDelayMs = static_cast<uint16_t>(
niklase@google.com470e71d2011-07-07 08:21:25 +00005162 (timestamp - _previousTimestamp) >> 5);
5163 break;
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005164 case 48000:
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005165 packetDelayMs = static_cast<uint16_t>(
tina.legrand@webrtc.orga7d83872012-10-18 10:00:52 +00005166 (timestamp - _previousTimestamp) / 48);
5167 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00005168 }
5169
5170 if (packetDelayMs >= 10 && packetDelayMs <= 60)
5171 _recPacketDelayMs = packetDelayMs;
5172 }
5173 }
5174
5175 _previousSequenceNumber = sequenceNumber;
5176 _previousTimestamp = timestamp;
5177
5178 return 0;
5179}
5180
5181void
5182Channel::RegisterReceiveCodecsToRTPModule()
5183{
5184 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5185 "Channel::RegisterReceiveCodecsToRTPModule()");
5186
5187
5188 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005189 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005190
5191 for (int idx = 0; idx < nSupportedCodecs; idx++)
5192 {
5193 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005194 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00005195 (_rtpRtcpModule->RegisterReceivePayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005196 {
5197 WEBRTC_TRACE(
5198 kTraceWarning,
5199 kTraceVoice,
5200 VoEId(_instanceId, _channelId),
5201 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5202 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5203 codec.plname, codec.pltype, codec.plfreq,
5204 codec.channels, codec.rate);
5205 }
5206 else
5207 {
5208 WEBRTC_TRACE(
5209 kTraceInfo,
5210 kTraceVoice,
5211 VoEId(_instanceId, _channelId),
5212 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005213 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005214 "receiver",
5215 codec.plname, codec.pltype, codec.plfreq,
5216 codec.channels, codec.rate);
5217 }
5218 }
5219}
5220
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005221int Channel::ApmProcessRx(AudioFrame& frame) {
5222 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5223 // Register the (possibly new) frame parameters.
5224 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005225 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005226 }
5227 if (audioproc->set_num_channels(frame.num_channels_,
5228 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005229 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005230 }
5231 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005232 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005233 }
5234 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005235}
5236
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005237int Channel::SetSecondarySendCodec(const CodecInst& codec,
5238 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005239 // Sanity check for payload type.
5240 if (red_payload_type < 0 || red_payload_type > 127) {
5241 _engineStatisticsPtr->SetLastError(
5242 VE_PLTYPE_ERROR, kTraceError,
5243 "SetRedPayloadType() invalid RED payload type");
5244 return -1;
5245 }
5246
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005247 if (SetRedPayloadType(red_payload_type) < 0) {
5248 _engineStatisticsPtr->SetLastError(
5249 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5250 "SetSecondarySendCodec() Failed to register RED ACM");
5251 return -1;
5252 }
5253 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5254 _engineStatisticsPtr->SetLastError(
5255 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5256 "SetSecondarySendCodec() Failed to register secondary send codec in "
5257 "ACM");
5258 return -1;
5259 }
5260
5261 return 0;
5262}
5263
5264void Channel::RemoveSecondarySendCodec() {
5265 _audioCodingModule.UnregisterSecondarySendCodec();
5266}
5267
5268int Channel::GetSecondarySendCodec(CodecInst* codec) {
5269 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5270 _engineStatisticsPtr->SetLastError(
5271 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5272 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5273 return -1;
5274 }
5275 return 0;
5276}
5277
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005278// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005279int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005280 CodecInst codec;
5281 bool found_red = false;
5282
5283 // Get default RED settings from the ACM database
5284 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5285 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005286 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005287 if (!STR_CASE_CMP(codec.plname, "RED")) {
5288 found_red = true;
5289 break;
5290 }
5291 }
5292
5293 if (!found_red) {
5294 _engineStatisticsPtr->SetLastError(
5295 VE_CODEC_ERROR, kTraceError,
5296 "SetRedPayloadType() RED is not supported");
5297 return -1;
5298 }
5299
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005300 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005301 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5302 _engineStatisticsPtr->SetLastError(
5303 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5304 "SetRedPayloadType() RED registration in ACM module failed");
5305 return -1;
5306 }
5307
5308 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5309 _engineStatisticsPtr->SetLastError(
5310 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5311 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5312 return -1;
5313 }
5314 return 0;
5315}
5316
niklase@google.com470e71d2011-07-07 08:21:25 +00005317} // namespace voe
niklase@google.com470e71d2011-07-07 08:21:25 +00005318} // namespace webrtc