blob: be42d511f6bed6b855ee5aac72553cfee15f7a60 [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"
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +000015#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
16#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
18#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000019#include "webrtc/modules/utility/interface/audio_frame_operations.h"
20#include "webrtc/modules/utility/interface/process_thread.h"
21#include "webrtc/modules/utility/interface/rtp_dump.h"
22#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
23#include "webrtc/system_wrappers/interface/logging.h"
24#include "webrtc/system_wrappers/interface/trace.h"
25#include "webrtc/voice_engine/include/voe_base.h"
26#include "webrtc/voice_engine/include/voe_external_media.h"
27#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
28#include "webrtc/voice_engine/output_mixer.h"
29#include "webrtc/voice_engine/statistics.h"
30#include "webrtc/voice_engine/transmit_mixer.h"
31#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000032
33#if defined(_WIN32)
34#include <Qos.h>
35#endif
36
andrew@webrtc.org50419b02012-11-14 19:07:54 +000037namespace webrtc {
38namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000039
pbos@webrtc.org6141e132013-04-09 10:09:10 +000040int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000041Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000042 uint8_t payloadType,
43 uint32_t timeStamp,
44 const uint8_t* payloadData,
45 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000046 const RTPFragmentationHeader* fragmentation)
47{
48 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
49 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
50 " payloadSize=%u, fragmentation=0x%x)",
51 frameType, payloadType, timeStamp, payloadSize, fragmentation);
52
53 if (_includeAudioLevelIndication)
54 {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +000055 assert(_rtpAudioProc.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +000056 // Store current audio level in the RTP/RTCP module.
57 // The level will be used in combination with voice-activity state
58 // (frameType) to add an RTP header extension
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000059 _rtpRtcpModule->SetAudioLevel(_rtpAudioProc->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +000060 }
61
62 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
63 // packetization.
64 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +000065 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +000066 payloadType,
67 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +000068 // Leaving the time when this frame was
69 // received from the capture device as
70 // undefined for voice for now.
71 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +000072 payloadData,
73 payloadSize,
74 fragmentation) == -1)
75 {
76 _engineStatisticsPtr->SetLastError(
77 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
78 "Channel::SendData() failed to send data to RTP/RTCP module");
79 return -1;
80 }
81
82 _lastLocalTimeStamp = timeStamp;
83 _lastPayloadType = payloadType;
84
85 return 0;
86}
87
pbos@webrtc.org6141e132013-04-09 10:09:10 +000088int32_t
89Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +000090{
91 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
92 "Channel::InFrameType(frameType=%d)", frameType);
93
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +000094 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +000095 // 1 indicates speech
96 _sendFrameType = (frameType == 1) ? 1 : 0;
97 return 0;
98}
99
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000100int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000101Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000102{
103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
104 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
105
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000106 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000107 if (_rxVadObserverPtr)
108 {
109 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
110 }
111
112 return 0;
113}
114
115int
116Channel::SendPacket(int channel, const void *data, int len)
117{
118 channel = VoEChannelId(channel);
119 assert(channel == _channelId);
120
121 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
122 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
123
124 if (_transportPtr == NULL)
125 {
126 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
127 "Channel::SendPacket() failed to send RTP packet due to"
128 " invalid transport object");
129 return -1;
130 }
131
132 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
133 // API
134 if (_insertExtraRTPPacket)
135 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136 uint8_t* rtpHdr = (uint8_t*)data;
137 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 if (_extraMarkerBit)
139 {
140 M_PT = 0x80; // set the M-bit
141 }
142 M_PT += _extraPayloadType; // set the payload type
143 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
144 _insertExtraRTPPacket = false; // insert one packet only
145 }
146
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 uint8_t* bufferToSendPtr = (uint8_t*)data;
148 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000149
150 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 {
153 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
154 VoEId(_instanceId,_channelId),
155 "Channel::SendPacket() RTP dump to output file failed");
156 }
157
158 // SRTP or External encryption
159 if (_encrypting)
160 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000161 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000162
163 if (_encryptionPtr)
164 {
165 if (!_encryptionRTPBufferPtr)
166 {
167 // Allocate memory for encryption buffer one time only
168 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000170 memset(_encryptionRTPBufferPtr, 0,
171 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 }
173
174 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000175 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 _encryptionPtr->encrypt(_channelId,
177 bufferToSendPtr,
178 _encryptionRTPBufferPtr,
179 bufferLength,
180 (int*)&encryptedBufferLength);
181 if (encryptedBufferLength <= 0)
182 {
183 _engineStatisticsPtr->SetLastError(
184 VE_ENCRYPTION_FAILED,
185 kTraceError, "Channel::SendPacket() encryption failed");
186 return -1;
187 }
188
189 // Replace default data buffer with encrypted buffer
190 bufferToSendPtr = _encryptionRTPBufferPtr;
191 bufferLength = encryptedBufferLength;
192 }
193 }
194
195 // Packet transmission using WebRtc socket transport
196 if (!_externalTransport)
197 {
198 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
199 bufferLength);
200 if (n < 0)
201 {
202 WEBRTC_TRACE(kTraceError, kTraceVoice,
203 VoEId(_instanceId,_channelId),
204 "Channel::SendPacket() RTP transmission using WebRtc"
205 " sockets failed");
206 return -1;
207 }
208 return n;
209 }
210
211 // Packet transmission using external transport transport
212 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000213 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
215 int n = _transportPtr->SendPacket(channel,
216 bufferToSendPtr,
217 bufferLength);
218 if (n < 0)
219 {
220 WEBRTC_TRACE(kTraceError, kTraceVoice,
221 VoEId(_instanceId,_channelId),
222 "Channel::SendPacket() RTP transmission using external"
223 " transport failed");
224 return -1;
225 }
226 return n;
227 }
228}
229
230int
231Channel::SendRTCPPacket(int channel, const void *data, int len)
232{
233 channel = VoEChannelId(channel);
234 assert(channel == _channelId);
235
236 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
237 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
238
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000240 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +0000241 if (_transportPtr == NULL)
242 {
243 WEBRTC_TRACE(kTraceError, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendRTCPPacket() failed to send RTCP packet"
246 " due to invalid transport object");
247 return -1;
248 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 uint8_t* bufferToSendPtr = (uint8_t*)data;
252 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000255 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
258 VoEId(_instanceId,_channelId),
259 "Channel::SendPacket() RTCP dump to output file failed");
260 }
261
262 // SRTP or External encryption
263 if (_encrypting)
264 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000265 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
267 if (_encryptionPtr)
268 {
269 if (!_encryptionRTCPBufferPtr)
270 {
271 // Allocate memory for encryption buffer one time only
272 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000273 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
276 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000277 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 _encryptionPtr->encrypt_rtcp(_channelId,
279 bufferToSendPtr,
280 _encryptionRTCPBufferPtr,
281 bufferLength,
282 (int*)&encryptedBufferLength);
283 if (encryptedBufferLength <= 0)
284 {
285 _engineStatisticsPtr->SetLastError(
286 VE_ENCRYPTION_FAILED, kTraceError,
287 "Channel::SendRTCPPacket() encryption failed");
288 return -1;
289 }
290
291 // Replace default data buffer with encrypted buffer
292 bufferToSendPtr = _encryptionRTCPBufferPtr;
293 bufferLength = encryptedBufferLength;
294 }
295 }
296
297 // Packet transmission using WebRtc socket transport
298 if (!_externalTransport)
299 {
300 int n = _transportPtr->SendRTCPPacket(channel,
301 bufferToSendPtr,
302 bufferLength);
303 if (n < 0)
304 {
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
306 VoEId(_instanceId,_channelId),
307 "Channel::SendRTCPPacket() transmission using WebRtc"
308 " sockets failed");
309 return -1;
310 }
311 return n;
312 }
313
314 // Packet transmission using external transport transport
315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000316 CriticalSectionScoped cs(&_callbackCritSect);
henrike@webrtc.orgde727ab2012-11-18 18:49:13 +0000317 if (_transportPtr == NULL)
318 {
319 return -1;
320 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 int n = _transportPtr->SendRTCPPacket(channel,
322 bufferToSendPtr,
323 bufferLength);
324 if (n < 0)
325 {
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using external"
329 " transport failed");
330 return -1;
331 }
332 return n;
333 }
334
335 return len;
336}
337
338void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000339Channel::OnPlayTelephoneEvent(int32_t id,
340 uint8_t event,
341 uint16_t lengthMs,
342 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343{
344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
345 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000346 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
348 if (!_playOutbandDtmfEvent || (event > 15))
349 {
350 // Ignore callback since feedback is disabled or event is not a
351 // Dtmf tone event.
352 return;
353 }
354
355 assert(_outputMixerPtr != NULL);
356
357 // Start playing out the Dtmf tone (if playout is enabled).
358 // Reduce length of tone with 80ms to the reduce risk of echo.
359 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
360}
361
362void
stefan@webrtc.org717d1472013-07-10 13:39:27 +0000363Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org717d1472013-07-10 13:39:27 +0000367 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000369 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 assert(channel == _channelId);
371
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 if (_rtpObserver)
373 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000374 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 if (_rtpObserverPtr)
377 {
378 // Send new SSRC to registered observer using callback
stefan@webrtc.org717d1472013-07-10 13:39:27 +0000379 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 }
381 }
382}
383
pbos@webrtc.org92135212013-05-14 08:31:39 +0000384void Channel::OnIncomingCSRCChanged(int32_t id,
385 uint32_t CSRC,
386 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000387{
388 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
389 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
390 id, CSRC, added);
391
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000392 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 assert(channel == _channelId);
394
395 if (_rtpObserver)
396 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000397 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
399 if (_rtpObserverPtr)
400 {
401 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
402 }
403 }
404}
405
stefan@webrtc.org717d1472013-07-10 13:39:27 +0000406void Channel::OnResetStatistics(uint32_t ssrc) {
407 StreamStatistician* statistician =
408 rtp_receive_statistics_->GetStatistician(ssrc);
409 if (statistician) {
410 statistician->ResetStatistics();
411 }
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000412}
413
niklase@google.com470e71d2011-07-07 08:21:25 +0000414void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000415Channel::OnApplicationDataReceived(int32_t id,
416 uint8_t subType,
417 uint32_t name,
418 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000419 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000420{
421 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
422 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
423 " name=%u, length=%u)",
424 id, subType, name, length);
425
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000426 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 assert(channel == _channelId);
428
429 if (_rtcpObserver)
430 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000431 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000432
433 if (_rtcpObserverPtr)
434 {
435 _rtcpObserverPtr->OnApplicationDataReceived(channel,
436 subType,
437 name,
438 data,
439 length);
440 }
441 }
442}
443
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000445Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000446 int32_t id,
447 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000448 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000449 int frequency,
450 uint8_t channels,
451 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000452{
453 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
454 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
455 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
456 id, payloadType, payloadName, frequency, channels, rate);
457
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000458 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000459
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000460 CodecInst receiveCodec = {0};
461 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000462
463 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000464 receiveCodec.plfreq = frequency;
465 receiveCodec.channels = channels;
466 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000467 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000468
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000469 _audioCodingModule.Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 receiveCodec.pacsize = dummyCodec.pacsize;
471
472 // Register the new codec to the ACM
473 if (_audioCodingModule.RegisterReceiveCodec(receiveCodec) == -1)
474 {
475 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000476 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 "Channel::OnInitializeDecoder() invalid codec ("
478 "pt=%d, name=%s) received - 1", payloadType, payloadName);
479 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
480 return -1;
481 }
482
483 return 0;
484}
485
486void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000487Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000488{
489 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
490 "Channel::OnPacketTimeout(id=%d)", id);
491
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000492 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 if (_voiceEngineObserverPtr)
494 {
495 if (_receiving || _externalTransport)
496 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000497 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000498 assert(channel == _channelId);
499 // Ensure that next OnReceivedPacket() callback will trigger
500 // a VE_PACKET_RECEIPT_RESTARTED callback.
501 _rtpPacketTimedOut = true;
502 // Deliver callback to the observer
503 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
504 VoEId(_instanceId,_channelId),
505 "Channel::OnPacketTimeout() => "
506 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
507 _voiceEngineObserverPtr->CallbackOnError(channel,
508 VE_RECEIVE_PACKET_TIMEOUT);
509 }
510 }
511}
512
513void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000514Channel::OnReceivedPacket(int32_t id,
515 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000516{
517 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
518 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
519 id, packetType);
520
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000521 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
523 // Notify only for the case when we have restarted an RTP session.
524 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
525 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000526 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 if (_voiceEngineObserverPtr)
528 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000529 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 assert(channel == _channelId);
531 // Reset timeout mechanism
532 _rtpPacketTimedOut = false;
533 // Deliver callback to the observer
534 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
535 VoEId(_instanceId,_channelId),
536 "Channel::OnPacketTimeout() =>"
537 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
538 _voiceEngineObserverPtr->CallbackOnError(
539 channel,
540 VE_PACKET_RECEIPT_RESTARTED);
541 }
542 }
543}
544
545void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000546Channel::OnPeriodicDeadOrAlive(int32_t id,
547 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000548{
549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
550 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
551
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000552 {
553 CriticalSectionScoped cs(&_callbackCritSect);
554 if (!_connectionObserver)
555 return;
556 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000558 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 assert(channel == _channelId);
560
561 // Use Alive as default to limit risk of false Dead detections
562 bool isAlive(true);
563
564 // Always mark the connection as Dead when the module reports kRtpDead
565 if (kRtpDead == alive)
566 {
567 isAlive = false;
568 }
569
570 // It is possible that the connection is alive even if no RTP packet has
571 // been received for a long time since the other side might use VAD/DTX
572 // and a low SID-packet update rate.
573 if ((kRtpNoRtp == alive) && _playing)
574 {
575 // Detect Alive for all NetEQ states except for the case when we are
576 // in PLC_CNG state.
577 // PLC_CNG <=> background noise only due to long expand or error.
578 // Note that, the case where the other side stops sending during CNG
579 // state will be detected as Alive. Dead is is not set until after
580 // missing RTCP packets for at least twelve seconds (handled
581 // internally by the RTP/RTCP module).
582 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
583 }
584
585 UpdateDeadOrAliveCounters(isAlive);
586
587 // Send callback to the registered observer
588 if (_connectionObserver)
589 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000590 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 if (_connectionObserverPtr)
592 {
593 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
594 }
595 }
596}
597
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000598int32_t
599Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000600 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 const WebRtcRTPHeader* rtpHeader)
602{
603 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
604 "Channel::OnReceivedPayloadData(payloadSize=%d,"
605 " payloadType=%u, audioChannel=%u)",
606 payloadSize,
607 rtpHeader->header.payloadType,
608 rtpHeader->type.Audio.channel);
609
roosa@google.com0870f022012-12-12 21:31:41 +0000610 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
611
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 if (!_playing)
613 {
614 // Avoid inserting into NetEQ when we are not playing. Count the
615 // packet as discarded.
616 WEBRTC_TRACE(kTraceStream, kTraceVoice,
617 VoEId(_instanceId, _channelId),
618 "received packet is discarded since playing is not"
619 " activated");
620 _numberOfDiscardedPackets++;
621 return 0;
622 }
623
624 // Push the incoming payload (parsed and ready for decoding) into the ACM
tina.legrand@webrtc.org16b6b902012-04-12 11:02:38 +0000625 if (_audioCodingModule.IncomingPacket(payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 payloadSize,
627 *rtpHeader) != 0)
628 {
629 _engineStatisticsPtr->SetLastError(
630 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
631 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
632 return -1;
633 }
634
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000635 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 UpdatePacketDelay(rtpHeader->header.timestamp,
637 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000638
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000639 uint16_t round_trip_time = 0;
640 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
641 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000642
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000643 std::vector<uint16_t> nack_list = _audioCodingModule.GetNackList(
644 round_trip_time);
645 if (!nack_list.empty()) {
646 // Can't use nack_list.data() since it's not supported by all
647 // compilers.
648 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000649 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 return 0;
651}
652
pbos@webrtc.org92135212013-05-14 08:31:39 +0000653int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000654{
655 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
656 "Channel::GetAudioFrame(id=%d)", id);
657
658 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000659 if (_audioCodingModule.PlayoutData10Ms(audioFrame.sample_rate_hz_,
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +0000660 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 {
662 WEBRTC_TRACE(kTraceError, kTraceVoice,
663 VoEId(_instanceId,_channelId),
664 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000665 // In all likelihood, the audio in this frame is garbage. We return an
666 // error so that the audio mixer module doesn't add it to the mix. As
667 // a result, it won't be played out and the actions skipped here are
668 // irrelevant.
669 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 }
671
672 if (_RxVadDetection)
673 {
674 UpdateRxVadDetection(audioFrame);
675 }
676
677 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000678 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000680 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000681
682 // Perform far-end AudioProcessing module processing on the received signal
683 if (_rxApmIsEnabled)
684 {
685 ApmProcessRx(audioFrame);
686 }
687
688 // Output volume scaling
689 if (_outputGain < 0.99f || _outputGain > 1.01f)
690 {
691 AudioFrameOperations::ScaleWithSat(_outputGain, audioFrame);
692 }
693
694 // Scale left and/or right channel(s) if stereo and master balance is
695 // active
696
697 if (_panLeft != 1.0f || _panRight != 1.0f)
698 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000699 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000700 {
701 // Emulate stereo mode since panning is active.
702 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000703 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 }
705 // For true stereo mode (when we are receiving a stereo signal), no
706 // action is needed.
707
708 // Do the panning operation (the audio frame contains stereo at this
709 // stage)
710 AudioFrameOperations::Scale(_panLeft, _panRight, audioFrame);
711 }
712
713 // Mix decoded PCM output with file if file mixing is enabled
714 if (_outputFilePlaying)
715 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000716 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 }
718
719 // Place channel in on-hold state (~muted) if on-hold is activated
720 if (_outputIsOnHold)
721 {
722 AudioFrameOperations::Mute(audioFrame);
723 }
724
725 // External media
726 if (_outputExternalMedia)
727 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000728 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000729 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 if (_outputExternalMediaCallbackPtr)
731 {
732 _outputExternalMediaCallbackPtr->Process(
733 _channelId,
734 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000735 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000736 audioFrame.samples_per_channel_,
737 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 isStereo);
739 }
740 }
741
742 // Record playout if enabled
743 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000744 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000745
746 if (_outputFileRecording && _outputFileRecorderPtr)
747 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000748 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000749 }
750 }
751
752 // Measure audio level (0-9)
753 _outputAudioLevel.ComputeLevel(audioFrame);
754
755 return 0;
756}
757
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000758int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000759Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000760{
761 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
762 "Channel::NeededFrequency(id=%d)", id);
763
764 int highestNeeded = 0;
765
766 // Determine highest needed receive frequency
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000767 int32_t receiveFrequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000768
769 // Return the bigger of playout and receive frequency in the ACM.
770 if (_audioCodingModule.PlayoutFrequency() > receiveFrequency)
771 {
772 highestNeeded = _audioCodingModule.PlayoutFrequency();
773 }
774 else
775 {
776 highestNeeded = receiveFrequency;
777 }
778
779 // Special case, if we're playing a file on the playout side
780 // we take that frequency into consideration as well
781 // This is not needed on sending side, since the codec will
782 // limit the spectrum anyway.
783 if (_outputFilePlaying)
784 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000785 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 if (_outputFilePlayerPtr && _outputFilePlaying)
787 {
788 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
789 {
790 highestNeeded=_outputFilePlayerPtr->Frequency();
791 }
792 }
793 }
794
795 return(highestNeeded);
796}
797
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000798int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000799Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000800 int32_t channelId,
801 uint32_t instanceId)
niklase@google.com470e71d2011-07-07 08:21:25 +0000802{
803 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
804 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
805 channelId, instanceId);
806
807 channel = new Channel(channelId, instanceId);
808 if (channel == NULL)
809 {
810 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
811 VoEId(instanceId,channelId),
812 "Channel::CreateChannel() unable to allocate memory for"
813 " channel");
814 return -1;
815 }
816 return 0;
817}
818
819void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000820Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000821{
822 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
823 "Channel::PlayNotification(id=%d, durationMs=%d)",
824 id, durationMs);
825
826 // Not implement yet
827}
828
829void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000830Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000831{
832 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
833 "Channel::RecordNotification(id=%d, durationMs=%d)",
834 id, durationMs);
835
836 // Not implement yet
837}
838
839void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000840Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000841{
842 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
843 "Channel::PlayFileEnded(id=%d)", id);
844
845 if (id == _inputFilePlayerId)
846 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000847 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000848
849 _inputFilePlaying = false;
850 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
851 VoEId(_instanceId,_channelId),
852 "Channel::PlayFileEnded() => input file player module is"
853 " shutdown");
854 }
855 else if (id == _outputFilePlayerId)
856 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000857 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000858
859 _outputFilePlaying = false;
860 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
861 VoEId(_instanceId,_channelId),
862 "Channel::PlayFileEnded() => output file player module is"
863 " shutdown");
864 }
865}
866
867void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000868Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000869{
870 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
871 "Channel::RecordFileEnded(id=%d)", id);
872
873 assert(id == _outputFileRecorderId);
874
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000875 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000876
877 _outputFileRecording = false;
878 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
879 VoEId(_instanceId,_channelId),
880 "Channel::RecordFileEnded() => output file recorder module is"
881 " shutdown");
882}
883
pbos@webrtc.org92135212013-05-14 08:31:39 +0000884Channel::Channel(int32_t channelId,
885 uint32_t instanceId) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
887 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000890 rtp_header_parser_(RtpHeaderParser::Create()),
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +0000891 rtp_payload_registry_(
892 new RTPPayloadRegistry(channelId,
893 RTPPayloadStrategy::CreateStrategy(true))),
894 rtp_receive_statistics_(ReceiveStatistics::Create(
895 Clock::GetRealTimeClock())),
896 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
897 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
898 this, this, rtp_payload_registry_.get())),
899 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 _audioCodingModule(*AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000901 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 _rtpDumpIn(*RtpDump::CreateRtpDump()),
903 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _inputFilePlayerPtr(NULL),
907 _outputFilePlayerPtr(NULL),
908 _outputFileRecorderPtr(NULL),
909 // Avoid conflict with other channels by adding 1024 - 1026,
910 // won't use as much as 1024 channels.
911 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
912 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
913 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
914 _inputFilePlaying(false),
915 _outputFilePlaying(false),
916 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000917 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
918 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000920 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 _inputExternalMediaCallbackPtr(NULL),
922 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000923 _encryptionRTPBufferPtr(NULL),
924 _decryptionRTPBufferPtr(NULL),
925 _encryptionRTCPBufferPtr(NULL),
926 _decryptionRTCPBufferPtr(NULL),
927 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
928 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000929 playout_timestamp_rtp_(0),
930 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000931 _numberOfDiscardedPackets(0),
932 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000933 _outputMixerPtr(NULL),
934 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000935 _moduleProcessThreadPtr(NULL),
936 _audioDeviceModulePtr(NULL),
937 _voiceEngineObserverPtr(NULL),
938 _callbackCritSectPtr(NULL),
939 _transportPtr(NULL),
940 _encryptionPtr(NULL),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000941 _rtpAudioProc(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000942 _rxAudioProcessingModulePtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000943 _rxVadObserverPtr(NULL),
944 _oldVadDecision(-1),
945 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 _rtpObserverPtr(NULL),
947 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000948 _outputIsOnHold(false),
949 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000950 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000951 _inputIsOnHold(false),
952 _playing(false),
953 _sending(false),
954 _receiving(false),
955 _mixFileWithMicrophone(false),
956 _rtpObserver(false),
957 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 _mute(false),
959 _panLeft(1.0f),
960 _panRight(1.0f),
961 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000962 _encrypting(false),
963 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 _playOutbandDtmfEvent(false),
965 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 _extraPayloadType(0),
967 _insertExtraRTPPacket(false),
968 _extraMarkerBit(false),
969 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000970 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000972 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 _rtpPacketTimedOut(false),
974 _rtpPacketTimeOutIsEnabled(false),
975 _rtpTimeOutSeconds(0),
976 _connectionObserver(false),
977 _connectionObserverPtr(NULL),
978 _countAliveDetections(0),
979 _countDeadDetections(0),
980 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000981 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000982 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 _previousTimestamp(0),
984 _recPacketDelayMs(20),
985 _RxVadDetection(false),
986 _rxApmIsEnabled(false),
987 _rxAgcIsEnabled(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000988 _rxNsIsEnabled(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000989{
990 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
991 "Channel::Channel() - ctor");
992 _inbandDtmfQueue.ResetDtmf();
993 _inbandDtmfGenerator.Init();
994 _outputAudioLevel.Clear();
995
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000996 RtpRtcp::Configuration configuration;
997 configuration.id = VoEModuleId(instanceId, channelId);
998 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000999 configuration.outgoing_transport = this;
1000 configuration.rtcp_feedback = this;
1001 configuration.audio_messages = this;
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001002 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001003
1004 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
1005
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 // Create far end AudioProcessing Module
1007 _rxAudioProcessingModulePtr = AudioProcessing::Create(
1008 VoEModuleId(instanceId, channelId));
1009}
1010
1011Channel::~Channel()
1012{
1013 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1014 "Channel::~Channel() - dtor");
1015
1016 if (_outputExternalMedia)
1017 {
1018 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1019 }
1020 if (_inputExternalMedia)
1021 {
1022 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1023 }
1024 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 StopPlayout();
1026
1027 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001028 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 if (_inputFilePlayerPtr)
1030 {
1031 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1032 _inputFilePlayerPtr->StopPlayingFile();
1033 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1034 _inputFilePlayerPtr = NULL;
1035 }
1036 if (_outputFilePlayerPtr)
1037 {
1038 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1039 _outputFilePlayerPtr->StopPlayingFile();
1040 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1041 _outputFilePlayerPtr = NULL;
1042 }
1043 if (_outputFileRecorderPtr)
1044 {
1045 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1046 _outputFileRecorderPtr->StopRecording();
1047 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1048 _outputFileRecorderPtr = NULL;
1049 }
1050 }
1051
1052 // The order to safely shutdown modules in a channel is:
1053 // 1. De-register callbacks in modules
1054 // 2. De-register modules in process thread
1055 // 3. Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 if (_audioCodingModule.RegisterTransportCallback(NULL) == -1)
1057 {
1058 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1059 VoEId(_instanceId,_channelId),
1060 "~Channel() failed to de-register transport callback"
1061 " (Audio coding module)");
1062 }
1063 if (_audioCodingModule.RegisterVADCallback(NULL) == -1)
1064 {
1065 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1066 VoEId(_instanceId,_channelId),
1067 "~Channel() failed to de-register VAD callback"
1068 " (Audio coding module)");
1069 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001071 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 {
1073 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1074 VoEId(_instanceId,_channelId),
1075 "~Channel() failed to deregister RTP/RTCP module");
1076 }
1077
1078 // Destroy modules
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 AudioCodingModule::Destroy(&_audioCodingModule);
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 if (_rxAudioProcessingModulePtr != NULL)
1081 {
1082 AudioProcessing::Destroy(_rxAudioProcessingModulePtr); // far end APM
1083 _rxAudioProcessingModulePtr = NULL;
1084 }
1085
1086 // End of modules shutdown
1087
1088 // Delete other objects
1089 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1090 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1091 delete [] _encryptionRTPBufferPtr;
1092 delete [] _decryptionRTPBufferPtr;
1093 delete [] _encryptionRTCPBufferPtr;
1094 delete [] _decryptionRTCPBufferPtr;
1095 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001096 delete &_fileCritSect;
1097}
1098
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001099int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001100Channel::Init()
1101{
1102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1103 "Channel::Init()");
1104
1105 // --- Initial sanity
1106
1107 if ((_engineStatisticsPtr == NULL) ||
1108 (_moduleProcessThreadPtr == NULL))
1109 {
1110 WEBRTC_TRACE(kTraceError, kTraceVoice,
1111 VoEId(_instanceId,_channelId),
1112 "Channel::Init() must call SetEngineInformation() first");
1113 return -1;
1114 }
1115
1116 // --- Add modules to process thread (for periodic schedulation)
1117
1118 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001119 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 if (processThreadFail)
1122 {
1123 _engineStatisticsPtr->SetLastError(
1124 VE_CANNOT_INIT_CHANNEL, kTraceError,
1125 "Channel::Init() modules not registered");
1126 return -1;
1127 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001128 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001129
1130 if ((_audioCodingModule.InitializeReceiver() == -1) ||
1131#ifdef WEBRTC_CODEC_AVT
1132 // out-of-band Dtmf tones are played out by default
1133 (_audioCodingModule.SetDtmfPlayoutStatus(true) == -1) ||
1134#endif
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 (_audioCodingModule.InitializeSender() == -1))
1136 {
1137 _engineStatisticsPtr->SetLastError(
1138 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1139 "Channel::Init() unable to initialize the ACM - 1");
1140 return -1;
1141 }
1142
1143 // --- RTP/RTCP module initialization
1144
1145 // Ensure that RTCP is enabled by default for the created channel.
1146 // Note that, the module will keep generating RTCP until it is explicitly
1147 // disabled by the user.
1148 // After StopListen (when no sockets exists), RTCP packets will no longer
1149 // be transmitted since the Transport object will then be invalid.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001150 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1151 // RTCP is enabled by default.
1152 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 {
1154 _engineStatisticsPtr->SetLastError(
1155 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1156 "Channel::Init() RTP/RTCP module not initialized");
1157 return -1;
1158 }
1159
1160 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 const bool fail =
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 (_audioCodingModule.RegisterTransportCallback(this) == -1) ||
1163 (_audioCodingModule.RegisterVADCallback(this) == -1);
1164
1165 if (fail)
1166 {
1167 _engineStatisticsPtr->SetLastError(
1168 VE_CANNOT_INIT_CHANNEL, kTraceError,
1169 "Channel::Init() callbacks not registered");
1170 return -1;
1171 }
1172
1173 // --- Register all supported codecs to the receiving side of the
1174 // RTP/RTCP module
1175
1176 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001177 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001178
1179 for (int idx = 0; idx < nSupportedCodecs; idx++)
1180 {
1181 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001182 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001183 (rtp_receiver_->RegisterReceivePayload(
1184 codec.plname,
1185 codec.pltype,
1186 codec.plfreq,
1187 codec.channels,
1188 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 {
1190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1191 VoEId(_instanceId,_channelId),
1192 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1193 "to RTP/RTCP receiver",
1194 codec.plname, codec.pltype, codec.plfreq,
1195 codec.channels, codec.rate);
1196 }
1197 else
1198 {
1199 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1202 "the RTP/RTCP receiver",
1203 codec.plname, codec.pltype, codec.plfreq,
1204 codec.channels, codec.rate);
1205 }
1206
1207 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001208 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 {
1210 SetSendCodec(codec);
1211 }
1212
1213 // Register default PT for outband 'telephone-event'
1214 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1215 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001216 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 (_audioCodingModule.RegisterReceiveCodec(codec) == -1))
1218 {
1219 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1220 VoEId(_instanceId,_channelId),
1221 "Channel::Init() failed to register outband "
1222 "'telephone-event' (%d/%d) correctly",
1223 codec.pltype, codec.plfreq);
1224 }
1225 }
1226
1227 if (!STR_CASE_CMP(codec.plname, "CN"))
1228 {
1229 if ((_audioCodingModule.RegisterSendCodec(codec) == -1) ||
1230 (_audioCodingModule.RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001231 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001232 {
1233 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1234 VoEId(_instanceId,_channelId),
1235 "Channel::Init() failed to register CN (%d/%d) "
1236 "correctly - 1",
1237 codec.pltype, codec.plfreq);
1238 }
1239 }
1240#ifdef WEBRTC_CODEC_RED
1241 // Register RED to the receiving side of the ACM.
1242 // We will not receive an OnInitializeDecoder() callback for RED.
1243 if (!STR_CASE_CMP(codec.plname, "RED"))
1244 {
1245 if (_audioCodingModule.RegisterReceiveCodec(codec) == -1)
1246 {
1247 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1248 VoEId(_instanceId,_channelId),
1249 "Channel::Init() failed to register RED (%d/%d) "
1250 "correctly",
1251 codec.pltype, codec.plfreq);
1252 }
1253 }
1254#endif
1255 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001256
niklase@google.com470e71d2011-07-07 08:21:25 +00001257 // Initialize the far end AP module
1258 // Using 8 kHz as initial Fs, the same as in transmission. Might be
1259 // changed at the first receiving audio.
1260 if (_rxAudioProcessingModulePtr == NULL)
1261 {
1262 _engineStatisticsPtr->SetLastError(
1263 VE_NO_MEMORY, kTraceCritical,
1264 "Channel::Init() failed to create the far-end AudioProcessing"
1265 " module");
1266 return -1;
1267 }
1268
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 if (_rxAudioProcessingModulePtr->set_sample_rate_hz(8000))
1270 {
1271 _engineStatisticsPtr->SetLastError(
1272 VE_APM_ERROR, kTraceWarning,
1273 "Channel::Init() failed to set the sample rate to 8K for"
1274 " far-end AP module");
1275 }
1276
1277 if (_rxAudioProcessingModulePtr->set_num_channels(1, 1) != 0)
1278 {
1279 _engineStatisticsPtr->SetLastError(
1280 VE_SOUNDCARD_ERROR, kTraceWarning,
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001281 "Init() failed to set channels for the primary audio stream");
niklase@google.com470e71d2011-07-07 08:21:25 +00001282 }
1283
1284 if (_rxAudioProcessingModulePtr->high_pass_filter()->Enable(
1285 WEBRTC_VOICE_ENGINE_RX_HP_DEFAULT_STATE) != 0)
1286 {
1287 _engineStatisticsPtr->SetLastError(
1288 VE_APM_ERROR, kTraceWarning,
1289 "Channel::Init() failed to set the high-pass filter for"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001290 " far-end AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001291 }
1292
1293 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(
1294 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE) != 0)
1295 {
1296 _engineStatisticsPtr->SetLastError(
1297 VE_APM_ERROR, kTraceWarning,
1298 "Init() failed to set noise reduction level for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001299 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 }
1301 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(
1302 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_STATE) != 0)
1303 {
1304 _engineStatisticsPtr->SetLastError(
1305 VE_APM_ERROR, kTraceWarning,
1306 "Init() failed to set noise reduction state for far-end"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00001307 " AP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 }
1309
1310 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(
1311 (GainControl::Mode)WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_MODE) != 0)
1312 {
1313 _engineStatisticsPtr->SetLastError(
1314 VE_APM_ERROR, kTraceWarning,
1315 "Init() failed to set AGC mode for far-end AP module");
1316 }
1317 if (_rxAudioProcessingModulePtr->gain_control()->Enable(
1318 WEBRTC_VOICE_ENGINE_RX_AGC_DEFAULT_STATE) != 0)
1319 {
1320 _engineStatisticsPtr->SetLastError(
1321 VE_APM_ERROR, kTraceWarning,
1322 "Init() failed to set AGC state for far-end AP module");
1323 }
1324
1325 return 0;
1326}
1327
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001328int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001329Channel::SetEngineInformation(Statistics& engineStatistics,
1330 OutputMixer& outputMixer,
1331 voe::TransmitMixer& transmitMixer,
1332 ProcessThread& moduleProcessThread,
1333 AudioDeviceModule& audioDeviceModule,
1334 VoiceEngineObserver* voiceEngineObserver,
1335 CriticalSectionWrapper* callbackCritSect)
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::SetEngineInformation()");
1339 _engineStatisticsPtr = &engineStatistics;
1340 _outputMixerPtr = &outputMixer;
1341 _transmitMixerPtr = &transmitMixer,
1342 _moduleProcessThreadPtr = &moduleProcessThread;
1343 _audioDeviceModulePtr = &audioDeviceModule;
1344 _voiceEngineObserverPtr = voiceEngineObserver;
1345 _callbackCritSectPtr = callbackCritSect;
1346 return 0;
1347}
1348
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001349int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001350Channel::UpdateLocalTimeStamp()
1351{
1352
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001353 _timeStamp += _audioFrame.samples_per_channel_;
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::StartPlayout()
1359{
1360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1361 "Channel::StartPlayout()");
1362 if (_playing)
1363 {
1364 return 0;
1365 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001366
1367 if (!_externalMixing) {
1368 // Add participant as candidates for mixing.
1369 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1370 {
1371 _engineStatisticsPtr->SetLastError(
1372 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1373 "StartPlayout() failed to add participant to mixer");
1374 return -1;
1375 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 }
1377
1378 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001379
1380 if (RegisterFilePlayingToMixer() != 0)
1381 return -1;
1382
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 return 0;
1384}
1385
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001386int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001387Channel::StopPlayout()
1388{
1389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1390 "Channel::StopPlayout()");
1391 if (!_playing)
1392 {
1393 return 0;
1394 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001395
1396 if (!_externalMixing) {
1397 // Remove participant as candidates for mixing
1398 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1399 {
1400 _engineStatisticsPtr->SetLastError(
1401 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1402 "StopPlayout() failed to remove participant from mixer");
1403 return -1;
1404 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001405 }
1406
1407 _playing = false;
1408 _outputAudioLevel.Clear();
1409
1410 return 0;
1411}
1412
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001413int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001414Channel::StartSend()
1415{
1416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1417 "Channel::StartSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001418 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001419 // A lock is needed because |_sending| can be accessed or modified by
1420 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001421 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001422
1423 if (_sending)
1424 {
1425 return 0;
1426 }
1427 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001428 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001429
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001430 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 {
1432 _engineStatisticsPtr->SetLastError(
1433 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1434 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001435 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001436 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001437 return -1;
1438 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001439
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 return 0;
1441}
1442
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001443int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001444Channel::StopSend()
1445{
1446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1447 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001448 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001449 // A lock is needed because |_sending| can be accessed or modified by
1450 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001451 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001452
1453 if (!_sending)
1454 {
1455 return 0;
1456 }
1457 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001458 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001459
niklase@google.com470e71d2011-07-07 08:21:25 +00001460 // Reset sending SSRC and sequence number and triggers direct transmission
1461 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001462 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1463 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 {
1465 _engineStatisticsPtr->SetLastError(
1466 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1467 "StartSend() RTP/RTCP failed to stop sending");
1468 }
1469
niklase@google.com470e71d2011-07-07 08:21:25 +00001470 return 0;
1471}
1472
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001473int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001474Channel::StartReceiving()
1475{
1476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1477 "Channel::StartReceiving()");
1478 if (_receiving)
1479 {
1480 return 0;
1481 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 _receiving = true;
1483 _numberOfDiscardedPackets = 0;
1484 return 0;
1485}
1486
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001487int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001488Channel::StopReceiving()
1489{
1490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1491 "Channel::StopReceiving()");
1492 if (!_receiving)
1493 {
1494 return 0;
1495 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001496
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001497 // Recover DTMF detection status.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001498 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 RegisterReceiveCodecsToRTPModule();
1500 _receiving = false;
1501 return 0;
1502}
1503
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001504int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001505Channel::SetNetEQPlayoutMode(NetEqModes mode)
1506{
1507 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1508 "Channel::SetNetEQPlayoutMode()");
1509 AudioPlayoutMode playoutMode(voice);
1510 switch (mode)
1511 {
1512 case kNetEqDefault:
1513 playoutMode = voice;
1514 break;
1515 case kNetEqStreaming:
1516 playoutMode = streaming;
1517 break;
1518 case kNetEqFax:
1519 playoutMode = fax;
1520 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001521 case kNetEqOff:
1522 playoutMode = off;
1523 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 }
1525 if (_audioCodingModule.SetPlayoutMode(playoutMode) != 0)
1526 {
1527 _engineStatisticsPtr->SetLastError(
1528 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1529 "SetNetEQPlayoutMode() failed to set playout mode");
1530 return -1;
1531 }
1532 return 0;
1533}
1534
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001535int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001536Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1537{
1538 const AudioPlayoutMode playoutMode = _audioCodingModule.PlayoutMode();
1539 switch (playoutMode)
1540 {
1541 case voice:
1542 mode = kNetEqDefault;
1543 break;
1544 case streaming:
1545 mode = kNetEqStreaming;
1546 break;
1547 case fax:
1548 mode = kNetEqFax;
1549 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001550 case off:
1551 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001552 }
1553 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1554 VoEId(_instanceId,_channelId),
1555 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1556 return 0;
1557}
1558
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001559int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001560Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1561{
1562 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1563 "Channel::SetOnHoldStatus()");
1564 if (mode == kHoldSendAndPlay)
1565 {
1566 _outputIsOnHold = enable;
1567 _inputIsOnHold = enable;
1568 }
1569 else if (mode == kHoldPlayOnly)
1570 {
1571 _outputIsOnHold = enable;
1572 }
1573 if (mode == kHoldSendOnly)
1574 {
1575 _inputIsOnHold = enable;
1576 }
1577 return 0;
1578}
1579
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001580int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001581Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1582{
1583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1584 "Channel::GetOnHoldStatus()");
1585 enabled = (_outputIsOnHold || _inputIsOnHold);
1586 if (_outputIsOnHold && _inputIsOnHold)
1587 {
1588 mode = kHoldSendAndPlay;
1589 }
1590 else if (_outputIsOnHold && !_inputIsOnHold)
1591 {
1592 mode = kHoldPlayOnly;
1593 }
1594 else if (!_outputIsOnHold && _inputIsOnHold)
1595 {
1596 mode = kHoldSendOnly;
1597 }
1598 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1599 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1600 enabled, mode);
1601 return 0;
1602}
1603
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001604int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001605Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1606{
1607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1608 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001609 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001610
1611 if (_voiceEngineObserverPtr)
1612 {
1613 _engineStatisticsPtr->SetLastError(
1614 VE_INVALID_OPERATION, kTraceError,
1615 "RegisterVoiceEngineObserver() observer already enabled");
1616 return -1;
1617 }
1618 _voiceEngineObserverPtr = &observer;
1619 return 0;
1620}
1621
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001622int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001623Channel::DeRegisterVoiceEngineObserver()
1624{
1625 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1626 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001627 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001628
1629 if (!_voiceEngineObserverPtr)
1630 {
1631 _engineStatisticsPtr->SetLastError(
1632 VE_INVALID_OPERATION, kTraceWarning,
1633 "DeRegisterVoiceEngineObserver() observer already disabled");
1634 return 0;
1635 }
1636 _voiceEngineObserverPtr = NULL;
1637 return 0;
1638}
1639
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001640int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001641Channel::GetSendCodec(CodecInst& codec)
1642{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001643 return (_audioCodingModule.SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001644}
1645
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001646int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001647Channel::GetRecCodec(CodecInst& codec)
1648{
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001649 return (_audioCodingModule.ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001650}
1651
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001652int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001653Channel::SetSendCodec(const CodecInst& codec)
1654{
1655 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1656 "Channel::SetSendCodec()");
1657
1658 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1659 {
1660 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1661 "SetSendCodec() failed to register codec to ACM");
1662 return -1;
1663 }
1664
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001665 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001666 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001667 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1668 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001669 {
1670 WEBRTC_TRACE(
1671 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1672 "SetSendCodec() failed to register codec to"
1673 " RTP/RTCP module");
1674 return -1;
1675 }
1676 }
1677
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001678 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001679 {
1680 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1681 "SetSendCodec() failed to set audio packet size");
1682 return -1;
1683 }
1684
1685 return 0;
1686}
1687
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001688int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001689Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1690{
1691 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1692 "Channel::SetVADStatus(mode=%d)", mode);
1693 // To disable VAD, DTX must be disabled too
1694 disableDTX = ((enableVAD == false) ? true : disableDTX);
1695 if (_audioCodingModule.SetVAD(!disableDTX, enableVAD, mode) != 0)
1696 {
1697 _engineStatisticsPtr->SetLastError(
1698 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1699 "SetVADStatus() failed to set VAD");
1700 return -1;
1701 }
1702 return 0;
1703}
1704
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001705int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001706Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1707{
1708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1709 "Channel::GetVADStatus");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001710 if (_audioCodingModule.VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001711 {
1712 _engineStatisticsPtr->SetLastError(
1713 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1714 "GetVADStatus() failed to get VAD status");
1715 return -1;
1716 }
1717 disabledDTX = !disabledDTX;
1718 return 0;
1719}
1720
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001721int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001722Channel::SetRecPayloadType(const CodecInst& codec)
1723{
1724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1725 "Channel::SetRecPayloadType()");
1726
1727 if (_playing)
1728 {
1729 _engineStatisticsPtr->SetLastError(
1730 VE_ALREADY_PLAYING, kTraceError,
1731 "SetRecPayloadType() unable to set PT while playing");
1732 return -1;
1733 }
1734 if (_receiving)
1735 {
1736 _engineStatisticsPtr->SetLastError(
1737 VE_ALREADY_LISTENING, kTraceError,
1738 "SetRecPayloadType() unable to set PT while listening");
1739 return -1;
1740 }
1741
1742 if (codec.pltype == -1)
1743 {
1744 // De-register the selected codec (RTP/RTCP module and ACM)
1745
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001746 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001747 CodecInst rxCodec = codec;
1748
1749 // Get payload type for the given codec
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001750 rtp_payload_registry_->ReceivePayloadType(
1751 rxCodec.plname,
1752 rxCodec.plfreq,
1753 rxCodec.channels,
1754 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1755 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001756 rxCodec.pltype = pltype;
1757
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001758 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001759 {
1760 _engineStatisticsPtr->SetLastError(
1761 VE_RTP_RTCP_MODULE_ERROR,
1762 kTraceError,
1763 "SetRecPayloadType() RTP/RTCP-module deregistration "
1764 "failed");
1765 return -1;
1766 }
1767 if (_audioCodingModule.UnregisterReceiveCodec(rxCodec.pltype) != 0)
1768 {
1769 _engineStatisticsPtr->SetLastError(
1770 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1771 "SetRecPayloadType() ACM deregistration failed - 1");
1772 return -1;
1773 }
1774 return 0;
1775 }
1776
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001777 if (rtp_receiver_->RegisterReceivePayload(
1778 codec.plname,
1779 codec.pltype,
1780 codec.plfreq,
1781 codec.channels,
1782 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001783 {
1784 // First attempt to register failed => de-register and try again
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001785 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1786 if (rtp_receiver_->RegisterReceivePayload(
1787 codec.plname,
1788 codec.pltype,
1789 codec.plfreq,
1790 codec.channels,
1791 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001792 {
1793 _engineStatisticsPtr->SetLastError(
1794 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1795 "SetRecPayloadType() RTP/RTCP-module registration failed");
1796 return -1;
1797 }
1798 }
1799 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1800 {
1801 _audioCodingModule.UnregisterReceiveCodec(codec.pltype);
1802 if (_audioCodingModule.RegisterReceiveCodec(codec) != 0)
1803 {
1804 _engineStatisticsPtr->SetLastError(
1805 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1806 "SetRecPayloadType() ACM registration failed - 1");
1807 return -1;
1808 }
1809 }
1810 return 0;
1811}
1812
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001813int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001814Channel::GetRecPayloadType(CodecInst& codec)
1815{
1816 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1817 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001818 int8_t payloadType(-1);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00001819 if (rtp_payload_registry_->ReceivePayloadType(
1820 codec.plname,
1821 codec.plfreq,
1822 codec.channels,
1823 (codec.rate < 0) ? 0 : codec.rate,
1824 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001825 {
1826 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001827 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001828 "GetRecPayloadType() failed to retrieve RX payload type");
1829 return -1;
1830 }
1831 codec.pltype = payloadType;
1832 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1833 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1834 return 0;
1835}
1836
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001837int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001838Channel::SetAMREncFormat(AmrMode mode)
1839{
1840 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1841 "Channel::SetAMREncFormat()");
1842
1843 // ACM doesn't support AMR
1844 return -1;
1845}
1846
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001847int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001848Channel::SetAMRDecFormat(AmrMode mode)
1849{
1850 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1851 "Channel::SetAMRDecFormat()");
1852
1853 // ACM doesn't support AMR
1854 return -1;
1855}
1856
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001857int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001858Channel::SetAMRWbEncFormat(AmrMode mode)
1859{
1860 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1861 "Channel::SetAMRWbEncFormat()");
1862
1863 // ACM doesn't support AMR
1864 return -1;
1865
1866}
1867
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001868int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001869Channel::SetAMRWbDecFormat(AmrMode mode)
1870{
1871 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1872 "Channel::SetAMRWbDecFormat()");
1873
1874 // ACM doesn't support AMR
1875 return -1;
1876}
1877
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001878int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001879Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1880{
1881 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1882 "Channel::SetSendCNPayloadType()");
1883
1884 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001885 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001886 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001887 if (frequency == kFreq32000Hz)
1888 samplingFreqHz = 32000;
1889 else if (frequency == kFreq16000Hz)
1890 samplingFreqHz = 16000;
1891
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001892 if (_audioCodingModule.Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001893 {
1894 _engineStatisticsPtr->SetLastError(
1895 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1896 "SetSendCNPayloadType() failed to retrieve default CN codec "
1897 "settings");
1898 return -1;
1899 }
1900
1901 // Modify the payload type (must be set to dynamic range)
1902 codec.pltype = type;
1903
1904 if (_audioCodingModule.RegisterSendCodec(codec) != 0)
1905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1908 "SetSendCNPayloadType() failed to register CN to ACM");
1909 return -1;
1910 }
1911
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001912 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001913 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001914 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1915 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001916 {
1917 _engineStatisticsPtr->SetLastError(
1918 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1919 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1920 "module");
1921 return -1;
1922 }
1923 }
1924 return 0;
1925}
1926
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001927int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001928Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1929{
1930 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1931 "Channel::SetISACInitTargetRate()");
1932
1933 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00001934 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 {
1936 _engineStatisticsPtr->SetLastError(
1937 VE_CODEC_ERROR, kTraceError,
1938 "SetISACInitTargetRate() failed to retrieve send codec");
1939 return -1;
1940 }
1941 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1942 {
1943 // This API is only valid if iSAC is setup to run in channel-adaptive
1944 // mode.
1945 // We do not validate the adaptive mode here. It is done later in the
1946 // ConfigISACBandwidthEstimator() API.
1947 _engineStatisticsPtr->SetLastError(
1948 VE_CODEC_ERROR, kTraceError,
1949 "SetISACInitTargetRate() send codec is not iSAC");
1950 return -1;
1951 }
1952
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001953 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001954 if (16000 == sendCodec.plfreq)
1955 {
1956 // Note that 0 is a valid and corresponds to "use default
1957 if ((rateBps != 0 &&
1958 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1959 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1960 {
1961 _engineStatisticsPtr->SetLastError(
1962 VE_INVALID_ARGUMENT, kTraceError,
1963 "SetISACInitTargetRate() invalid target rate - 1");
1964 return -1;
1965 }
1966 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001967 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001968 }
1969 else if (32000 == sendCodec.plfreq)
1970 {
1971 if ((rateBps != 0 &&
1972 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1973 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1974 {
1975 _engineStatisticsPtr->SetLastError(
1976 VE_INVALID_ARGUMENT, kTraceError,
1977 "SetISACInitTargetRate() invalid target rate - 2");
1978 return -1;
1979 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001980 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001981 }
1982
1983 if (_audioCodingModule.ConfigISACBandwidthEstimator(
1984 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1985 {
1986 _engineStatisticsPtr->SetLastError(
1987 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1988 "SetISACInitTargetRate() iSAC BWE config failed");
1989 return -1;
1990 }
1991
1992 return 0;
1993}
1994
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001995int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001996Channel::SetISACMaxRate(int rateBps)
1997{
1998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1999 "Channel::SetISACMaxRate()");
2000
2001 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002002 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002003 {
2004 _engineStatisticsPtr->SetLastError(
2005 VE_CODEC_ERROR, kTraceError,
2006 "SetISACMaxRate() failed to retrieve send codec");
2007 return -1;
2008 }
2009 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2010 {
2011 // This API is only valid if iSAC is selected as sending codec.
2012 _engineStatisticsPtr->SetLastError(
2013 VE_CODEC_ERROR, kTraceError,
2014 "SetISACMaxRate() send codec is not iSAC");
2015 return -1;
2016 }
2017 if (16000 == sendCodec.plfreq)
2018 {
2019 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2020 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2021 {
2022 _engineStatisticsPtr->SetLastError(
2023 VE_INVALID_ARGUMENT, kTraceError,
2024 "SetISACMaxRate() invalid max rate - 1");
2025 return -1;
2026 }
2027 }
2028 else if (32000 == sendCodec.plfreq)
2029 {
2030 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2031 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2032 {
2033 _engineStatisticsPtr->SetLastError(
2034 VE_INVALID_ARGUMENT, kTraceError,
2035 "SetISACMaxRate() invalid max rate - 2");
2036 return -1;
2037 }
2038 }
2039 if (_sending)
2040 {
2041 _engineStatisticsPtr->SetLastError(
2042 VE_SENDING, kTraceError,
2043 "SetISACMaxRate() unable to set max rate while sending");
2044 return -1;
2045 }
2046
2047 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2048 // and non-adaptive mode)
2049 if (_audioCodingModule.SetISACMaxRate(rateBps) == -1)
2050 {
2051 _engineStatisticsPtr->SetLastError(
2052 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2053 "SetISACMaxRate() failed to set max rate");
2054 return -1;
2055 }
2056
2057 return 0;
2058}
2059
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002060int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002061Channel::SetISACMaxPayloadSize(int sizeBytes)
2062{
2063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2064 "Channel::SetISACMaxPayloadSize()");
2065 CodecInst sendCodec;
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00002066 if (_audioCodingModule.SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002067 {
2068 _engineStatisticsPtr->SetLastError(
2069 VE_CODEC_ERROR, kTraceError,
2070 "SetISACMaxPayloadSize() failed to retrieve send codec");
2071 return -1;
2072 }
2073 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2074 {
2075 _engineStatisticsPtr->SetLastError(
2076 VE_CODEC_ERROR, kTraceError,
2077 "SetISACMaxPayloadSize() send codec is not iSAC");
2078 return -1;
2079 }
2080 if (16000 == sendCodec.plfreq)
2081 {
2082 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2083 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2084 {
2085 _engineStatisticsPtr->SetLastError(
2086 VE_INVALID_ARGUMENT, kTraceError,
2087 "SetISACMaxPayloadSize() invalid max payload - 1");
2088 return -1;
2089 }
2090 }
2091 else if (32000 == sendCodec.plfreq)
2092 {
2093 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2094 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2095 {
2096 _engineStatisticsPtr->SetLastError(
2097 VE_INVALID_ARGUMENT, kTraceError,
2098 "SetISACMaxPayloadSize() invalid max payload - 2");
2099 return -1;
2100 }
2101 }
2102 if (_sending)
2103 {
2104 _engineStatisticsPtr->SetLastError(
2105 VE_SENDING, kTraceError,
2106 "SetISACMaxPayloadSize() unable to set max rate while sending");
2107 return -1;
2108 }
2109
2110 if (_audioCodingModule.SetISACMaxPayloadSize(sizeBytes) == -1)
2111 {
2112 _engineStatisticsPtr->SetLastError(
2113 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2114 "SetISACMaxPayloadSize() failed to set max payload size");
2115 return -1;
2116 }
2117 return 0;
2118}
2119
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002120int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002121{
2122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2123 "Channel::RegisterExternalTransport()");
2124
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002125 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002126
niklase@google.com470e71d2011-07-07 08:21:25 +00002127 if (_externalTransport)
2128 {
2129 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2130 kTraceError,
2131 "RegisterExternalTransport() external transport already enabled");
2132 return -1;
2133 }
2134 _externalTransport = true;
2135 _transportPtr = &transport;
2136 return 0;
2137}
2138
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002139int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002140Channel::DeRegisterExternalTransport()
2141{
2142 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2143 "Channel::DeRegisterExternalTransport()");
2144
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002145 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002146
niklase@google.com470e71d2011-07-07 08:21:25 +00002147 if (!_transportPtr)
2148 {
2149 _engineStatisticsPtr->SetLastError(
2150 VE_INVALID_OPERATION, kTraceWarning,
2151 "DeRegisterExternalTransport() external transport already "
2152 "disabled");
2153 return 0;
2154 }
2155 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002156 _transportPtr = NULL;
2157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2158 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002159 return 0;
2160}
2161
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002162int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002163 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2164 "Channel::ReceivedRTPPacket()");
2165
2166 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002167 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002168
2169 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002170 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2171 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002172 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2173 VoEId(_instanceId,_channelId),
2174 "Channel::SendPacket() RTP dump to input file failed");
2175 }
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002176 RTPHeader header;
2177 if (!rtp_header_parser_->Parse(reinterpret_cast<const uint8_t*>(data),
2178 static_cast<uint16_t>(length), &header)) {
2179 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideo,
2180 VoEId(_instanceId,_channelId),
2181 "IncomingPacket invalid RTP header");
2182 return -1;
2183 }
pbos@webrtc.org08933a52013-07-10 10:06:29 +00002184 header.payload_type_frequency =
2185 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org9de89a62013-07-10 12:42:15 +00002186 if (header.payload_type_frequency < 0) {
2187 return -1;
2188 }
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002189 bool retransmitted = IsPacketRetransmitted(header);
2190 bool in_order = rtp_receiver_->InOrderPacket(header.sequenceNumber);
2191 rtp_receive_statistics_->IncomingPacket(header, static_cast<uint16_t>(length),
2192 retransmitted, in_order);
2193 PayloadUnion payload_specific;
2194 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
2195 &payload_specific)) {
2196 return -1;
2197 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002198 // Deliver RTP packet to RTP/RTCP module for parsing
2199 // The packet will be pushed back to the channel thru the
2200 // OnReceivedPayloadData callback so we don't push it to the ACM here
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002201 if (!rtp_receiver_->IncomingRtpPacket(&header,
2202 reinterpret_cast<const uint8_t*>(data),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002203 static_cast<uint16_t>(length),
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002204 payload_specific, in_order)) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002205 _engineStatisticsPtr->SetLastError(
2206 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2207 "Channel::IncomingRTPPacket() RTP packet is invalid");
2208 }
2209 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002210}
2211
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002212bool Channel::IsPacketRetransmitted(const RTPHeader& header) const {
2213 bool rtx_enabled = false;
2214 uint32_t rtx_ssrc = 0;
2215 int rtx_payload_type = 0;
2216 rtp_receiver_->RTXStatus(&rtx_enabled, &rtx_ssrc, &rtx_payload_type);
2217 if (!rtx_enabled) {
2218 // Check if this is a retransmission.
stefan@webrtc.org717d1472013-07-10 13:39:27 +00002219 StreamStatistician::Statistics stats;
2220 StreamStatistician* statistician =
2221 rtp_receive_statistics_->GetStatistician(header.ssrc);
2222 if (statistician && statistician->GetStatistics(&stats, false)) {
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00002223 uint16_t min_rtt = 0;
2224 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
2225 return rtp_receiver_->RetransmitOfOldPacket(header, stats.jitter,
2226 min_rtt);
2227 }
2228 }
2229 return false;
2230}
2231
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002232int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002233 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2234 "Channel::ReceivedRTCPPacket()");
2235 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002236 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002237
2238 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002239 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2240 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002241 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2242 VoEId(_instanceId,_channelId),
2243 "Channel::SendPacket() RTCP dump to input file failed");
2244 }
2245
2246 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002247 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2248 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002249 _engineStatisticsPtr->SetLastError(
2250 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2251 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2252 }
2253 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002254}
2255
niklase@google.com470e71d2011-07-07 08:21:25 +00002256int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002257 bool loop,
2258 FileFormats format,
2259 int startPosition,
2260 float volumeScaling,
2261 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002262 const CodecInst* codecInst)
2263{
2264 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2265 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2266 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2267 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2268 startPosition, stopPosition);
2269
2270 if (_outputFilePlaying)
2271 {
2272 _engineStatisticsPtr->SetLastError(
2273 VE_ALREADY_PLAYING, kTraceError,
2274 "StartPlayingFileLocally() is already playing");
2275 return -1;
2276 }
2277
niklase@google.com470e71d2011-07-07 08:21:25 +00002278 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002279 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002280
2281 if (_outputFilePlayerPtr)
2282 {
2283 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2284 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2285 _outputFilePlayerPtr = NULL;
2286 }
2287
2288 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2289 _outputFilePlayerId, (const FileFormats)format);
2290
2291 if (_outputFilePlayerPtr == NULL)
2292 {
2293 _engineStatisticsPtr->SetLastError(
2294 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002295 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002296 return -1;
2297 }
2298
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002299 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002300
2301 if (_outputFilePlayerPtr->StartPlayingFile(
2302 fileName,
2303 loop,
2304 startPosition,
2305 volumeScaling,
2306 notificationTime,
2307 stopPosition,
2308 (const CodecInst*)codecInst) != 0)
2309 {
2310 _engineStatisticsPtr->SetLastError(
2311 VE_BAD_FILE, kTraceError,
2312 "StartPlayingFile() failed to start file playout");
2313 _outputFilePlayerPtr->StopPlayingFile();
2314 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2315 _outputFilePlayerPtr = NULL;
2316 return -1;
2317 }
2318 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2319 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002320 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002321
2322 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002323 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002324
2325 return 0;
2326}
2327
2328int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002329 FileFormats format,
2330 int startPosition,
2331 float volumeScaling,
2332 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002333 const CodecInst* codecInst)
2334{
2335 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2336 "Channel::StartPlayingFileLocally(format=%d,"
2337 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2338 format, volumeScaling, startPosition, stopPosition);
2339
2340 if(stream == NULL)
2341 {
2342 _engineStatisticsPtr->SetLastError(
2343 VE_BAD_FILE, kTraceError,
2344 "StartPlayingFileLocally() NULL as input stream");
2345 return -1;
2346 }
2347
2348
2349 if (_outputFilePlaying)
2350 {
2351 _engineStatisticsPtr->SetLastError(
2352 VE_ALREADY_PLAYING, kTraceError,
2353 "StartPlayingFileLocally() is already playing");
2354 return -1;
2355 }
2356
niklase@google.com470e71d2011-07-07 08:21:25 +00002357 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002358 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002359
2360 // Destroy the old instance
2361 if (_outputFilePlayerPtr)
2362 {
2363 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2364 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2365 _outputFilePlayerPtr = NULL;
2366 }
2367
2368 // Create the instance
2369 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2370 _outputFilePlayerId,
2371 (const FileFormats)format);
2372
2373 if (_outputFilePlayerPtr == NULL)
2374 {
2375 _engineStatisticsPtr->SetLastError(
2376 VE_INVALID_ARGUMENT, kTraceError,
2377 "StartPlayingFileLocally() filePlayer format isnot correct");
2378 return -1;
2379 }
2380
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002381 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002382
2383 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2384 volumeScaling,
2385 notificationTime,
2386 stopPosition, codecInst) != 0)
2387 {
2388 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2389 "StartPlayingFile() failed to "
2390 "start file playout");
2391 _outputFilePlayerPtr->StopPlayingFile();
2392 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2393 _outputFilePlayerPtr = NULL;
2394 return -1;
2395 }
2396 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2397 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002398 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002399
2400 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002401 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002402
niklase@google.com470e71d2011-07-07 08:21:25 +00002403 return 0;
2404}
2405
2406int Channel::StopPlayingFileLocally()
2407{
2408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2409 "Channel::StopPlayingFileLocally()");
2410
2411 if (!_outputFilePlaying)
2412 {
2413 _engineStatisticsPtr->SetLastError(
2414 VE_INVALID_OPERATION, kTraceWarning,
2415 "StopPlayingFileLocally() isnot playing");
2416 return 0;
2417 }
2418
niklase@google.com470e71d2011-07-07 08:21:25 +00002419 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002420 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002421
2422 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2423 {
2424 _engineStatisticsPtr->SetLastError(
2425 VE_STOP_RECORDING_FAILED, kTraceError,
2426 "StopPlayingFile() could not stop playing");
2427 return -1;
2428 }
2429 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2430 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2431 _outputFilePlayerPtr = NULL;
2432 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002433 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002434 // _fileCritSect cannot be taken while calling
2435 // SetAnonymousMixibilityStatus. Refer to comments in
2436 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002437 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2438 {
2439 _engineStatisticsPtr->SetLastError(
2440 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002441 "StopPlayingFile() failed to stop participant from playing as"
2442 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002443 return -1;
2444 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002445
2446 return 0;
2447}
2448
2449int Channel::IsPlayingFileLocally() const
2450{
2451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2452 "Channel::IsPlayingFileLocally()");
2453
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002454 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002455}
2456
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002457int Channel::RegisterFilePlayingToMixer()
2458{
2459 // Return success for not registering for file playing to mixer if:
2460 // 1. playing file before playout is started on that channel.
2461 // 2. starting playout without file playing on that channel.
2462 if (!_playing || !_outputFilePlaying)
2463 {
2464 return 0;
2465 }
2466
2467 // |_fileCritSect| cannot be taken while calling
2468 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2469 // frames can be pulled by the mixer. Since the frames are generated from
2470 // the file, _fileCritSect will be taken. This would result in a deadlock.
2471 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2472 {
2473 CriticalSectionScoped cs(&_fileCritSect);
2474 _outputFilePlaying = false;
2475 _engineStatisticsPtr->SetLastError(
2476 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2477 "StartPlayingFile() failed to add participant as file to mixer");
2478 _outputFilePlayerPtr->StopPlayingFile();
2479 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2480 _outputFilePlayerPtr = NULL;
2481 return -1;
2482 }
2483
2484 return 0;
2485}
2486
pbos@webrtc.org92135212013-05-14 08:31:39 +00002487int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002488{
2489 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2490 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2491
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002492 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002493
2494 if (!_outputFilePlaying)
2495 {
2496 _engineStatisticsPtr->SetLastError(
2497 VE_INVALID_OPERATION, kTraceError,
2498 "ScaleLocalFilePlayout() isnot playing");
2499 return -1;
2500 }
2501 if ((_outputFilePlayerPtr == NULL) ||
2502 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2503 {
2504 _engineStatisticsPtr->SetLastError(
2505 VE_BAD_ARGUMENT, kTraceError,
2506 "SetAudioScaling() failed to scale the playout");
2507 return -1;
2508 }
2509
2510 return 0;
2511}
2512
2513int Channel::GetLocalPlayoutPosition(int& positionMs)
2514{
2515 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2516 "Channel::GetLocalPlayoutPosition(position=?)");
2517
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002518 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002519
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002520 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002521
2522 if (_outputFilePlayerPtr == NULL)
2523 {
2524 _engineStatisticsPtr->SetLastError(
2525 VE_INVALID_OPERATION, kTraceError,
2526 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2527 return -1;
2528 }
2529
2530 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2531 {
2532 _engineStatisticsPtr->SetLastError(
2533 VE_BAD_FILE, kTraceError,
2534 "GetLocalPlayoutPosition() failed");
2535 return -1;
2536 }
2537 positionMs = position;
2538
2539 return 0;
2540}
2541
2542int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002543 bool loop,
2544 FileFormats format,
2545 int startPosition,
2546 float volumeScaling,
2547 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002548 const CodecInst* codecInst)
2549{
2550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2551 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2552 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2553 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2554 startPosition, stopPosition);
2555
2556 if (_inputFilePlaying)
2557 {
2558 _engineStatisticsPtr->SetLastError(
2559 VE_ALREADY_PLAYING, kTraceWarning,
2560 "StartPlayingFileAsMicrophone() filePlayer is playing");
2561 return 0;
2562 }
2563
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002564 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002565
2566 // Destroy the old instance
2567 if (_inputFilePlayerPtr)
2568 {
2569 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2570 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2571 _inputFilePlayerPtr = NULL;
2572 }
2573
2574 // Create the instance
2575 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2576 _inputFilePlayerId, (const FileFormats)format);
2577
2578 if (_inputFilePlayerPtr == NULL)
2579 {
2580 _engineStatisticsPtr->SetLastError(
2581 VE_INVALID_ARGUMENT, kTraceError,
2582 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2583 return -1;
2584 }
2585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002586 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002587
2588 if (_inputFilePlayerPtr->StartPlayingFile(
2589 fileName,
2590 loop,
2591 startPosition,
2592 volumeScaling,
2593 notificationTime,
2594 stopPosition,
2595 (const CodecInst*)codecInst) != 0)
2596 {
2597 _engineStatisticsPtr->SetLastError(
2598 VE_BAD_FILE, kTraceError,
2599 "StartPlayingFile() failed to start file playout");
2600 _inputFilePlayerPtr->StopPlayingFile();
2601 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2602 _inputFilePlayerPtr = NULL;
2603 return -1;
2604 }
2605 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2606 _inputFilePlaying = true;
2607
2608 return 0;
2609}
2610
2611int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002612 FileFormats format,
2613 int startPosition,
2614 float volumeScaling,
2615 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 const CodecInst* codecInst)
2617{
2618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2619 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2620 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2621 format, volumeScaling, startPosition, stopPosition);
2622
2623 if(stream == NULL)
2624 {
2625 _engineStatisticsPtr->SetLastError(
2626 VE_BAD_FILE, kTraceError,
2627 "StartPlayingFileAsMicrophone NULL as input stream");
2628 return -1;
2629 }
2630
2631 if (_inputFilePlaying)
2632 {
2633 _engineStatisticsPtr->SetLastError(
2634 VE_ALREADY_PLAYING, kTraceWarning,
2635 "StartPlayingFileAsMicrophone() is playing");
2636 return 0;
2637 }
2638
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002639 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002640
2641 // Destroy the old instance
2642 if (_inputFilePlayerPtr)
2643 {
2644 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2645 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2646 _inputFilePlayerPtr = NULL;
2647 }
2648
2649 // Create the instance
2650 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2651 _inputFilePlayerId, (const FileFormats)format);
2652
2653 if (_inputFilePlayerPtr == NULL)
2654 {
2655 _engineStatisticsPtr->SetLastError(
2656 VE_INVALID_ARGUMENT, kTraceError,
2657 "StartPlayingInputFile() filePlayer format isnot correct");
2658 return -1;
2659 }
2660
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002661 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002662
2663 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2664 volumeScaling, notificationTime,
2665 stopPosition, codecInst) != 0)
2666 {
2667 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2668 "StartPlayingFile() failed to start "
2669 "file playout");
2670 _inputFilePlayerPtr->StopPlayingFile();
2671 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2672 _inputFilePlayerPtr = NULL;
2673 return -1;
2674 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002675
niklase@google.com470e71d2011-07-07 08:21:25 +00002676 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2677 _inputFilePlaying = true;
2678
2679 return 0;
2680}
2681
2682int Channel::StopPlayingFileAsMicrophone()
2683{
2684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2685 "Channel::StopPlayingFileAsMicrophone()");
2686
2687 if (!_inputFilePlaying)
2688 {
2689 _engineStatisticsPtr->SetLastError(
2690 VE_INVALID_OPERATION, kTraceWarning,
2691 "StopPlayingFileAsMicrophone() isnot playing");
2692 return 0;
2693 }
2694
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002695 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002696 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2697 {
2698 _engineStatisticsPtr->SetLastError(
2699 VE_STOP_RECORDING_FAILED, kTraceError,
2700 "StopPlayingFile() could not stop playing");
2701 return -1;
2702 }
2703 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2704 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2705 _inputFilePlayerPtr = NULL;
2706 _inputFilePlaying = false;
2707
2708 return 0;
2709}
2710
2711int Channel::IsPlayingFileAsMicrophone() const
2712{
2713 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2714 "Channel::IsPlayingFileAsMicrophone()");
2715
2716 return _inputFilePlaying;
2717}
2718
pbos@webrtc.org92135212013-05-14 08:31:39 +00002719int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002720{
2721 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2722 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2723
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002724 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002725
2726 if (!_inputFilePlaying)
2727 {
2728 _engineStatisticsPtr->SetLastError(
2729 VE_INVALID_OPERATION, kTraceError,
2730 "ScaleFileAsMicrophonePlayout() isnot playing");
2731 return -1;
2732 }
2733
2734 if ((_inputFilePlayerPtr == NULL) ||
2735 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2736 {
2737 _engineStatisticsPtr->SetLastError(
2738 VE_BAD_ARGUMENT, kTraceError,
2739 "SetAudioScaling() failed to scale playout");
2740 return -1;
2741 }
2742
2743 return 0;
2744}
2745
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002746int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002747 const CodecInst* codecInst)
2748{
2749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2750 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2751
2752 if (_outputFileRecording)
2753 {
2754 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2755 "StartRecordingPlayout() is already recording");
2756 return 0;
2757 }
2758
2759 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002760 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2762
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002763 if ((codecInst != NULL) &&
2764 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002765 {
2766 _engineStatisticsPtr->SetLastError(
2767 VE_BAD_ARGUMENT, kTraceError,
2768 "StartRecordingPlayout() invalid compression");
2769 return(-1);
2770 }
2771 if(codecInst == NULL)
2772 {
2773 format = kFileFormatPcm16kHzFile;
2774 codecInst=&dummyCodec;
2775 }
2776 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2777 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2778 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2779 {
2780 format = kFileFormatWavFile;
2781 }
2782 else
2783 {
2784 format = kFileFormatCompressedFile;
2785 }
2786
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002787 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002788
2789 // Destroy the old instance
2790 if (_outputFileRecorderPtr)
2791 {
2792 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2793 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2794 _outputFileRecorderPtr = NULL;
2795 }
2796
2797 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2798 _outputFileRecorderId, (const FileFormats)format);
2799 if (_outputFileRecorderPtr == NULL)
2800 {
2801 _engineStatisticsPtr->SetLastError(
2802 VE_INVALID_ARGUMENT, kTraceError,
2803 "StartRecordingPlayout() fileRecorder format isnot correct");
2804 return -1;
2805 }
2806
2807 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2808 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2809 {
2810 _engineStatisticsPtr->SetLastError(
2811 VE_BAD_FILE, kTraceError,
2812 "StartRecordingAudioFile() failed to start file recording");
2813 _outputFileRecorderPtr->StopRecording();
2814 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2815 _outputFileRecorderPtr = NULL;
2816 return -1;
2817 }
2818 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2819 _outputFileRecording = true;
2820
2821 return 0;
2822}
2823
2824int Channel::StartRecordingPlayout(OutStream* stream,
2825 const CodecInst* codecInst)
2826{
2827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2828 "Channel::StartRecordingPlayout()");
2829
2830 if (_outputFileRecording)
2831 {
2832 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2833 "StartRecordingPlayout() is already recording");
2834 return 0;
2835 }
2836
2837 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002838 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002839 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2840
2841 if (codecInst != NULL && codecInst->channels != 1)
2842 {
2843 _engineStatisticsPtr->SetLastError(
2844 VE_BAD_ARGUMENT, kTraceError,
2845 "StartRecordingPlayout() invalid compression");
2846 return(-1);
2847 }
2848 if(codecInst == NULL)
2849 {
2850 format = kFileFormatPcm16kHzFile;
2851 codecInst=&dummyCodec;
2852 }
2853 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2854 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2855 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2856 {
2857 format = kFileFormatWavFile;
2858 }
2859 else
2860 {
2861 format = kFileFormatCompressedFile;
2862 }
2863
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002864 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002865
2866 // Destroy the old instance
2867 if (_outputFileRecorderPtr)
2868 {
2869 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2870 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2871 _outputFileRecorderPtr = NULL;
2872 }
2873
2874 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2875 _outputFileRecorderId, (const FileFormats)format);
2876 if (_outputFileRecorderPtr == NULL)
2877 {
2878 _engineStatisticsPtr->SetLastError(
2879 VE_INVALID_ARGUMENT, kTraceError,
2880 "StartRecordingPlayout() fileRecorder format isnot correct");
2881 return -1;
2882 }
2883
2884 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2885 notificationTime) != 0)
2886 {
2887 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2888 "StartRecordingPlayout() failed to "
2889 "start file recording");
2890 _outputFileRecorderPtr->StopRecording();
2891 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2892 _outputFileRecorderPtr = NULL;
2893 return -1;
2894 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002895
niklase@google.com470e71d2011-07-07 08:21:25 +00002896 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2897 _outputFileRecording = true;
2898
2899 return 0;
2900}
2901
2902int Channel::StopRecordingPlayout()
2903{
2904 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2905 "Channel::StopRecordingPlayout()");
2906
2907 if (!_outputFileRecording)
2908 {
2909 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2910 "StopRecordingPlayout() isnot recording");
2911 return -1;
2912 }
2913
2914
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002915 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002916
2917 if (_outputFileRecorderPtr->StopRecording() != 0)
2918 {
2919 _engineStatisticsPtr->SetLastError(
2920 VE_STOP_RECORDING_FAILED, kTraceError,
2921 "StopRecording() could not stop recording");
2922 return(-1);
2923 }
2924 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2925 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2926 _outputFileRecorderPtr = NULL;
2927 _outputFileRecording = false;
2928
2929 return 0;
2930}
2931
2932void
2933Channel::SetMixWithMicStatus(bool mix)
2934{
2935 _mixFileWithMicrophone=mix;
2936}
2937
2938int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002939Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002940{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002941 int8_t currentLevel = _outputAudioLevel.Level();
2942 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002943 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2944 VoEId(_instanceId,_channelId),
2945 "GetSpeechOutputLevel() => level=%u", level);
2946 return 0;
2947}
2948
2949int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002950Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002951{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002952 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2953 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002954 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2955 VoEId(_instanceId,_channelId),
2956 "GetSpeechOutputLevelFullRange() => level=%u", level);
2957 return 0;
2958}
2959
2960int
2961Channel::SetMute(bool enable)
2962{
2963 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2964 "Channel::SetMute(enable=%d)", enable);
2965 _mute = enable;
2966 return 0;
2967}
2968
2969bool
2970Channel::Mute() const
2971{
2972 return _mute;
2973}
2974
2975int
2976Channel::SetOutputVolumePan(float left, float right)
2977{
2978 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2979 "Channel::SetOutputVolumePan()");
2980 _panLeft = left;
2981 _panRight = right;
2982 return 0;
2983}
2984
2985int
2986Channel::GetOutputVolumePan(float& left, float& right) const
2987{
2988 left = _panLeft;
2989 right = _panRight;
2990 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2991 VoEId(_instanceId,_channelId),
2992 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2993 return 0;
2994}
2995
2996int
2997Channel::SetChannelOutputVolumeScaling(float scaling)
2998{
2999 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3000 "Channel::SetChannelOutputVolumeScaling()");
3001 _outputGain = scaling;
3002 return 0;
3003}
3004
3005int
3006Channel::GetChannelOutputVolumeScaling(float& scaling) const
3007{
3008 scaling = _outputGain;
3009 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3010 VoEId(_instanceId,_channelId),
3011 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3012 return 0;
3013}
3014
niklase@google.com470e71d2011-07-07 08:21:25 +00003015int
3016Channel::RegisterExternalEncryption(Encryption& encryption)
3017{
3018 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3019 "Channel::RegisterExternalEncryption()");
3020
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003021 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003022
3023 if (_encryptionPtr)
3024 {
3025 _engineStatisticsPtr->SetLastError(
3026 VE_INVALID_OPERATION, kTraceError,
3027 "RegisterExternalEncryption() encryption already enabled");
3028 return -1;
3029 }
3030
3031 _encryptionPtr = &encryption;
3032
3033 _decrypting = true;
3034 _encrypting = true;
3035
3036 return 0;
3037}
3038
3039int
3040Channel::DeRegisterExternalEncryption()
3041{
3042 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3043 "Channel::DeRegisterExternalEncryption()");
3044
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003045 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003046
3047 if (!_encryptionPtr)
3048 {
3049 _engineStatisticsPtr->SetLastError(
3050 VE_INVALID_OPERATION, kTraceWarning,
3051 "DeRegisterExternalEncryption() encryption already disabled");
3052 return 0;
3053 }
3054
3055 _decrypting = false;
3056 _encrypting = false;
3057
3058 _encryptionPtr = NULL;
3059
3060 return 0;
3061}
3062
3063int Channel::SendTelephoneEventOutband(unsigned char eventCode,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003064 int lengthMs, int attenuationDb,
3065 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003066{
3067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3068 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3069 playDtmfEvent);
3070
3071 _playOutbandDtmfEvent = playDtmfEvent;
3072
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003073 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003074 attenuationDb) != 0)
3075 {
3076 _engineStatisticsPtr->SetLastError(
3077 VE_SEND_DTMF_FAILED,
3078 kTraceWarning,
3079 "SendTelephoneEventOutband() failed to send event");
3080 return -1;
3081 }
3082 return 0;
3083}
3084
3085int Channel::SendTelephoneEventInband(unsigned char eventCode,
3086 int lengthMs,
3087 int attenuationDb,
3088 bool playDtmfEvent)
3089{
3090 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3091 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3092 playDtmfEvent);
3093
3094 _playInbandDtmfEvent = playDtmfEvent;
3095 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3096
3097 return 0;
3098}
3099
3100int
3101Channel::SetDtmfPlayoutStatus(bool enable)
3102{
3103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3104 "Channel::SetDtmfPlayoutStatus()");
3105 if (_audioCodingModule.SetDtmfPlayoutStatus(enable) != 0)
3106 {
3107 _engineStatisticsPtr->SetLastError(
3108 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3109 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3110 return -1;
3111 }
3112 return 0;
3113}
3114
3115bool
3116Channel::DtmfPlayoutStatus() const
3117{
3118 return _audioCodingModule.DtmfPlayoutStatus();
3119}
3120
3121int
3122Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3123{
3124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3125 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003126 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 {
3128 _engineStatisticsPtr->SetLastError(
3129 VE_INVALID_ARGUMENT, kTraceError,
3130 "SetSendTelephoneEventPayloadType() invalid type");
3131 return -1;
3132 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003133 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003134 codec.plfreq = 8000;
3135 codec.pltype = type;
3136 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003137 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003138 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003139 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3140 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3141 _engineStatisticsPtr->SetLastError(
3142 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3143 "SetSendTelephoneEventPayloadType() failed to register send"
3144 "payload type");
3145 return -1;
3146 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003147 }
3148 _sendTelephoneEventPayloadType = type;
3149 return 0;
3150}
3151
3152int
3153Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3154{
3155 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3156 "Channel::GetSendTelephoneEventPayloadType()");
3157 type = _sendTelephoneEventPayloadType;
3158 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3159 VoEId(_instanceId,_channelId),
3160 "GetSendTelephoneEventPayloadType() => type=%u", type);
3161 return 0;
3162}
3163
niklase@google.com470e71d2011-07-07 08:21:25 +00003164int
3165Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3166{
3167 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3168 "Channel::UpdateRxVadDetection()");
3169
3170 int vadDecision = 1;
3171
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003172 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003173
3174 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3175 {
3176 OnRxVadDetected(vadDecision);
3177 _oldVadDecision = vadDecision;
3178 }
3179
3180 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3181 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3182 vadDecision);
3183 return 0;
3184}
3185
3186int
3187Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3188{
3189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3190 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003191 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003192
3193 if (_rxVadObserverPtr)
3194 {
3195 _engineStatisticsPtr->SetLastError(
3196 VE_INVALID_OPERATION, kTraceError,
3197 "RegisterRxVadObserver() observer already enabled");
3198 return -1;
3199 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003200 _rxVadObserverPtr = &observer;
3201 _RxVadDetection = true;
3202 return 0;
3203}
3204
3205int
3206Channel::DeRegisterRxVadObserver()
3207{
3208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3209 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003210 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003211
3212 if (!_rxVadObserverPtr)
3213 {
3214 _engineStatisticsPtr->SetLastError(
3215 VE_INVALID_OPERATION, kTraceWarning,
3216 "DeRegisterRxVadObserver() observer already disabled");
3217 return 0;
3218 }
3219 _rxVadObserverPtr = NULL;
3220 _RxVadDetection = false;
3221 return 0;
3222}
3223
3224int
3225Channel::VoiceActivityIndicator(int &activity)
3226{
3227 activity = _sendFrameType;
3228
3229 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3230 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
3231 return 0;
3232}
3233
3234#ifdef WEBRTC_VOICE_ENGINE_AGC
3235
3236int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003237Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003238{
3239 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3240 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3241 (int)enable, (int)mode);
3242
3243 GainControl::Mode agcMode(GainControl::kFixedDigital);
3244 switch (mode)
3245 {
3246 case kAgcDefault:
3247 agcMode = GainControl::kAdaptiveDigital;
3248 break;
3249 case kAgcUnchanged:
3250 agcMode = _rxAudioProcessingModulePtr->gain_control()->mode();
3251 break;
3252 case kAgcFixedDigital:
3253 agcMode = GainControl::kFixedDigital;
3254 break;
3255 case kAgcAdaptiveDigital:
3256 agcMode =GainControl::kAdaptiveDigital;
3257 break;
3258 default:
3259 _engineStatisticsPtr->SetLastError(
3260 VE_INVALID_ARGUMENT, kTraceError,
3261 "SetRxAgcStatus() invalid Agc mode");
3262 return -1;
3263 }
3264
3265 if (_rxAudioProcessingModulePtr->gain_control()->set_mode(agcMode) != 0)
3266 {
3267 _engineStatisticsPtr->SetLastError(
3268 VE_APM_ERROR, kTraceError,
3269 "SetRxAgcStatus() failed to set Agc mode");
3270 return -1;
3271 }
3272 if (_rxAudioProcessingModulePtr->gain_control()->Enable(enable) != 0)
3273 {
3274 _engineStatisticsPtr->SetLastError(
3275 VE_APM_ERROR, kTraceError,
3276 "SetRxAgcStatus() failed to set Agc state");
3277 return -1;
3278 }
3279
3280 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3282
3283 return 0;
3284}
3285
3286int
3287Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3288{
3289 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3290 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3291
3292 bool enable = _rxAudioProcessingModulePtr->gain_control()->is_enabled();
3293 GainControl::Mode agcMode =
3294 _rxAudioProcessingModulePtr->gain_control()->mode();
3295
3296 enabled = enable;
3297
3298 switch (agcMode)
3299 {
3300 case GainControl::kFixedDigital:
3301 mode = kAgcFixedDigital;
3302 break;
3303 case GainControl::kAdaptiveDigital:
3304 mode = kAgcAdaptiveDigital;
3305 break;
3306 default:
3307 _engineStatisticsPtr->SetLastError(
3308 VE_APM_ERROR, kTraceError,
3309 "GetRxAgcStatus() invalid Agc mode");
3310 return -1;
3311 }
3312
3313 return 0;
3314}
3315
3316int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003317Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003318{
3319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3320 "Channel::SetRxAgcConfig()");
3321
3322 if (_rxAudioProcessingModulePtr->gain_control()->set_target_level_dbfs(
3323 config.targetLeveldBOv) != 0)
3324 {
3325 _engineStatisticsPtr->SetLastError(
3326 VE_APM_ERROR, kTraceError,
3327 "SetRxAgcConfig() failed to set target peak |level|"
3328 "(or envelope) of the Agc");
3329 return -1;
3330 }
3331 if (_rxAudioProcessingModulePtr->gain_control()->set_compression_gain_db(
3332 config.digitalCompressionGaindB) != 0)
3333 {
3334 _engineStatisticsPtr->SetLastError(
3335 VE_APM_ERROR, kTraceError,
3336 "SetRxAgcConfig() failed to set the range in |gain| the"
3337 " digital compression stage may apply");
3338 return -1;
3339 }
3340 if (_rxAudioProcessingModulePtr->gain_control()->enable_limiter(
3341 config.limiterEnable) != 0)
3342 {
3343 _engineStatisticsPtr->SetLastError(
3344 VE_APM_ERROR, kTraceError,
3345 "SetRxAgcConfig() failed to set hard limiter to the signal");
3346 return -1;
3347 }
3348
3349 return 0;
3350}
3351
3352int
3353Channel::GetRxAgcConfig(AgcConfig& config)
3354{
3355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3356 "Channel::GetRxAgcConfig(config=%?)");
3357
3358 config.targetLeveldBOv =
3359 _rxAudioProcessingModulePtr->gain_control()->target_level_dbfs();
3360 config.digitalCompressionGaindB =
3361 _rxAudioProcessingModulePtr->gain_control()->compression_gain_db();
3362 config.limiterEnable =
3363 _rxAudioProcessingModulePtr->gain_control()->is_limiter_enabled();
3364
3365 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3366 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3367 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3368 " limiterEnable=%d",
3369 config.targetLeveldBOv,
3370 config.digitalCompressionGaindB,
3371 config.limiterEnable);
3372
3373 return 0;
3374}
3375
3376#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3377
3378#ifdef WEBRTC_VOICE_ENGINE_NR
3379
3380int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003381Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003382{
3383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3384 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3385 (int)enable, (int)mode);
3386
3387 NoiseSuppression::Level nsLevel(
3388 (NoiseSuppression::Level)WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE);
3389 switch (mode)
3390 {
3391
3392 case kNsDefault:
3393 nsLevel = (NoiseSuppression::Level)
3394 WEBRTC_VOICE_ENGINE_RX_NS_DEFAULT_MODE;
3395 break;
3396 case kNsUnchanged:
3397 nsLevel = _rxAudioProcessingModulePtr->noise_suppression()->level();
3398 break;
3399 case kNsConference:
3400 nsLevel = NoiseSuppression::kHigh;
3401 break;
3402 case kNsLowSuppression:
3403 nsLevel = NoiseSuppression::kLow;
3404 break;
3405 case kNsModerateSuppression:
3406 nsLevel = NoiseSuppression::kModerate;
3407 break;
3408 case kNsHighSuppression:
3409 nsLevel = NoiseSuppression::kHigh;
3410 break;
3411 case kNsVeryHighSuppression:
3412 nsLevel = NoiseSuppression::kVeryHigh;
3413 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003414 }
3415
3416 if (_rxAudioProcessingModulePtr->noise_suppression()->set_level(nsLevel)
3417 != 0)
3418 {
3419 _engineStatisticsPtr->SetLastError(
3420 VE_APM_ERROR, kTraceError,
3421 "SetRxAgcStatus() failed to set Ns level");
3422 return -1;
3423 }
3424 if (_rxAudioProcessingModulePtr->noise_suppression()->Enable(enable) != 0)
3425 {
3426 _engineStatisticsPtr->SetLastError(
3427 VE_APM_ERROR, kTraceError,
3428 "SetRxAgcStatus() failed to set Agc state");
3429 return -1;
3430 }
3431
3432 _rxNsIsEnabled = enable;
3433 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3434
3435 return 0;
3436}
3437
3438int
3439Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3440{
3441 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3442 "Channel::GetRxNsStatus(enable=?, mode=?)");
3443
3444 bool enable =
3445 _rxAudioProcessingModulePtr->noise_suppression()->is_enabled();
3446 NoiseSuppression::Level ncLevel =
3447 _rxAudioProcessingModulePtr->noise_suppression()->level();
3448
3449 enabled = enable;
3450
3451 switch (ncLevel)
3452 {
3453 case NoiseSuppression::kLow:
3454 mode = kNsLowSuppression;
3455 break;
3456 case NoiseSuppression::kModerate:
3457 mode = kNsModerateSuppression;
3458 break;
3459 case NoiseSuppression::kHigh:
3460 mode = kNsHighSuppression;
3461 break;
3462 case NoiseSuppression::kVeryHigh:
3463 mode = kNsVeryHighSuppression;
3464 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003465 }
3466
3467 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3468 VoEId(_instanceId,_channelId),
3469 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3470 return 0;
3471}
3472
3473#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3474
3475int
3476Channel::RegisterRTPObserver(VoERTPObserver& observer)
3477{
3478 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3479 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003480 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003481
3482 if (_rtpObserverPtr)
3483 {
3484 _engineStatisticsPtr->SetLastError(
3485 VE_INVALID_OPERATION, kTraceError,
3486 "RegisterRTPObserver() observer already enabled");
3487 return -1;
3488 }
3489
3490 _rtpObserverPtr = &observer;
3491 _rtpObserver = true;
3492
3493 return 0;
3494}
3495
3496int
3497Channel::DeRegisterRTPObserver()
3498{
3499 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3500 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003501 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003502
3503 if (!_rtpObserverPtr)
3504 {
3505 _engineStatisticsPtr->SetLastError(
3506 VE_INVALID_OPERATION, kTraceWarning,
3507 "DeRegisterRTPObserver() observer already disabled");
3508 return 0;
3509 }
3510
3511 _rtpObserver = false;
3512 _rtpObserverPtr = NULL;
3513
3514 return 0;
3515}
3516
3517int
3518Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3519{
3520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3521 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003522 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003523
3524 if (_rtcpObserverPtr)
3525 {
3526 _engineStatisticsPtr->SetLastError(
3527 VE_INVALID_OPERATION, kTraceError,
3528 "RegisterRTCPObserver() observer already enabled");
3529 return -1;
3530 }
3531
3532 _rtcpObserverPtr = &observer;
3533 _rtcpObserver = true;
3534
3535 return 0;
3536}
3537
3538int
3539Channel::DeRegisterRTCPObserver()
3540{
3541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3542 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003543 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003544
3545 if (!_rtcpObserverPtr)
3546 {
3547 _engineStatisticsPtr->SetLastError(
3548 VE_INVALID_OPERATION, kTraceWarning,
3549 "DeRegisterRTCPObserver() observer already disabled");
3550 return 0;
3551 }
3552
3553 _rtcpObserver = false;
3554 _rtcpObserverPtr = NULL;
3555
3556 return 0;
3557}
3558
3559int
3560Channel::SetLocalSSRC(unsigned int ssrc)
3561{
3562 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3563 "Channel::SetLocalSSRC()");
3564 if (_sending)
3565 {
3566 _engineStatisticsPtr->SetLastError(
3567 VE_ALREADY_SENDING, kTraceError,
3568 "SetLocalSSRC() already sending");
3569 return -1;
3570 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003571 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003572 {
3573 _engineStatisticsPtr->SetLastError(
3574 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3575 "SetLocalSSRC() failed to set SSRC");
3576 return -1;
3577 }
3578 return 0;
3579}
3580
3581int
3582Channel::GetLocalSSRC(unsigned int& ssrc)
3583{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003584 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003585 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3586 VoEId(_instanceId,_channelId),
3587 "GetLocalSSRC() => ssrc=%lu", ssrc);
3588 return 0;
3589}
3590
3591int
3592Channel::GetRemoteSSRC(unsigned int& ssrc)
3593{
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003594 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003595 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3596 VoEId(_instanceId,_channelId),
3597 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3598 return 0;
3599}
3600
3601int
3602Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3603{
3604 if (arrCSRC == NULL)
3605 {
3606 _engineStatisticsPtr->SetLastError(
3607 VE_INVALID_ARGUMENT, kTraceError,
3608 "GetRemoteCSRCs() invalid array argument");
3609 return -1;
3610 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003611 uint32_t arrOfCSRC[kRtpCsrcSize];
3612 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003613 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003614 if (CSRCs > 0)
3615 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003616 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003617 for (int i = 0; i < (int) CSRCs; i++)
3618 {
3619 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3620 VoEId(_instanceId, _channelId),
3621 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3622 }
3623 } else
3624 {
3625 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3626 VoEId(_instanceId, _channelId),
3627 "GetRemoteCSRCs() => list is empty!");
3628 }
3629 return CSRCs;
3630}
3631
3632int
3633Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3634{
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003635 if (_rtpAudioProc.get() == NULL)
3636 {
3637 _rtpAudioProc.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3638 _channelId)));
3639 if (_rtpAudioProc.get() == NULL)
3640 {
3641 _engineStatisticsPtr->SetLastError(VE_NO_MEMORY, kTraceCritical,
3642 "Failed to create AudioProcessing");
3643 return -1;
3644 }
3645 }
3646
3647 if (_rtpAudioProc->level_estimator()->Enable(enable) !=
3648 AudioProcessing::kNoError)
3649 {
3650 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceWarning,
3651 "Failed to enable AudioProcessing::level_estimator()");
3652 }
3653
niklase@google.com470e71d2011-07-07 08:21:25 +00003654 _includeAudioLevelIndication = enable;
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00003655 if (enable) {
3656 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3657 ID);
3658 } else {
3659 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3660 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003661 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003662}
3663int
3664Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3665{
3666 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3667 VoEId(_instanceId,_channelId),
3668 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3669 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003670 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003671}
3672
3673int
3674Channel::SetRTCPStatus(bool enable)
3675{
3676 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3677 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003678 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003679 kRtcpCompound : kRtcpOff) != 0)
3680 {
3681 _engineStatisticsPtr->SetLastError(
3682 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3683 "SetRTCPStatus() failed to set RTCP status");
3684 return -1;
3685 }
3686 return 0;
3687}
3688
3689int
3690Channel::GetRTCPStatus(bool& enabled)
3691{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003692 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003693 enabled = (method != kRtcpOff);
3694 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3695 VoEId(_instanceId,_channelId),
3696 "GetRTCPStatus() => enabled=%d", enabled);
3697 return 0;
3698}
3699
3700int
3701Channel::SetRTCP_CNAME(const char cName[256])
3702{
3703 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3704 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003705 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003706 {
3707 _engineStatisticsPtr->SetLastError(
3708 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3709 "SetRTCP_CNAME() failed to set RTCP CNAME");
3710 return -1;
3711 }
3712 return 0;
3713}
3714
3715int
3716Channel::GetRTCP_CNAME(char cName[256])
3717{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003718 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003719 {
3720 _engineStatisticsPtr->SetLastError(
3721 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3722 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3723 return -1;
3724 }
3725 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3726 VoEId(_instanceId, _channelId),
3727 "GetRTCP_CNAME() => cName=%s", cName);
3728 return 0;
3729}
3730
3731int
3732Channel::GetRemoteRTCP_CNAME(char cName[256])
3733{
3734 if (cName == NULL)
3735 {
3736 _engineStatisticsPtr->SetLastError(
3737 VE_INVALID_ARGUMENT, kTraceError,
3738 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3739 return -1;
3740 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003741 char cname[RTCP_CNAME_SIZE];
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003742 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003743 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003744 {
3745 _engineStatisticsPtr->SetLastError(
3746 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3747 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3748 return -1;
3749 }
3750 strcpy(cName, cname);
3751 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3752 VoEId(_instanceId, _channelId),
3753 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3754 return 0;
3755}
3756
3757int
3758Channel::GetRemoteRTCPData(
3759 unsigned int& NTPHigh,
3760 unsigned int& NTPLow,
3761 unsigned int& timestamp,
3762 unsigned int& playoutTimestamp,
3763 unsigned int* jitter,
3764 unsigned short* fractionLost)
3765{
3766 // --- Information from sender info in received Sender Reports
3767
3768 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003769 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003770 {
3771 _engineStatisticsPtr->SetLastError(
3772 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003773 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003774 "side");
3775 return -1;
3776 }
3777
3778 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3779 // and octet count)
3780 NTPHigh = senderInfo.NTPseconds;
3781 NTPLow = senderInfo.NTPfraction;
3782 timestamp = senderInfo.RTPtimeStamp;
3783
3784 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3785 VoEId(_instanceId, _channelId),
3786 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3787 "timestamp=%lu",
3788 NTPHigh, NTPLow, timestamp);
3789
3790 // --- Locally derived information
3791
3792 // This value is updated on each incoming RTCP packet (0 when no packet
3793 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003794 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003795
3796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3797 VoEId(_instanceId, _channelId),
3798 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003799 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003800
3801 if (NULL != jitter || NULL != fractionLost)
3802 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003803 // Get all RTCP receiver report blocks that have been received on this
3804 // channel. If we receive RTP packets from a remote source we know the
3805 // remote SSRC and use the report block from him.
3806 // Otherwise use the first report block.
3807 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003808 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003809 remote_stats.empty()) {
3810 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3811 VoEId(_instanceId, _channelId),
3812 "GetRemoteRTCPData() failed to measure statistics due"
3813 " to lack of received RTP and/or RTCP packets");
3814 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003815 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003816
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003817 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003818 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3819 for (; it != remote_stats.end(); ++it) {
3820 if (it->remoteSSRC == remoteSSRC)
3821 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003822 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003823
3824 if (it == remote_stats.end()) {
3825 // If we have not received any RTCP packets from this SSRC it probably
3826 // means that we have not received any RTP packets.
3827 // Use the first received report block instead.
3828 it = remote_stats.begin();
3829 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003830 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003831
xians@webrtc.org79af7342012-01-31 12:22:14 +00003832 if (jitter) {
3833 *jitter = it->jitter;
3834 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3835 VoEId(_instanceId, _channelId),
3836 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3837 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003838
xians@webrtc.org79af7342012-01-31 12:22:14 +00003839 if (fractionLost) {
3840 *fractionLost = it->fractionLost;
3841 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3842 VoEId(_instanceId, _channelId),
3843 "GetRemoteRTCPData() => fractionLost = %lu",
3844 *fractionLost);
3845 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003846 }
3847 return 0;
3848}
3849
3850int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003851Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003852 unsigned int name,
3853 const char* data,
3854 unsigned short dataLengthInBytes)
3855{
3856 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3857 "Channel::SendApplicationDefinedRTCPPacket()");
3858 if (!_sending)
3859 {
3860 _engineStatisticsPtr->SetLastError(
3861 VE_NOT_SENDING, kTraceError,
3862 "SendApplicationDefinedRTCPPacket() not sending");
3863 return -1;
3864 }
3865 if (NULL == data)
3866 {
3867 _engineStatisticsPtr->SetLastError(
3868 VE_INVALID_ARGUMENT, kTraceError,
3869 "SendApplicationDefinedRTCPPacket() invalid data value");
3870 return -1;
3871 }
3872 if (dataLengthInBytes % 4 != 0)
3873 {
3874 _engineStatisticsPtr->SetLastError(
3875 VE_INVALID_ARGUMENT, kTraceError,
3876 "SendApplicationDefinedRTCPPacket() invalid length value");
3877 return -1;
3878 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003879 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003880 if (status == kRtcpOff)
3881 {
3882 _engineStatisticsPtr->SetLastError(
3883 VE_RTCP_ERROR, kTraceError,
3884 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3885 return -1;
3886 }
3887
3888 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003889 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 subType,
3891 name,
3892 (const unsigned char*) data,
3893 dataLengthInBytes) != 0)
3894 {
3895 _engineStatisticsPtr->SetLastError(
3896 VE_SEND_ERROR, kTraceError,
3897 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3898 return -1;
3899 }
3900 return 0;
3901}
3902
3903int
3904Channel::GetRTPStatistics(
3905 unsigned int& averageJitterMs,
3906 unsigned int& maxJitterMs,
3907 unsigned int& discardedPackets)
3908{
niklase@google.com470e71d2011-07-07 08:21:25 +00003909 // The jitter statistics is updated for each received RTP packet and is
3910 // based on received packets.
stefan@webrtc.org717d1472013-07-10 13:39:27 +00003911 StreamStatistician::Statistics statistics;
3912 StreamStatistician* statistician =
3913 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3914 if (!statistician || !statistician->GetStatistics(
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003915 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3916 _engineStatisticsPtr->SetLastError(
3917 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3918 "GetRTPStatistics() failed to read RTP statistics from the "
3919 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003920 }
3921
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003922 const int32_t playoutFrequency =
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 _audioCodingModule.PlayoutFrequency();
3924 if (playoutFrequency > 0)
3925 {
3926 // Scale RTP statistics given the current playout frequency
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00003927 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3928 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003929 }
3930
3931 discardedPackets = _numberOfDiscardedPackets;
3932
3933 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3934 VoEId(_instanceId, _channelId),
3935 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003936 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003937 averageJitterMs, maxJitterMs, discardedPackets);
3938 return 0;
3939}
3940
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003941int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3942 if (sender_info == NULL) {
3943 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3944 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3945 return -1;
3946 }
3947
3948 // Get the sender info from the latest received RTCP Sender Report.
3949 RTCPSenderInfo rtcp_sender_info;
3950 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3951 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3952 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3953 return -1;
3954 }
3955
3956 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3957 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3958 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3959 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3960 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3961 return 0;
3962}
3963
3964int Channel::GetRemoteRTCPReportBlocks(
3965 std::vector<ReportBlock>* report_blocks) {
3966 if (report_blocks == NULL) {
3967 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3968 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3969 return -1;
3970 }
3971
3972 // Get the report blocks from the latest received RTCP Sender or Receiver
3973 // Report. Each element in the vector contains the sender's SSRC and a
3974 // report block according to RFC 3550.
3975 std::vector<RTCPReportBlock> rtcp_report_blocks;
3976 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3977 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3978 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3979 return -1;
3980 }
3981
3982 if (rtcp_report_blocks.empty())
3983 return 0;
3984
3985 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3986 for (; it != rtcp_report_blocks.end(); ++it) {
3987 ReportBlock report_block;
3988 report_block.sender_SSRC = it->remoteSSRC;
3989 report_block.source_SSRC = it->sourceSSRC;
3990 report_block.fraction_lost = it->fractionLost;
3991 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3992 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3993 report_block.interarrival_jitter = it->jitter;
3994 report_block.last_SR_timestamp = it->lastSR;
3995 report_block.delay_since_last_SR = it->delaySinceLastSR;
3996 report_blocks->push_back(report_block);
3997 }
3998 return 0;
3999}
4000
niklase@google.com470e71d2011-07-07 08:21:25 +00004001int
4002Channel::GetRTPStatistics(CallStatistics& stats)
4003{
niklase@google.com470e71d2011-07-07 08:21:25 +00004004 // --- Part one of the final structure (four values)
4005
4006 // The jitter statistics is updated for each received RTP packet and is
4007 // based on received packets.
stefan@webrtc.org717d1472013-07-10 13:39:27 +00004008 StreamStatistician::Statistics statistics;
4009 StreamStatistician* statistician =
4010 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
4011 if (!statistician || !statistician->GetStatistics(
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004012 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4013 _engineStatisticsPtr->SetLastError(
4014 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4015 "GetRTPStatistics() failed to read RTP statistics from the "
4016 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004017 }
4018
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004019 stats.fractionLost = statistics.fraction_lost;
4020 stats.cumulativeLost = statistics.cumulative_lost;
4021 stats.extendedMax = statistics.extended_max_sequence_number;
4022 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004023
4024 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4025 VoEId(_instanceId, _channelId),
4026 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004027 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004028 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4029 stats.jitterSamples);
4030
4031 // --- Part two of the final structure (one value)
4032
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004033 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004034 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004035 if (method == kRtcpOff)
4036 {
4037 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4038 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004039 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004040 "measurements cannot be retrieved");
4041 } else
4042 {
4043 // The remote SSRC will be zero if no RTP packet has been received.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004044 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004045 if (remoteSSRC > 0)
4046 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004047 uint16_t avgRTT(0);
4048 uint16_t maxRTT(0);
4049 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004050
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004051 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004052 != 0)
4053 {
4054 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4055 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004056 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004057 "the RTP/RTCP module");
4058 }
4059 } else
4060 {
4061 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4062 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004063 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004064 "RTP packets have been received yet");
4065 }
4066 }
4067
4068 stats.rttMs = static_cast<int> (RTT);
4069
4070 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4071 VoEId(_instanceId, _channelId),
4072 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4073
4074 // --- Part three of the final structure (four values)
4075
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004076 uint32_t bytesSent(0);
4077 uint32_t packetsSent(0);
4078 uint32_t bytesReceived(0);
4079 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004080
stefan@webrtc.org717d1472013-07-10 13:39:27 +00004081 if (statistician) {
4082 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4083 }
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004084
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004085 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004086 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004087 {
4088 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4089 VoEId(_instanceId, _channelId),
4090 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004091 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004092 }
4093
4094 stats.bytesSent = bytesSent;
4095 stats.packetsSent = packetsSent;
4096 stats.bytesReceived = bytesReceived;
4097 stats.packetsReceived = packetsReceived;
4098
4099 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4100 VoEId(_instanceId, _channelId),
4101 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004102 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004103 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4104 stats.packetsReceived);
4105
4106 return 0;
4107}
4108
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004109int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4111 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004112
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004113 if (enable) {
4114 if (redPayloadtype < 0 || redPayloadtype > 127) {
4115 _engineStatisticsPtr->SetLastError(
4116 VE_PLTYPE_ERROR, kTraceError,
4117 "SetFECStatus() invalid RED payload type");
4118 return -1;
4119 }
4120
4121 if (SetRedPayloadType(redPayloadtype) < 0) {
4122 _engineStatisticsPtr->SetLastError(
4123 VE_CODEC_ERROR, kTraceError,
4124 "SetSecondarySendCodec() Failed to register RED ACM");
4125 return -1;
4126 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004127 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004128
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004129 if (_audioCodingModule.SetFECStatus(enable) != 0) {
4130 _engineStatisticsPtr->SetLastError(
4131 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4132 "SetFECStatus() failed to set FEC state in the ACM");
4133 return -1;
4134 }
4135 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004136}
4137
4138int
4139Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4140{
4141 enabled = _audioCodingModule.FECStatus();
4142 if (enabled)
4143 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004144 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004145 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004146 {
4147 _engineStatisticsPtr->SetLastError(
4148 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4149 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4150 "module");
4151 return -1;
4152 }
4153 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4154 VoEId(_instanceId, _channelId),
4155 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4156 enabled, redPayloadtype);
4157 return 0;
4158 }
4159 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4160 VoEId(_instanceId, _channelId),
4161 "GetFECStatus() => enabled=%d", enabled);
4162 return 0;
4163}
4164
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004165void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4166 // None of these functions can fail.
4167 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004168 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff,
4169 maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004170 if (enable)
4171 _audioCodingModule.EnableNack(maxNumberOfPackets);
4172 else
4173 _audioCodingModule.DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004174}
4175
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004176// Called when we are missing one or more packets.
4177int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004178 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4179}
4180
niklase@google.com470e71d2011-07-07 08:21:25 +00004181int
niklase@google.com470e71d2011-07-07 08:21:25 +00004182Channel::StartRTPDump(const char fileNameUTF8[1024],
4183 RTPDirections direction)
4184{
4185 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4186 "Channel::StartRTPDump()");
4187 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4188 {
4189 _engineStatisticsPtr->SetLastError(
4190 VE_INVALID_ARGUMENT, kTraceError,
4191 "StartRTPDump() invalid RTP direction");
4192 return -1;
4193 }
4194 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4195 &_rtpDumpIn : &_rtpDumpOut;
4196 if (rtpDumpPtr == NULL)
4197 {
4198 assert(false);
4199 return -1;
4200 }
4201 if (rtpDumpPtr->IsActive())
4202 {
4203 rtpDumpPtr->Stop();
4204 }
4205 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4206 {
4207 _engineStatisticsPtr->SetLastError(
4208 VE_BAD_FILE, kTraceError,
4209 "StartRTPDump() failed to create file");
4210 return -1;
4211 }
4212 return 0;
4213}
4214
4215int
4216Channel::StopRTPDump(RTPDirections direction)
4217{
4218 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4219 "Channel::StopRTPDump()");
4220 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4221 {
4222 _engineStatisticsPtr->SetLastError(
4223 VE_INVALID_ARGUMENT, kTraceError,
4224 "StopRTPDump() invalid RTP direction");
4225 return -1;
4226 }
4227 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4228 &_rtpDumpIn : &_rtpDumpOut;
4229 if (rtpDumpPtr == NULL)
4230 {
4231 assert(false);
4232 return -1;
4233 }
4234 if (!rtpDumpPtr->IsActive())
4235 {
4236 return 0;
4237 }
4238 return rtpDumpPtr->Stop();
4239}
4240
4241bool
4242Channel::RTPDumpIsActive(RTPDirections direction)
4243{
4244 if ((direction != kRtpIncoming) &&
4245 (direction != kRtpOutgoing))
4246 {
4247 _engineStatisticsPtr->SetLastError(
4248 VE_INVALID_ARGUMENT, kTraceError,
4249 "RTPDumpIsActive() invalid RTP direction");
4250 return false;
4251 }
4252 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4253 &_rtpDumpIn : &_rtpDumpOut;
4254 return rtpDumpPtr->IsActive();
4255}
4256
4257int
4258Channel::InsertExtraRTPPacket(unsigned char payloadType,
4259 bool markerBit,
4260 const char* payloadData,
4261 unsigned short payloadSize)
4262{
4263 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4264 "Channel::InsertExtraRTPPacket()");
4265 if (payloadType > 127)
4266 {
4267 _engineStatisticsPtr->SetLastError(
4268 VE_INVALID_PLTYPE, kTraceError,
4269 "InsertExtraRTPPacket() invalid payload type");
4270 return -1;
4271 }
4272 if (payloadData == NULL)
4273 {
4274 _engineStatisticsPtr->SetLastError(
4275 VE_INVALID_ARGUMENT, kTraceError,
4276 "InsertExtraRTPPacket() invalid payload data");
4277 return -1;
4278 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004279 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004280 {
4281 _engineStatisticsPtr->SetLastError(
4282 VE_INVALID_ARGUMENT, kTraceError,
4283 "InsertExtraRTPPacket() invalid payload size");
4284 return -1;
4285 }
4286 if (!_sending)
4287 {
4288 _engineStatisticsPtr->SetLastError(
4289 VE_NOT_SENDING, kTraceError,
4290 "InsertExtraRTPPacket() not sending");
4291 return -1;
4292 }
4293
4294 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4295 // Transport::SendPacket() will be called by the module when the RTP packet
4296 // is created.
4297 // The call to SendOutgoingData() does *not* modify the timestamp and
4298 // payloadtype to ensure that the RTP module generates a valid RTP packet
4299 // (user might utilize a non-registered payload type).
4300 // The marker bit and payload type will be replaced just before the actual
4301 // transmission, i.e., the actual modification is done *after* the RTP
4302 // module has delivered its RTP packet back to the VoE.
4303 // We will use the stored values above when the packet is modified
4304 // (see Channel::SendPacket()).
4305
4306 _extraPayloadType = payloadType;
4307 _extraMarkerBit = markerBit;
4308 _insertExtraRTPPacket = true;
4309
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004310 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004311 _lastPayloadType,
4312 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004313 // Leaving the time when this frame was
4314 // received from the capture device as
4315 // undefined for voice for now.
4316 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004317 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004318 payloadSize) != 0)
4319 {
4320 _engineStatisticsPtr->SetLastError(
4321 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4322 "InsertExtraRTPPacket() failed to send extra RTP packet");
4323 return -1;
4324 }
4325
4326 return 0;
4327}
4328
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004329uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004330Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004331{
4332 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004333 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004334 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004335 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004336 return 0;
4337}
4338
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004339uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004340Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004341{
4342 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4343 "Channel::PrepareEncodeAndSend()");
4344
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004345 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004346 {
4347 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4348 "Channel::PrepareEncodeAndSend() invalid audio frame");
4349 return -1;
4350 }
4351
4352 if (_inputFilePlaying)
4353 {
4354 MixOrReplaceAudioWithFile(mixingFrequency);
4355 }
4356
4357 if (_mute)
4358 {
4359 AudioFrameOperations::Mute(_audioFrame);
4360 }
4361
4362 if (_inputExternalMedia)
4363 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004364 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004365 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004366 if (_inputExternalMediaCallbackPtr)
4367 {
4368 _inputExternalMediaCallbackPtr->Process(
4369 _channelId,
4370 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004371 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004372 _audioFrame.samples_per_channel_,
4373 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004374 isStereo);
4375 }
4376 }
4377
4378 InsertInbandDtmfTone();
4379
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004380 if (_includeAudioLevelIndication)
4381 {
4382 assert(_rtpAudioProc.get() != NULL);
4383
4384 // Check if settings need to be updated.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004385 if (_rtpAudioProc->sample_rate_hz() != _audioFrame.sample_rate_hz_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004386 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004387 if (_rtpAudioProc->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004388 AudioProcessing::kNoError)
4389 {
4390 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4391 VoEId(_instanceId, _channelId),
4392 "Error setting AudioProcessing sample rate");
4393 return -1;
4394 }
4395 }
4396
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004397 if (_rtpAudioProc->num_input_channels() != _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004398 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004399 if (_rtpAudioProc->set_num_channels(_audioFrame.num_channels_,
4400 _audioFrame.num_channels_)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004401 != AudioProcessing::kNoError)
4402 {
4403 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4404 VoEId(_instanceId, _channelId),
4405 "Error setting AudioProcessing channels");
4406 return -1;
4407 }
4408 }
4409
4410 // Performs level analysis only; does not affect the signal.
4411 _rtpAudioProc->ProcessStream(&_audioFrame);
4412 }
4413
niklase@google.com470e71d2011-07-07 08:21:25 +00004414 return 0;
4415}
4416
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004417uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004418Channel::EncodeAndSend()
4419{
4420 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4421 "Channel::EncodeAndSend()");
4422
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004423 assert(_audioFrame.num_channels_ <= 2);
4424 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004425 {
4426 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4427 "Channel::EncodeAndSend() invalid audio frame");
4428 return -1;
4429 }
4430
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004431 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004432
4433 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4434
4435 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004436 _audioFrame.timestamp_ = _timeStamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004437 if (_audioCodingModule.Add10MsData((AudioFrame&)_audioFrame) != 0)
4438 {
4439 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4440 "Channel::EncodeAndSend() ACM encoding failed");
4441 return -1;
4442 }
4443
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004444 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004445
4446 // --- Encode if complete frame is ready
4447
4448 // This call will trigger AudioPacketizationCallback::SendData if encoding
4449 // is done and payload is ready for packetization and transmission.
4450 return _audioCodingModule.Process();
4451}
4452
4453int Channel::RegisterExternalMediaProcessing(
4454 ProcessingTypes type,
4455 VoEMediaProcess& processObject)
4456{
4457 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4458 "Channel::RegisterExternalMediaProcessing()");
4459
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004460 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004461
4462 if (kPlaybackPerChannel == type)
4463 {
4464 if (_outputExternalMediaCallbackPtr)
4465 {
4466 _engineStatisticsPtr->SetLastError(
4467 VE_INVALID_OPERATION, kTraceError,
4468 "Channel::RegisterExternalMediaProcessing() "
4469 "output external media already enabled");
4470 return -1;
4471 }
4472 _outputExternalMediaCallbackPtr = &processObject;
4473 _outputExternalMedia = true;
4474 }
4475 else if (kRecordingPerChannel == type)
4476 {
4477 if (_inputExternalMediaCallbackPtr)
4478 {
4479 _engineStatisticsPtr->SetLastError(
4480 VE_INVALID_OPERATION, kTraceError,
4481 "Channel::RegisterExternalMediaProcessing() "
4482 "output external media already enabled");
4483 return -1;
4484 }
4485 _inputExternalMediaCallbackPtr = &processObject;
4486 _inputExternalMedia = true;
4487 }
4488 return 0;
4489}
4490
4491int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4492{
4493 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4494 "Channel::DeRegisterExternalMediaProcessing()");
4495
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004496 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004497
4498 if (kPlaybackPerChannel == type)
4499 {
4500 if (!_outputExternalMediaCallbackPtr)
4501 {
4502 _engineStatisticsPtr->SetLastError(
4503 VE_INVALID_OPERATION, kTraceWarning,
4504 "Channel::DeRegisterExternalMediaProcessing() "
4505 "output external media already disabled");
4506 return 0;
4507 }
4508 _outputExternalMedia = false;
4509 _outputExternalMediaCallbackPtr = NULL;
4510 }
4511 else if (kRecordingPerChannel == type)
4512 {
4513 if (!_inputExternalMediaCallbackPtr)
4514 {
4515 _engineStatisticsPtr->SetLastError(
4516 VE_INVALID_OPERATION, kTraceWarning,
4517 "Channel::DeRegisterExternalMediaProcessing() "
4518 "input external media already disabled");
4519 return 0;
4520 }
4521 _inputExternalMedia = false;
4522 _inputExternalMediaCallbackPtr = NULL;
4523 }
4524
4525 return 0;
4526}
4527
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004528int Channel::SetExternalMixing(bool enabled) {
4529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4530 "Channel::SetExternalMixing(enabled=%d)", enabled);
4531
4532 if (_playing)
4533 {
4534 _engineStatisticsPtr->SetLastError(
4535 VE_INVALID_OPERATION, kTraceError,
4536 "Channel::SetExternalMixing() "
4537 "external mixing cannot be changed while playing.");
4538 return -1;
4539 }
4540
4541 _externalMixing = enabled;
4542
4543 return 0;
4544}
4545
niklase@google.com470e71d2011-07-07 08:21:25 +00004546int
4547Channel::ResetRTCPStatistics()
4548{
4549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4550 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004551 uint32_t remoteSSRC(0);
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004552 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004553 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004554}
4555
4556int
4557Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4558{
4559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4560 "Channel::GetRoundTripTimeSummary()");
4561 // Override default module outputs for the case when RTCP is disabled.
4562 // This is done to ensure that we are backward compatible with the
4563 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004564 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004565 {
4566 delaysMs.min = -1;
4567 delaysMs.max = -1;
4568 delaysMs.average = -1;
4569 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4570 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4571 " valid RTT measurements cannot be retrieved");
4572 return 0;
4573 }
4574
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004575 uint32_t remoteSSRC;
4576 uint16_t RTT;
4577 uint16_t avgRTT;
4578 uint16_t maxRTT;
4579 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004580 // The remote SSRC will be zero if no RTP packet has been received.
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004581 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004582 if (remoteSSRC == 0)
4583 {
4584 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4585 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4586 " since no RTP packet has been received yet");
4587 }
4588
4589 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4590 // channel and SSRC. The SSRC is required to parse out the correct source
4591 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004592 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004593 {
4594 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4595 "GetRoundTripTimeSummary unable to retrieve RTT values"
4596 " from the RTCP layer");
4597 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4598 }
4599 else
4600 {
4601 delaysMs.min = minRTT;
4602 delaysMs.max = maxRTT;
4603 delaysMs.average = avgRTT;
4604 }
4605 return 0;
4606}
4607
4608int
4609Channel::GetNetworkStatistics(NetworkStatistics& stats)
4610{
4611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4612 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004613 ACMNetworkStatistics acm_stats;
4614 int return_value = _audioCodingModule.NetworkStatistics(&acm_stats);
4615 if (return_value >= 0) {
4616 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4617 }
4618 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004619}
4620
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004621bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4622 int* playout_buffer_delay_ms) const {
4623 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004624 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004625 "Channel::GetDelayEstimate() no valid estimate.");
4626 return false;
4627 }
4628 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4629 _recPacketDelayMs;
4630 *playout_buffer_delay_ms = playout_delay_ms_;
4631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4632 "Channel::GetDelayEstimate()");
4633 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004634}
4635
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004636int Channel::SetInitialPlayoutDelay(int delay_ms)
4637{
4638 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4639 "Channel::SetInitialPlayoutDelay()");
4640 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4641 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4642 {
4643 _engineStatisticsPtr->SetLastError(
4644 VE_INVALID_ARGUMENT, kTraceError,
4645 "SetInitialPlayoutDelay() invalid min delay");
4646 return -1;
4647 }
4648 if (_audioCodingModule.SetInitialPlayoutDelay(delay_ms) != 0)
4649 {
4650 _engineStatisticsPtr->SetLastError(
4651 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4652 "SetInitialPlayoutDelay() failed to set min playout delay");
4653 return -1;
4654 }
4655 return 0;
4656}
4657
4658
niklase@google.com470e71d2011-07-07 08:21:25 +00004659int
4660Channel::SetMinimumPlayoutDelay(int delayMs)
4661{
4662 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4663 "Channel::SetMinimumPlayoutDelay()");
4664 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4665 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4666 {
4667 _engineStatisticsPtr->SetLastError(
4668 VE_INVALID_ARGUMENT, kTraceError,
4669 "SetMinimumPlayoutDelay() invalid min delay");
4670 return -1;
4671 }
4672 if (_audioCodingModule.SetMinimumPlayoutDelay(delayMs) != 0)
4673 {
4674 _engineStatisticsPtr->SetLastError(
4675 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4676 "SetMinimumPlayoutDelay() failed to set min playout delay");
4677 return -1;
4678 }
4679 return 0;
4680}
4681
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004682void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4683 uint32_t playout_timestamp = 0;
4684
4685 if (_audioCodingModule.PlayoutTimestamp(&playout_timestamp) == -1) {
4686 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4687 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4688 " timestamp from the ACM");
4689 _engineStatisticsPtr->SetLastError(
4690 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4691 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4692 return;
4693 }
4694
4695 uint16_t delay_ms = 0;
4696 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4697 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4698 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4699 " delay from the ADM");
4700 _engineStatisticsPtr->SetLastError(
4701 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4702 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4703 return;
4704 }
4705
4706 int32_t playout_frequency = _audioCodingModule.PlayoutFrequency();
4707 CodecInst current_recive_codec;
4708 if (_audioCodingModule.ReceiveCodec(&current_recive_codec) == 0) {
4709 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4710 playout_frequency = 8000;
4711 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4712 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004713 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004714 }
4715
4716 // Remove the playout delay.
4717 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4718
4719 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4720 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4721 playout_timestamp);
4722
4723 if (rtcp) {
4724 playout_timestamp_rtcp_ = playout_timestamp;
4725 } else {
4726 playout_timestamp_rtp_ = playout_timestamp;
4727 }
4728 playout_delay_ms_ = delay_ms;
4729}
4730
4731int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4732 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4733 "Channel::GetPlayoutTimestamp()");
4734 if (playout_timestamp_rtp_ == 0) {
4735 _engineStatisticsPtr->SetLastError(
4736 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4737 "GetPlayoutTimestamp() failed to retrieve timestamp");
4738 return -1;
4739 }
4740 timestamp = playout_timestamp_rtp_;
4741 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4742 VoEId(_instanceId,_channelId),
4743 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4744 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004745}
4746
4747int
4748Channel::SetInitTimestamp(unsigned int timestamp)
4749{
4750 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4751 "Channel::SetInitTimestamp()");
4752 if (_sending)
4753 {
4754 _engineStatisticsPtr->SetLastError(
4755 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4756 return -1;
4757 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004758 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004759 {
4760 _engineStatisticsPtr->SetLastError(
4761 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4762 "SetInitTimestamp() failed to set timestamp");
4763 return -1;
4764 }
4765 return 0;
4766}
4767
4768int
4769Channel::SetInitSequenceNumber(short sequenceNumber)
4770{
4771 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4772 "Channel::SetInitSequenceNumber()");
4773 if (_sending)
4774 {
4775 _engineStatisticsPtr->SetLastError(
4776 VE_SENDING, kTraceError,
4777 "SetInitSequenceNumber() already sending");
4778 return -1;
4779 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004780 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004781 {
4782 _engineStatisticsPtr->SetLastError(
4783 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4784 "SetInitSequenceNumber() failed to set sequence number");
4785 return -1;
4786 }
4787 return 0;
4788}
4789
4790int
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004791Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004792{
4793 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4794 "Channel::GetRtpRtcp()");
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00004795 *rtpRtcpModule = _rtpRtcpModule.get();
4796 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004797 return 0;
4798}
4799
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004800// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4801// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004802int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004803Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004804{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004805 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004806 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004807
4808 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004809 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004810
4811 if (_inputFilePlayerPtr == NULL)
4812 {
4813 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4814 VoEId(_instanceId, _channelId),
4815 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4816 " doesnt exist");
4817 return -1;
4818 }
4819
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004820 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004821 fileSamples,
4822 mixingFrequency) == -1)
4823 {
4824 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4825 VoEId(_instanceId, _channelId),
4826 "Channel::MixOrReplaceAudioWithFile() file mixing "
4827 "failed");
4828 return -1;
4829 }
4830 if (fileSamples == 0)
4831 {
4832 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4833 VoEId(_instanceId, _channelId),
4834 "Channel::MixOrReplaceAudioWithFile() file is ended");
4835 return 0;
4836 }
4837 }
4838
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004839 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004840
4841 if (_mixFileWithMicrophone)
4842 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004843 // Currently file stream is always mono.
4844 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004845 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004846 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004847 fileBuffer.get(),
4848 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004849 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004850 }
4851 else
4852 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004853 // Replace ACM audio with file.
4854 // Currently file stream is always mono.
4855 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004856 _audioFrame.UpdateFrame(_channelId,
4857 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004858 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004859 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004860 mixingFrequency,
4861 AudioFrame::kNormalSpeech,
4862 AudioFrame::kVadUnknown,
4863 1);
4864
4865 }
4866 return 0;
4867}
4868
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004869int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004870Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004871 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004872{
4873 assert(mixingFrequency <= 32000);
4874
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004875 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004876 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004877
4878 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004879 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004880
4881 if (_outputFilePlayerPtr == NULL)
4882 {
4883 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4884 VoEId(_instanceId, _channelId),
4885 "Channel::MixAudioWithFile() file mixing failed");
4886 return -1;
4887 }
4888
4889 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004890 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004891 fileSamples,
4892 mixingFrequency) == -1)
4893 {
4894 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4895 VoEId(_instanceId, _channelId),
4896 "Channel::MixAudioWithFile() file mixing failed");
4897 return -1;
4898 }
4899 }
4900
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004901 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004902 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004903 // Currently file stream is always mono.
4904 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004905 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004906 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004907 fileBuffer.get(),
4908 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004909 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004910 }
4911 else
4912 {
4913 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004914 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004915 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004916 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004917 return -1;
4918 }
4919
4920 return 0;
4921}
4922
4923int
4924Channel::InsertInbandDtmfTone()
4925{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004926 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004927 if (_inbandDtmfQueue.PendingDtmf() &&
4928 !_inbandDtmfGenerator.IsAddingTone() &&
4929 _inbandDtmfGenerator.DelaySinceLastTone() >
4930 kMinTelephoneEventSeparationMs)
4931 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004932 int8_t eventCode(0);
4933 uint16_t lengthMs(0);
4934 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004935
4936 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4937 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4938 if (_playInbandDtmfEvent)
4939 {
4940 // Add tone to output mixer using a reduced length to minimize
4941 // risk of echo.
4942 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4943 attenuationDb);
4944 }
4945 }
4946
4947 if (_inbandDtmfGenerator.IsAddingTone())
4948 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004949 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004950 _inbandDtmfGenerator.GetSampleRate(frequency);
4951
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004952 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004953 {
4954 // Update sample rate of Dtmf tone since the mixing frequency
4955 // has changed.
4956 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004957 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004958 // Reset the tone to be added taking the new sample rate into
4959 // account.
4960 _inbandDtmfGenerator.ResetTone();
4961 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004962
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004963 int16_t toneBuffer[320];
4964 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004965 // Get 10ms tone segment and set time since last tone to zero
4966 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4967 {
4968 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4969 VoEId(_instanceId, _channelId),
4970 "Channel::EncodeAndSend() inserting Dtmf failed");
4971 return -1;
4972 }
4973
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004974 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004975 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004976 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004977 sample++)
4978 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004979 for (int channel = 0;
4980 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004981 channel++)
4982 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004983 const int index = sample * _audioFrame.num_channels_ + channel;
4984 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004985 }
4986 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004987
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004988 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004989 } else
4990 {
4991 // Add 10ms to "delay-since-last-tone" counter
4992 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4993 }
4994 return 0;
4995}
4996
niklase@google.com470e71d2011-07-07 08:21:25 +00004997void
4998Channel::ResetDeadOrAliveCounters()
4999{
5000 _countDeadDetections = 0;
5001 _countAliveDetections = 0;
5002}
5003
5004void
5005Channel::UpdateDeadOrAliveCounters(bool alive)
5006{
5007 if (alive)
5008 _countAliveDetections++;
5009 else
5010 _countDeadDetections++;
5011}
5012
5013int
5014Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5015{
niklase@google.com470e71d2011-07-07 08:21:25 +00005016 return 0;
5017}
5018
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005019int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005020Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5021{
5022 if (_transportPtr == NULL)
5023 {
5024 return -1;
5025 }
5026 if (!RTCP)
5027 {
5028 return _transportPtr->SendPacket(_channelId, data, len);
5029 }
5030 else
5031 {
5032 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5033 }
5034}
5035
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005036// Called for incoming RTP packets after successful RTP header parsing.
5037void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5038 uint16_t sequence_number) {
5039 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5040 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5041 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005042
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005043 // Get frequency of last received payload
5044 int rtp_receive_frequency = _audioCodingModule.ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005045
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005046 CodecInst current_receive_codec;
5047 if (_audioCodingModule.ReceiveCodec(&current_receive_codec) != 0) {
5048 return;
5049 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005050
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005051 // Update the least required delay.
5052 least_required_delay_ms_ = _audioCodingModule.LeastRequiredDelayMs();
5053
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005054 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5055 // Even though the actual sampling rate for G.722 audio is
5056 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5057 // 8,000 Hz because that value was erroneously assigned in
5058 // RFC 1890 and must remain unchanged for backward compatibility.
5059 rtp_receive_frequency = 8000;
5060 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5061 // We are resampling Opus internally to 32,000 Hz until all our
5062 // DSP routines can operate at 48,000 Hz, but the RTP clock
5063 // rate for the Opus payload format is standardized to 48,000 Hz,
5064 // because that is the maximum supported decoding sampling rate.
5065 rtp_receive_frequency = 48000;
5066 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005067
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005068 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5069 // packet.
5070 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5071 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005072
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005073 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5074 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005075
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005076 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005077
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005078 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5079 timestamp_diff_ms = 0;
5080 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005081
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005082 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005083
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005084 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5085 _recPacketDelayMs = packet_delay_ms;
5086 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005087
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005088 if (_average_jitter_buffer_delay_us == 0) {
5089 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5090 return;
5091 }
5092
5093 // Filter average delay value using exponential filter (alpha is
5094 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5095 // risk of rounding error) and compensate for it in GetDelayEstimate()
5096 // later.
5097 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5098 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005099}
5100
5101void
5102Channel::RegisterReceiveCodecsToRTPModule()
5103{
5104 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5105 "Channel::RegisterReceiveCodecsToRTPModule()");
5106
5107
5108 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005109 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005110
5111 for (int idx = 0; idx < nSupportedCodecs; idx++)
5112 {
5113 // Open up the RTP/RTCP receiver for all supported codecs
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005114 if ((_audioCodingModule.Codec(idx, &codec) == -1) ||
stefan@webrtc.org66b2e5c2013-07-05 14:30:48 +00005115 (rtp_receiver_->RegisterReceivePayload(
5116 codec.plname,
5117 codec.pltype,
5118 codec.plfreq,
5119 codec.channels,
5120 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005121 {
5122 WEBRTC_TRACE(
5123 kTraceWarning,
5124 kTraceVoice,
5125 VoEId(_instanceId, _channelId),
5126 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5127 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5128 codec.plname, codec.pltype, codec.plfreq,
5129 codec.channels, codec.rate);
5130 }
5131 else
5132 {
5133 WEBRTC_TRACE(
5134 kTraceInfo,
5135 kTraceVoice,
5136 VoEId(_instanceId, _channelId),
5137 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005138 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005139 "receiver",
5140 codec.plname, codec.pltype, codec.plfreq,
5141 codec.channels, codec.rate);
5142 }
5143 }
5144}
5145
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005146int Channel::ApmProcessRx(AudioFrame& frame) {
5147 AudioProcessing* audioproc = _rxAudioProcessingModulePtr;
5148 // Register the (possibly new) frame parameters.
5149 if (audioproc->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005150 LOG_FERR1(LS_WARNING, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005151 }
5152 if (audioproc->set_num_channels(frame.num_channels_,
5153 frame.num_channels_) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005154 LOG_FERR1(LS_WARNING, set_num_channels, frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005155 }
5156 if (audioproc->ProcessStream(&frame) != 0) {
andrew@webrtc.org655d8f52012-11-20 07:34:45 +00005157 LOG_FERR0(LS_WARNING, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005158 }
5159 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005160}
5161
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005162int Channel::SetSecondarySendCodec(const CodecInst& codec,
5163 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005164 // Sanity check for payload type.
5165 if (red_payload_type < 0 || red_payload_type > 127) {
5166 _engineStatisticsPtr->SetLastError(
5167 VE_PLTYPE_ERROR, kTraceError,
5168 "SetRedPayloadType() invalid RED payload type");
5169 return -1;
5170 }
5171
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005172 if (SetRedPayloadType(red_payload_type) < 0) {
5173 _engineStatisticsPtr->SetLastError(
5174 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5175 "SetSecondarySendCodec() Failed to register RED ACM");
5176 return -1;
5177 }
5178 if (_audioCodingModule.RegisterSecondarySendCodec(codec) < 0) {
5179 _engineStatisticsPtr->SetLastError(
5180 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5181 "SetSecondarySendCodec() Failed to register secondary send codec in "
5182 "ACM");
5183 return -1;
5184 }
5185
5186 return 0;
5187}
5188
5189void Channel::RemoveSecondarySendCodec() {
5190 _audioCodingModule.UnregisterSecondarySendCodec();
5191}
5192
5193int Channel::GetSecondarySendCodec(CodecInst* codec) {
5194 if (_audioCodingModule.SecondarySendCodec(codec) < 0) {
5195 _engineStatisticsPtr->SetLastError(
5196 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5197 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5198 return -1;
5199 }
5200 return 0;
5201}
5202
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005203// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005204int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005205 CodecInst codec;
5206 bool found_red = false;
5207
5208 // Get default RED settings from the ACM database
5209 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5210 for (int idx = 0; idx < num_codecs; idx++) {
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00005211 _audioCodingModule.Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005212 if (!STR_CASE_CMP(codec.plname, "RED")) {
5213 found_red = true;
5214 break;
5215 }
5216 }
5217
5218 if (!found_red) {
5219 _engineStatisticsPtr->SetLastError(
5220 VE_CODEC_ERROR, kTraceError,
5221 "SetRedPayloadType() RED is not supported");
5222 return -1;
5223 }
5224
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005225 codec.pltype = red_payload_type;
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005226 if (_audioCodingModule.RegisterSendCodec(codec) < 0) {
5227 _engineStatisticsPtr->SetLastError(
5228 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5229 "SetRedPayloadType() RED registration in ACM module failed");
5230 return -1;
5231 }
5232
5233 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5234 _engineStatisticsPtr->SetLastError(
5235 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5236 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5237 return -1;
5238 }
5239 return 0;
5240}
5241
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005242} // namespace voe
5243} // namespace webrtc