blob: 4e1913dc3569e581d7171d098c746916cea42228 [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
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000016#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/utility/interface/audio_frame_operations.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/utility/interface/rtp_dump.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/voice_engine/include/voe_base.h"
27#include "webrtc/voice_engine/include/voe_external_media.h"
28#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
29#include "webrtc/voice_engine/output_mixer.h"
30#include "webrtc/voice_engine/statistics.h"
31#include "webrtc/voice_engine/transmit_mixer.h"
32#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34#if defined(_WIN32)
35#include <Qos.h>
36#endif
37
andrew@webrtc.org50419b02012-11-14 19:07:54 +000038namespace webrtc {
39namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000040
pbos@webrtc.org6141e132013-04-09 10:09:10 +000041int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000042Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000043 uint8_t payloadType,
44 uint32_t timeStamp,
45 const uint8_t* payloadData,
46 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000047 const RTPFragmentationHeader* fragmentation)
48{
49 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
50 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
51 " payloadSize=%u, fragmentation=0x%x)",
52 frameType, payloadType, timeStamp, payloadSize, fragmentation);
53
54 if (_includeAudioLevelIndication)
55 {
56 // 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
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +000059 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->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
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000124 CriticalSectionScoped cs(&_callbackCritSect);
125
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 if (_transportPtr == NULL)
127 {
128 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
129 "Channel::SendPacket() failed to send RTP packet due to"
130 " invalid transport object");
131 return -1;
132 }
133
134 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
135 // API
136 if (_insertExtraRTPPacket)
137 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000138 uint8_t* rtpHdr = (uint8_t*)data;
139 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000140 if (_extraMarkerBit)
141 {
142 M_PT = 0x80; // set the M-bit
143 }
144 M_PT += _extraPayloadType; // set the payload type
145 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
146 _insertExtraRTPPacket = false; // insert one packet only
147 }
148
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000149 uint8_t* bufferToSendPtr = (uint8_t*)data;
150 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151
152 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000153 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 {
155 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
156 VoEId(_instanceId,_channelId),
157 "Channel::SendPacket() RTP dump to output file failed");
158 }
159
160 // SRTP or External encryption
161 if (_encrypting)
162 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000163 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
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000195 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
196 bufferLength);
197 if (n < 0) {
198 std::string transport_name =
199 _externalTransport ? "external transport" : "WebRtc sockets";
200 WEBRTC_TRACE(kTraceError, kTraceVoice,
201 VoEId(_instanceId,_channelId),
202 "Channel::SendPacket() RTP transmission using %s failed",
203 transport_name.c_str());
204 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000206 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207}
208
209int
210Channel::SendRTCPPacket(int channel, const void *data, int len)
211{
212 channel = VoEChannelId(channel);
213 assert(channel == _channelId);
214
215 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
216 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
217
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000218 CriticalSectionScoped cs(&_callbackCritSect);
219 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000221 WEBRTC_TRACE(kTraceError, kTraceVoice,
222 VoEId(_instanceId,_channelId),
223 "Channel::SendRTCPPacket() failed to send RTCP packet"
224 " due to invalid transport object");
225 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 }
227
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000228 uint8_t* bufferToSendPtr = (uint8_t*)data;
229 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
231 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000232 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 {
234 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
235 VoEId(_instanceId,_channelId),
236 "Channel::SendPacket() RTCP dump to output file failed");
237 }
238
239 // SRTP or External encryption
240 if (_encrypting)
241 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 if (_encryptionPtr)
243 {
244 if (!_encryptionRTCPBufferPtr)
245 {
246 // Allocate memory for encryption buffer one time only
247 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000248 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
251 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000252 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 _encryptionPtr->encrypt_rtcp(_channelId,
254 bufferToSendPtr,
255 _encryptionRTCPBufferPtr,
256 bufferLength,
257 (int*)&encryptedBufferLength);
258 if (encryptedBufferLength <= 0)
259 {
260 _engineStatisticsPtr->SetLastError(
261 VE_ENCRYPTION_FAILED, kTraceError,
262 "Channel::SendRTCPPacket() encryption failed");
263 return -1;
264 }
265
266 // Replace default data buffer with encrypted buffer
267 bufferToSendPtr = _encryptionRTCPBufferPtr;
268 bufferLength = encryptedBufferLength;
269 }
270 }
271
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000272 int n = _transportPtr->SendRTCPPacket(channel,
273 bufferToSendPtr,
274 bufferLength);
275 if (n < 0) {
276 std::string transport_name =
277 _externalTransport ? "external transport" : "WebRtc sockets";
278 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
279 VoEId(_instanceId,_channelId),
280 "Channel::SendRTCPPacket() transmission using %s failed",
281 transport_name.c_str());
282 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000284 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
287void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000288Channel::OnPlayTelephoneEvent(int32_t id,
289 uint8_t event,
290 uint16_t lengthMs,
291 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000292{
293 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
294 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000295 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000296
297 if (!_playOutbandDtmfEvent || (event > 15))
298 {
299 // Ignore callback since feedback is disabled or event is not a
300 // Dtmf tone event.
301 return;
302 }
303
304 assert(_outputMixerPtr != NULL);
305
306 // Start playing out the Dtmf tone (if playout is enabled).
307 // Reduce length of tone with 80ms to the reduce risk of echo.
308 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
309}
310
311void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000312Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000313{
314 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
315 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000316 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000317
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000318 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000319 assert(channel == _channelId);
320
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000321 // Update ssrc so that NTP for AV sync can be updated.
322 _rtpRtcpModule->SetRemoteSSRC(ssrc);
323
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 if (_rtpObserver)
325 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000326 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000327
328 if (_rtpObserverPtr)
329 {
330 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000331 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 }
333 }
334}
335
pbos@webrtc.org92135212013-05-14 08:31:39 +0000336void Channel::OnIncomingCSRCChanged(int32_t id,
337 uint32_t CSRC,
338 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000339{
340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
341 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
342 id, CSRC, added);
343
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000344 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 assert(channel == _channelId);
346
347 if (_rtpObserver)
348 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000349 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000350
351 if (_rtpObserverPtr)
352 {
353 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
354 }
355 }
356}
357
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000358void Channel::ResetStatistics(uint32_t ssrc) {
359 StreamStatistician* statistician =
360 rtp_receive_statistics_->GetStatistician(ssrc);
361 if (statistician) {
362 statistician->ResetStatistics();
363 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000364}
365
niklase@google.com470e71d2011-07-07 08:21:25 +0000366void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000367Channel::OnApplicationDataReceived(int32_t id,
368 uint8_t subType,
369 uint32_t name,
370 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000371 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000372{
373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
374 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
375 " name=%u, length=%u)",
376 id, subType, name, length);
377
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000378 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 assert(channel == _channelId);
380
381 if (_rtcpObserver)
382 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000383 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000384
385 if (_rtcpObserverPtr)
386 {
387 _rtcpObserverPtr->OnApplicationDataReceived(channel,
388 subType,
389 name,
390 data,
391 length);
392 }
393 }
394}
395
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000396int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000397Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000398 int32_t id,
399 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000400 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000401 int frequency,
402 uint8_t channels,
403 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000404{
405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
406 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
407 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
408 id, payloadType, payloadName, frequency, channels, rate);
409
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000410 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000411
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000412 CodecInst receiveCodec = {0};
413 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000414
415 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 receiveCodec.plfreq = frequency;
417 receiveCodec.channels = channels;
418 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000419 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000420
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000421 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 receiveCodec.pacsize = dummyCodec.pacsize;
423
424 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000425 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 {
427 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000428 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 "Channel::OnInitializeDecoder() invalid codec ("
430 "pt=%d, name=%s) received - 1", payloadType, payloadName);
431 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
432 return -1;
433 }
434
435 return 0;
436}
437
438void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000439Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000440{
441 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
442 "Channel::OnPacketTimeout(id=%d)", id);
443
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000444 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 if (_voiceEngineObserverPtr)
446 {
447 if (_receiving || _externalTransport)
448 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000449 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 assert(channel == _channelId);
451 // Ensure that next OnReceivedPacket() callback will trigger
452 // a VE_PACKET_RECEIPT_RESTARTED callback.
453 _rtpPacketTimedOut = true;
454 // Deliver callback to the observer
455 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
456 VoEId(_instanceId,_channelId),
457 "Channel::OnPacketTimeout() => "
458 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
459 _voiceEngineObserverPtr->CallbackOnError(channel,
460 VE_RECEIVE_PACKET_TIMEOUT);
461 }
462 }
463}
464
465void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000466Channel::OnReceivedPacket(int32_t id,
467 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000468{
469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
470 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
471 id, packetType);
472
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000473 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000474
475 // Notify only for the case when we have restarted an RTP session.
476 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
477 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000478 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 if (_voiceEngineObserverPtr)
480 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000481 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 assert(channel == _channelId);
483 // Reset timeout mechanism
484 _rtpPacketTimedOut = false;
485 // Deliver callback to the observer
486 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
487 VoEId(_instanceId,_channelId),
488 "Channel::OnPacketTimeout() =>"
489 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
490 _voiceEngineObserverPtr->CallbackOnError(
491 channel,
492 VE_PACKET_RECEIPT_RESTARTED);
493 }
494 }
495}
496
497void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000498Channel::OnPeriodicDeadOrAlive(int32_t id,
499 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000500{
501 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
502 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
503
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000504 {
505 CriticalSectionScoped cs(&_callbackCritSect);
506 if (!_connectionObserver)
507 return;
508 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000509
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000510 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 assert(channel == _channelId);
512
513 // Use Alive as default to limit risk of false Dead detections
514 bool isAlive(true);
515
516 // Always mark the connection as Dead when the module reports kRtpDead
517 if (kRtpDead == alive)
518 {
519 isAlive = false;
520 }
521
522 // It is possible that the connection is alive even if no RTP packet has
523 // been received for a long time since the other side might use VAD/DTX
524 // and a low SID-packet update rate.
525 if ((kRtpNoRtp == alive) && _playing)
526 {
527 // Detect Alive for all NetEQ states except for the case when we are
528 // in PLC_CNG state.
529 // PLC_CNG <=> background noise only due to long expand or error.
530 // Note that, the case where the other side stops sending during CNG
531 // state will be detected as Alive. Dead is is not set until after
532 // missing RTCP packets for at least twelve seconds (handled
533 // internally by the RTP/RTCP module).
534 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
535 }
536
537 UpdateDeadOrAliveCounters(isAlive);
538
539 // Send callback to the registered observer
540 if (_connectionObserver)
541 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000542 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000543 if (_connectionObserverPtr)
544 {
545 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
546 }
547 }
548}
549
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000550int32_t
551Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000552 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000553 const WebRtcRTPHeader* rtpHeader)
554{
555 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
556 "Channel::OnReceivedPayloadData(payloadSize=%d,"
557 " payloadType=%u, audioChannel=%u)",
558 payloadSize,
559 rtpHeader->header.payloadType,
560 rtpHeader->type.Audio.channel);
561
roosa@google.com0870f022012-12-12 21:31:41 +0000562 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
563
niklase@google.com470e71d2011-07-07 08:21:25 +0000564 if (!_playing)
565 {
566 // Avoid inserting into NetEQ when we are not playing. Count the
567 // packet as discarded.
568 WEBRTC_TRACE(kTraceStream, kTraceVoice,
569 VoEId(_instanceId, _channelId),
570 "received packet is discarded since playing is not"
571 " activated");
572 _numberOfDiscardedPackets++;
573 return 0;
574 }
575
576 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000577 if (audio_coding_->IncomingPacket(payloadData,
578 payloadSize,
579 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 {
581 _engineStatisticsPtr->SetLastError(
582 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
583 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
584 return -1;
585 }
586
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000587 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000588 UpdatePacketDelay(rtpHeader->header.timestamp,
589 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000590
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000591 uint16_t round_trip_time = 0;
592 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
593 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000594
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000595 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000596 round_trip_time);
597 if (!nack_list.empty()) {
598 // Can't use nack_list.data() since it's not supported by all
599 // compilers.
600 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000601 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 return 0;
603}
604
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000605bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
606 int rtp_packet_length) {
607 RTPHeader header;
608 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
609 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
610 "IncomingPacket invalid RTP header");
611 return false;
612 }
613 header.payload_type_frequency =
614 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
615 if (header.payload_type_frequency < 0)
616 return false;
617 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
618}
619
pbos@webrtc.org92135212013-05-14 08:31:39 +0000620int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000621{
622 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
623 "Channel::GetAudioFrame(id=%d)", id);
624
625 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000626 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
627 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 {
629 WEBRTC_TRACE(kTraceError, kTraceVoice,
630 VoEId(_instanceId,_channelId),
631 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000632 // In all likelihood, the audio in this frame is garbage. We return an
633 // error so that the audio mixer module doesn't add it to the mix. As
634 // a result, it won't be played out and the actions skipped here are
635 // irrelevant.
636 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 }
638
639 if (_RxVadDetection)
640 {
641 UpdateRxVadDetection(audioFrame);
642 }
643
644 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000645 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000646 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000647 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000648
649 // Perform far-end AudioProcessing module processing on the received signal
650 if (_rxApmIsEnabled)
651 {
652 ApmProcessRx(audioFrame);
653 }
654
wu@webrtc.org63420662013-10-17 18:28:55 +0000655 float output_gain = 1.0f;
656 float left_pan = 1.0f;
657 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000659 CriticalSectionScoped cs(&volume_settings_critsect_);
660 output_gain = _outputGain;
661 left_pan = _panLeft;
662 right_pan= _panRight;
663 }
664
665 // Output volume scaling
666 if (output_gain < 0.99f || output_gain > 1.01f)
667 {
668 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 }
670
671 // Scale left and/or right channel(s) if stereo and master balance is
672 // active
673
wu@webrtc.org63420662013-10-17 18:28:55 +0000674 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000676 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 {
678 // Emulate stereo mode since panning is active.
679 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000680 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 }
682 // For true stereo mode (when we are receiving a stereo signal), no
683 // action is needed.
684
685 // Do the panning operation (the audio frame contains stereo at this
686 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000687 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000688 }
689
690 // Mix decoded PCM output with file if file mixing is enabled
691 if (_outputFilePlaying)
692 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000693 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000694 }
695
696 // Place channel in on-hold state (~muted) if on-hold is activated
697 if (_outputIsOnHold)
698 {
699 AudioFrameOperations::Mute(audioFrame);
700 }
701
702 // External media
703 if (_outputExternalMedia)
704 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000705 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000706 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 if (_outputExternalMediaCallbackPtr)
708 {
709 _outputExternalMediaCallbackPtr->Process(
710 _channelId,
711 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000712 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000713 audioFrame.samples_per_channel_,
714 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 isStereo);
716 }
717 }
718
719 // Record playout if enabled
720 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000721 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000722
723 if (_outputFileRecording && _outputFileRecorderPtr)
724 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000725 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 }
727 }
728
729 // Measure audio level (0-9)
730 _outputAudioLevel.ComputeLevel(audioFrame);
731
732 return 0;
733}
734
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000735int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000736Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000737{
738 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
739 "Channel::NeededFrequency(id=%d)", id);
740
741 int highestNeeded = 0;
742
743 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000744 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000745
746 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000747 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000749 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000750 }
751 else
752 {
753 highestNeeded = receiveFrequency;
754 }
755
756 // Special case, if we're playing a file on the playout side
757 // we take that frequency into consideration as well
758 // This is not needed on sending side, since the codec will
759 // limit the spectrum anyway.
760 if (_outputFilePlaying)
761 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000762 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000763 if (_outputFilePlayerPtr && _outputFilePlaying)
764 {
765 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
766 {
767 highestNeeded=_outputFilePlayerPtr->Frequency();
768 }
769 }
770 }
771
772 return(highestNeeded);
773}
774
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000775int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000776Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000777 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000778 uint32_t instanceId,
779 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000780{
781 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
782 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
783 channelId, instanceId);
784
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000785 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 if (channel == NULL)
787 {
788 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
789 VoEId(instanceId,channelId),
790 "Channel::CreateChannel() unable to allocate memory for"
791 " channel");
792 return -1;
793 }
794 return 0;
795}
796
797void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000798Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000799{
800 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
801 "Channel::PlayNotification(id=%d, durationMs=%d)",
802 id, durationMs);
803
804 // Not implement yet
805}
806
807void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000808Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000809{
810 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
811 "Channel::RecordNotification(id=%d, durationMs=%d)",
812 id, durationMs);
813
814 // Not implement yet
815}
816
817void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000818Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000819{
820 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
821 "Channel::PlayFileEnded(id=%d)", id);
822
823 if (id == _inputFilePlayerId)
824 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000825 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000826
827 _inputFilePlaying = false;
828 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
829 VoEId(_instanceId,_channelId),
830 "Channel::PlayFileEnded() => input file player module is"
831 " shutdown");
832 }
833 else if (id == _outputFilePlayerId)
834 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000835 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000836
837 _outputFilePlaying = false;
838 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
839 VoEId(_instanceId,_channelId),
840 "Channel::PlayFileEnded() => output file player module is"
841 " shutdown");
842 }
843}
844
845void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000846Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000847{
848 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
849 "Channel::RecordFileEnded(id=%d)", id);
850
851 assert(id == _outputFileRecorderId);
852
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000853 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000854
855 _outputFileRecording = false;
856 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
857 VoEId(_instanceId,_channelId),
858 "Channel::RecordFileEnded() => output file recorder module is"
859 " shutdown");
860}
861
pbos@webrtc.org92135212013-05-14 08:31:39 +0000862Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000863 uint32_t instanceId,
864 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000865 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
866 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000867 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000869 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000870 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000871 rtp_payload_registry_(
872 new RTPPayloadRegistry(channelId,
873 RTPPayloadStrategy::CreateStrategy(true))),
874 rtp_receive_statistics_(ReceiveStatistics::Create(
875 Clock::GetRealTimeClock())),
876 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
877 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
878 this, this, rtp_payload_registry_.get())),
879 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000880 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000881 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000882 _rtpDumpIn(*RtpDump::CreateRtpDump()),
883 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 _inputFilePlayerPtr(NULL),
887 _outputFilePlayerPtr(NULL),
888 _outputFileRecorderPtr(NULL),
889 // Avoid conflict with other channels by adding 1024 - 1026,
890 // won't use as much as 1024 channels.
891 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
892 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
893 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
894 _inputFilePlaying(false),
895 _outputFilePlaying(false),
896 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000897 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
898 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000900 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 _inputExternalMediaCallbackPtr(NULL),
902 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000903 _encryptionRTPBufferPtr(NULL),
904 _decryptionRTPBufferPtr(NULL),
905 _encryptionRTCPBufferPtr(NULL),
906 _decryptionRTCPBufferPtr(NULL),
907 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
908 _sendTelephoneEventPayloadType(106),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000909 playout_timestamp_rtp_(0),
910 playout_timestamp_rtcp_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000911 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000912 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000913 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000914 _outputMixerPtr(NULL),
915 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000916 _moduleProcessThreadPtr(NULL),
917 _audioDeviceModulePtr(NULL),
918 _voiceEngineObserverPtr(NULL),
919 _callbackCritSectPtr(NULL),
920 _transportPtr(NULL),
921 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000922 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000923 _rxVadObserverPtr(NULL),
924 _oldVadDecision(-1),
925 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 _rtpObserverPtr(NULL),
927 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000928 _outputIsOnHold(false),
929 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000930 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000931 _inputIsOnHold(false),
932 _playing(false),
933 _sending(false),
934 _receiving(false),
935 _mixFileWithMicrophone(false),
936 _rtpObserver(false),
937 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000938 _mute(false),
939 _panLeft(1.0f),
940 _panRight(1.0f),
941 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000942 _encrypting(false),
943 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 _playOutbandDtmfEvent(false),
945 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 _extraPayloadType(0),
947 _insertExtraRTPPacket(false),
948 _extraMarkerBit(false),
949 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000950 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000951 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000952 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 _rtpPacketTimedOut(false),
954 _rtpPacketTimeOutIsEnabled(false),
955 _rtpTimeOutSeconds(0),
956 _connectionObserver(false),
957 _connectionObserverPtr(NULL),
958 _countAliveDetections(0),
959 _countDeadDetections(0),
960 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000961 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000962 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000963 _previousTimestamp(0),
964 _recPacketDelayMs(20),
965 _RxVadDetection(false),
966 _rxApmIsEnabled(false),
967 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000968 _rxNsIsEnabled(false),
969 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000970{
971 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
972 "Channel::Channel() - ctor");
973 _inbandDtmfQueue.ResetDtmf();
974 _inbandDtmfGenerator.Init();
975 _outputAudioLevel.Clear();
976
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000977 RtpRtcp::Configuration configuration;
978 configuration.id = VoEModuleId(instanceId, channelId);
979 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000980 configuration.outgoing_transport = this;
981 configuration.rtcp_feedback = this;
982 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000983 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000984
985 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
niklase@google.com470e71d2011-07-07 08:21:25 +0000986}
987
988Channel::~Channel()
989{
990 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
991 "Channel::~Channel() - dtor");
992
993 if (_outputExternalMedia)
994 {
995 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
996 }
997 if (_inputExternalMedia)
998 {
999 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1000 }
1001 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 StopPlayout();
1003
1004 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001005 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 if (_inputFilePlayerPtr)
1007 {
1008 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1009 _inputFilePlayerPtr->StopPlayingFile();
1010 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1011 _inputFilePlayerPtr = NULL;
1012 }
1013 if (_outputFilePlayerPtr)
1014 {
1015 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1016 _outputFilePlayerPtr->StopPlayingFile();
1017 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1018 _outputFilePlayerPtr = NULL;
1019 }
1020 if (_outputFileRecorderPtr)
1021 {
1022 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1023 _outputFileRecorderPtr->StopRecording();
1024 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1025 _outputFileRecorderPtr = NULL;
1026 }
1027 }
1028
1029 // The order to safely shutdown modules in a channel is:
1030 // 1. De-register callbacks in modules
1031 // 2. De-register modules in process thread
1032 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001033 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 {
1035 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1036 VoEId(_instanceId,_channelId),
1037 "~Channel() failed to de-register transport callback"
1038 " (Audio coding module)");
1039 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001040 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 {
1042 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1043 VoEId(_instanceId,_channelId),
1044 "~Channel() failed to de-register VAD callback"
1045 " (Audio coding module)");
1046 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001048 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 {
1050 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1051 VoEId(_instanceId,_channelId),
1052 "~Channel() failed to deregister RTP/RTCP module");
1053 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 // End of modules shutdown
1055
1056 // Delete other objects
1057 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1058 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1059 delete [] _encryptionRTPBufferPtr;
1060 delete [] _decryptionRTPBufferPtr;
1061 delete [] _encryptionRTCPBufferPtr;
1062 delete [] _decryptionRTCPBufferPtr;
1063 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001065 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001066}
1067
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001068int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001069Channel::Init()
1070{
1071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1072 "Channel::Init()");
1073
1074 // --- Initial sanity
1075
1076 if ((_engineStatisticsPtr == NULL) ||
1077 (_moduleProcessThreadPtr == NULL))
1078 {
1079 WEBRTC_TRACE(kTraceError, kTraceVoice,
1080 VoEId(_instanceId,_channelId),
1081 "Channel::Init() must call SetEngineInformation() first");
1082 return -1;
1083 }
1084
1085 // --- Add modules to process thread (for periodic schedulation)
1086
1087 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001088 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001089 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 if (processThreadFail)
1091 {
1092 _engineStatisticsPtr->SetLastError(
1093 VE_CANNOT_INIT_CHANNEL, kTraceError,
1094 "Channel::Init() modules not registered");
1095 return -1;
1096 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001097 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001098
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001099 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001100#ifdef WEBRTC_CODEC_AVT
1101 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001102 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001103#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001104 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1108 "Channel::Init() unable to initialize the ACM - 1");
1109 return -1;
1110 }
1111
1112 // --- RTP/RTCP module initialization
1113
1114 // Ensure that RTCP is enabled by default for the created channel.
1115 // Note that, the module will keep generating RTCP until it is explicitly
1116 // disabled by the user.
1117 // After StopListen (when no sockets exists), RTCP packets will no longer
1118 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001119 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1120 // RTCP is enabled by default.
1121 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
1123 _engineStatisticsPtr->SetLastError(
1124 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1125 "Channel::Init() RTP/RTCP module not initialized");
1126 return -1;
1127 }
1128
1129 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001131 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1132 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001133
1134 if (fail)
1135 {
1136 _engineStatisticsPtr->SetLastError(
1137 VE_CANNOT_INIT_CHANNEL, kTraceError,
1138 "Channel::Init() callbacks not registered");
1139 return -1;
1140 }
1141
1142 // --- Register all supported codecs to the receiving side of the
1143 // RTP/RTCP module
1144
1145 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001146 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001147
1148 for (int idx = 0; idx < nSupportedCodecs; idx++)
1149 {
1150 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001151 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001152 (rtp_receiver_->RegisterReceivePayload(
1153 codec.plname,
1154 codec.pltype,
1155 codec.plfreq,
1156 codec.channels,
1157 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 {
1159 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1160 VoEId(_instanceId,_channelId),
1161 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1162 "to RTP/RTCP receiver",
1163 codec.plname, codec.pltype, codec.plfreq,
1164 codec.channels, codec.rate);
1165 }
1166 else
1167 {
1168 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1169 VoEId(_instanceId,_channelId),
1170 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1171 "the RTP/RTCP receiver",
1172 codec.plname, codec.pltype, codec.plfreq,
1173 codec.channels, codec.rate);
1174 }
1175
1176 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001177 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 {
1179 SetSendCodec(codec);
1180 }
1181
1182 // Register default PT for outband 'telephone-event'
1183 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1184 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001185 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001186 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 {
1188 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1189 VoEId(_instanceId,_channelId),
1190 "Channel::Init() failed to register outband "
1191 "'telephone-event' (%d/%d) correctly",
1192 codec.pltype, codec.plfreq);
1193 }
1194 }
1195
1196 if (!STR_CASE_CMP(codec.plname, "CN"))
1197 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001198 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1199 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001200 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 {
1202 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1203 VoEId(_instanceId,_channelId),
1204 "Channel::Init() failed to register CN (%d/%d) "
1205 "correctly - 1",
1206 codec.pltype, codec.plfreq);
1207 }
1208 }
1209#ifdef WEBRTC_CODEC_RED
1210 // Register RED to the receiving side of the ACM.
1211 // We will not receive an OnInitializeDecoder() callback for RED.
1212 if (!STR_CASE_CMP(codec.plname, "RED"))
1213 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001214 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 {
1216 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1217 VoEId(_instanceId,_channelId),
1218 "Channel::Init() failed to register RED (%d/%d) "
1219 "correctly",
1220 codec.pltype, codec.plfreq);
1221 }
1222 }
1223#endif
1224 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001225
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001226 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1227 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1228 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001229 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001230 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1231 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1232 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001233 }
1234
1235 return 0;
1236}
1237
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001238int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001239Channel::SetEngineInformation(Statistics& engineStatistics,
1240 OutputMixer& outputMixer,
1241 voe::TransmitMixer& transmitMixer,
1242 ProcessThread& moduleProcessThread,
1243 AudioDeviceModule& audioDeviceModule,
1244 VoiceEngineObserver* voiceEngineObserver,
1245 CriticalSectionWrapper* callbackCritSect)
1246{
1247 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1248 "Channel::SetEngineInformation()");
1249 _engineStatisticsPtr = &engineStatistics;
1250 _outputMixerPtr = &outputMixer;
1251 _transmitMixerPtr = &transmitMixer,
1252 _moduleProcessThreadPtr = &moduleProcessThread;
1253 _audioDeviceModulePtr = &audioDeviceModule;
1254 _voiceEngineObserverPtr = voiceEngineObserver;
1255 _callbackCritSectPtr = callbackCritSect;
1256 return 0;
1257}
1258
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001259int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001260Channel::UpdateLocalTimeStamp()
1261{
1262
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001263 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001264 return 0;
1265}
1266
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001267int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001268Channel::StartPlayout()
1269{
1270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1271 "Channel::StartPlayout()");
1272 if (_playing)
1273 {
1274 return 0;
1275 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001276
1277 if (!_externalMixing) {
1278 // Add participant as candidates for mixing.
1279 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1280 {
1281 _engineStatisticsPtr->SetLastError(
1282 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1283 "StartPlayout() failed to add participant to mixer");
1284 return -1;
1285 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001286 }
1287
1288 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001289
1290 if (RegisterFilePlayingToMixer() != 0)
1291 return -1;
1292
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 return 0;
1294}
1295
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001296int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001297Channel::StopPlayout()
1298{
1299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1300 "Channel::StopPlayout()");
1301 if (!_playing)
1302 {
1303 return 0;
1304 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001305
1306 if (!_externalMixing) {
1307 // Remove participant as candidates for mixing
1308 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1309 {
1310 _engineStatisticsPtr->SetLastError(
1311 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1312 "StopPlayout() failed to remove participant from mixer");
1313 return -1;
1314 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 }
1316
1317 _playing = false;
1318 _outputAudioLevel.Clear();
1319
1320 return 0;
1321}
1322
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001323int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001324Channel::StartSend()
1325{
1326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1327 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001328 // Resume the previous sequence number which was reset by StopSend().
1329 // This needs to be done before |_sending| is set to true.
1330 if (send_sequence_number_)
1331 SetInitSequenceNumber(send_sequence_number_);
1332
niklase@google.com470e71d2011-07-07 08:21:25 +00001333 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001334 // A lock is needed because |_sending| can be accessed or modified by
1335 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001336 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001337
1338 if (_sending)
1339 {
1340 return 0;
1341 }
1342 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001343 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001344
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001345 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001346 {
1347 _engineStatisticsPtr->SetLastError(
1348 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1349 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001350 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001351 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 return -1;
1353 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001354
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 return 0;
1356}
1357
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001358int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001359Channel::StopSend()
1360{
1361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1362 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001364 // A lock is needed because |_sending| can be accessed or modified by
1365 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001366 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001367
1368 if (!_sending)
1369 {
1370 return 0;
1371 }
1372 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001374
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001375 // Store the sequence number to be able to pick up the same sequence for
1376 // the next StartSend(). This is needed for restarting device, otherwise
1377 // it might cause libSRTP to complain about packets being replayed.
1378 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1379 // CL is landed. See issue
1380 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1381 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1382
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 // Reset sending SSRC and sequence number and triggers direct transmission
1384 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001385 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1386 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001387 {
1388 _engineStatisticsPtr->SetLastError(
1389 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1390 "StartSend() RTP/RTCP failed to stop sending");
1391 }
1392
niklase@google.com470e71d2011-07-07 08:21:25 +00001393 return 0;
1394}
1395
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001396int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001397Channel::StartReceiving()
1398{
1399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1400 "Channel::StartReceiving()");
1401 if (_receiving)
1402 {
1403 return 0;
1404 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001405 _receiving = true;
1406 _numberOfDiscardedPackets = 0;
1407 return 0;
1408}
1409
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001410int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001411Channel::StopReceiving()
1412{
1413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1414 "Channel::StopReceiving()");
1415 if (!_receiving)
1416 {
1417 return 0;
1418 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001419
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001420 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001421 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001422 RegisterReceiveCodecsToRTPModule();
1423 _receiving = false;
1424 return 0;
1425}
1426
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001427int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001428Channel::SetNetEQPlayoutMode(NetEqModes mode)
1429{
1430 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1431 "Channel::SetNetEQPlayoutMode()");
1432 AudioPlayoutMode playoutMode(voice);
1433 switch (mode)
1434 {
1435 case kNetEqDefault:
1436 playoutMode = voice;
1437 break;
1438 case kNetEqStreaming:
1439 playoutMode = streaming;
1440 break;
1441 case kNetEqFax:
1442 playoutMode = fax;
1443 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001444 case kNetEqOff:
1445 playoutMode = off;
1446 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001447 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001448 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
1450 _engineStatisticsPtr->SetLastError(
1451 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1452 "SetNetEQPlayoutMode() failed to set playout mode");
1453 return -1;
1454 }
1455 return 0;
1456}
1457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001458int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001459Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1460{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001461 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 switch (playoutMode)
1463 {
1464 case voice:
1465 mode = kNetEqDefault;
1466 break;
1467 case streaming:
1468 mode = kNetEqStreaming;
1469 break;
1470 case fax:
1471 mode = kNetEqFax;
1472 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001473 case off:
1474 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 }
1476 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1477 VoEId(_instanceId,_channelId),
1478 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1479 return 0;
1480}
1481
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001482int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001483Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1484{
1485 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1486 "Channel::SetOnHoldStatus()");
1487 if (mode == kHoldSendAndPlay)
1488 {
1489 _outputIsOnHold = enable;
1490 _inputIsOnHold = enable;
1491 }
1492 else if (mode == kHoldPlayOnly)
1493 {
1494 _outputIsOnHold = enable;
1495 }
1496 if (mode == kHoldSendOnly)
1497 {
1498 _inputIsOnHold = enable;
1499 }
1500 return 0;
1501}
1502
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001503int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001504Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1505{
1506 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1507 "Channel::GetOnHoldStatus()");
1508 enabled = (_outputIsOnHold || _inputIsOnHold);
1509 if (_outputIsOnHold && _inputIsOnHold)
1510 {
1511 mode = kHoldSendAndPlay;
1512 }
1513 else if (_outputIsOnHold && !_inputIsOnHold)
1514 {
1515 mode = kHoldPlayOnly;
1516 }
1517 else if (!_outputIsOnHold && _inputIsOnHold)
1518 {
1519 mode = kHoldSendOnly;
1520 }
1521 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1522 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1523 enabled, mode);
1524 return 0;
1525}
1526
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001527int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001528Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1529{
1530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1531 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001532 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001533
1534 if (_voiceEngineObserverPtr)
1535 {
1536 _engineStatisticsPtr->SetLastError(
1537 VE_INVALID_OPERATION, kTraceError,
1538 "RegisterVoiceEngineObserver() observer already enabled");
1539 return -1;
1540 }
1541 _voiceEngineObserverPtr = &observer;
1542 return 0;
1543}
1544
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001545int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001546Channel::DeRegisterVoiceEngineObserver()
1547{
1548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1549 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001550 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001551
1552 if (!_voiceEngineObserverPtr)
1553 {
1554 _engineStatisticsPtr->SetLastError(
1555 VE_INVALID_OPERATION, kTraceWarning,
1556 "DeRegisterVoiceEngineObserver() observer already disabled");
1557 return 0;
1558 }
1559 _voiceEngineObserverPtr = NULL;
1560 return 0;
1561}
1562
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001563int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001564Channel::GetSendCodec(CodecInst& codec)
1565{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001566 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001567}
1568
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001569int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001570Channel::GetRecCodec(CodecInst& codec)
1571{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001572 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001573}
1574
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001575int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001576Channel::SetSendCodec(const CodecInst& codec)
1577{
1578 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1579 "Channel::SetSendCodec()");
1580
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001581 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001582 {
1583 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1584 "SetSendCodec() failed to register codec to ACM");
1585 return -1;
1586 }
1587
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001588 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001589 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001590 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1591 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001592 {
1593 WEBRTC_TRACE(
1594 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1595 "SetSendCodec() failed to register codec to"
1596 " RTP/RTCP module");
1597 return -1;
1598 }
1599 }
1600
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001601 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001602 {
1603 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1604 "SetSendCodec() failed to set audio packet size");
1605 return -1;
1606 }
1607
1608 return 0;
1609}
1610
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001611int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001612Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1613{
1614 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1615 "Channel::SetVADStatus(mode=%d)", mode);
1616 // To disable VAD, DTX must be disabled too
1617 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001618 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001619 {
1620 _engineStatisticsPtr->SetLastError(
1621 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1622 "SetVADStatus() failed to set VAD");
1623 return -1;
1624 }
1625 return 0;
1626}
1627
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001628int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001629Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1630{
1631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1632 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001633 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001634 {
1635 _engineStatisticsPtr->SetLastError(
1636 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1637 "GetVADStatus() failed to get VAD status");
1638 return -1;
1639 }
1640 disabledDTX = !disabledDTX;
1641 return 0;
1642}
1643
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001644int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001645Channel::SetRecPayloadType(const CodecInst& codec)
1646{
1647 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1648 "Channel::SetRecPayloadType()");
1649
1650 if (_playing)
1651 {
1652 _engineStatisticsPtr->SetLastError(
1653 VE_ALREADY_PLAYING, kTraceError,
1654 "SetRecPayloadType() unable to set PT while playing");
1655 return -1;
1656 }
1657 if (_receiving)
1658 {
1659 _engineStatisticsPtr->SetLastError(
1660 VE_ALREADY_LISTENING, kTraceError,
1661 "SetRecPayloadType() unable to set PT while listening");
1662 return -1;
1663 }
1664
1665 if (codec.pltype == -1)
1666 {
1667 // De-register the selected codec (RTP/RTCP module and ACM)
1668
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001669 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 CodecInst rxCodec = codec;
1671
1672 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001673 rtp_payload_registry_->ReceivePayloadType(
1674 rxCodec.plname,
1675 rxCodec.plfreq,
1676 rxCodec.channels,
1677 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1678 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001679 rxCodec.pltype = pltype;
1680
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001681 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001682 {
1683 _engineStatisticsPtr->SetLastError(
1684 VE_RTP_RTCP_MODULE_ERROR,
1685 kTraceError,
1686 "SetRecPayloadType() RTP/RTCP-module deregistration "
1687 "failed");
1688 return -1;
1689 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001690 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001691 {
1692 _engineStatisticsPtr->SetLastError(
1693 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1694 "SetRecPayloadType() ACM deregistration failed - 1");
1695 return -1;
1696 }
1697 return 0;
1698 }
1699
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001700 if (rtp_receiver_->RegisterReceivePayload(
1701 codec.plname,
1702 codec.pltype,
1703 codec.plfreq,
1704 codec.channels,
1705 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001706 {
1707 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001708 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1709 if (rtp_receiver_->RegisterReceivePayload(
1710 codec.plname,
1711 codec.pltype,
1712 codec.plfreq,
1713 codec.channels,
1714 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001715 {
1716 _engineStatisticsPtr->SetLastError(
1717 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1718 "SetRecPayloadType() RTP/RTCP-module registration failed");
1719 return -1;
1720 }
1721 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001722 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001723 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001724 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1725 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001726 {
1727 _engineStatisticsPtr->SetLastError(
1728 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1729 "SetRecPayloadType() ACM registration failed - 1");
1730 return -1;
1731 }
1732 }
1733 return 0;
1734}
1735
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001736int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001737Channel::GetRecPayloadType(CodecInst& codec)
1738{
1739 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1740 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001741 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001742 if (rtp_payload_registry_->ReceivePayloadType(
1743 codec.plname,
1744 codec.plfreq,
1745 codec.channels,
1746 (codec.rate < 0) ? 0 : codec.rate,
1747 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001748 {
1749 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001750 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001751 "GetRecPayloadType() failed to retrieve RX payload type");
1752 return -1;
1753 }
1754 codec.pltype = payloadType;
1755 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1756 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1757 return 0;
1758}
1759
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001760int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001761Channel::SetAMREncFormat(AmrMode mode)
1762{
1763 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1764 "Channel::SetAMREncFormat()");
1765
1766 // ACM doesn't support AMR
1767 return -1;
1768}
1769
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001770int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001771Channel::SetAMRDecFormat(AmrMode mode)
1772{
1773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1774 "Channel::SetAMRDecFormat()");
1775
1776 // ACM doesn't support AMR
1777 return -1;
1778}
1779
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001780int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001781Channel::SetAMRWbEncFormat(AmrMode mode)
1782{
1783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1784 "Channel::SetAMRWbEncFormat()");
1785
1786 // ACM doesn't support AMR
1787 return -1;
1788
1789}
1790
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001791int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001792Channel::SetAMRWbDecFormat(AmrMode mode)
1793{
1794 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1795 "Channel::SetAMRWbDecFormat()");
1796
1797 // ACM doesn't support AMR
1798 return -1;
1799}
1800
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001801int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001802Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1803{
1804 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1805 "Channel::SetSendCNPayloadType()");
1806
1807 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001808 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001809 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001810 if (frequency == kFreq32000Hz)
1811 samplingFreqHz = 32000;
1812 else if (frequency == kFreq16000Hz)
1813 samplingFreqHz = 16000;
1814
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001815 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001816 {
1817 _engineStatisticsPtr->SetLastError(
1818 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1819 "SetSendCNPayloadType() failed to retrieve default CN codec "
1820 "settings");
1821 return -1;
1822 }
1823
1824 // Modify the payload type (must be set to dynamic range)
1825 codec.pltype = type;
1826
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001827 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001828 {
1829 _engineStatisticsPtr->SetLastError(
1830 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1831 "SetSendCNPayloadType() failed to register CN to ACM");
1832 return -1;
1833 }
1834
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001835 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001836 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001837 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1838 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001839 {
1840 _engineStatisticsPtr->SetLastError(
1841 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1842 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1843 "module");
1844 return -1;
1845 }
1846 }
1847 return 0;
1848}
1849
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001850int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001851Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1852{
1853 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1854 "Channel::SetISACInitTargetRate()");
1855
1856 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001857 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001858 {
1859 _engineStatisticsPtr->SetLastError(
1860 VE_CODEC_ERROR, kTraceError,
1861 "SetISACInitTargetRate() failed to retrieve send codec");
1862 return -1;
1863 }
1864 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1865 {
1866 // This API is only valid if iSAC is setup to run in channel-adaptive
1867 // mode.
1868 // We do not validate the adaptive mode here. It is done later in the
1869 // ConfigISACBandwidthEstimator() API.
1870 _engineStatisticsPtr->SetLastError(
1871 VE_CODEC_ERROR, kTraceError,
1872 "SetISACInitTargetRate() send codec is not iSAC");
1873 return -1;
1874 }
1875
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001876 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001877 if (16000 == sendCodec.plfreq)
1878 {
1879 // Note that 0 is a valid and corresponds to "use default
1880 if ((rateBps != 0 &&
1881 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1882 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1883 {
1884 _engineStatisticsPtr->SetLastError(
1885 VE_INVALID_ARGUMENT, kTraceError,
1886 "SetISACInitTargetRate() invalid target rate - 1");
1887 return -1;
1888 }
1889 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001890 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001891 }
1892 else if (32000 == sendCodec.plfreq)
1893 {
1894 if ((rateBps != 0 &&
1895 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1896 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1897 {
1898 _engineStatisticsPtr->SetLastError(
1899 VE_INVALID_ARGUMENT, kTraceError,
1900 "SetISACInitTargetRate() invalid target rate - 2");
1901 return -1;
1902 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001903 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001904 }
1905
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001906 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001907 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1908 {
1909 _engineStatisticsPtr->SetLastError(
1910 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1911 "SetISACInitTargetRate() iSAC BWE config failed");
1912 return -1;
1913 }
1914
1915 return 0;
1916}
1917
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001918int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001919Channel::SetISACMaxRate(int rateBps)
1920{
1921 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1922 "Channel::SetISACMaxRate()");
1923
1924 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001925 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001926 {
1927 _engineStatisticsPtr->SetLastError(
1928 VE_CODEC_ERROR, kTraceError,
1929 "SetISACMaxRate() failed to retrieve send codec");
1930 return -1;
1931 }
1932 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1933 {
1934 // This API is only valid if iSAC is selected as sending codec.
1935 _engineStatisticsPtr->SetLastError(
1936 VE_CODEC_ERROR, kTraceError,
1937 "SetISACMaxRate() send codec is not iSAC");
1938 return -1;
1939 }
1940 if (16000 == sendCodec.plfreq)
1941 {
1942 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1943 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1944 {
1945 _engineStatisticsPtr->SetLastError(
1946 VE_INVALID_ARGUMENT, kTraceError,
1947 "SetISACMaxRate() invalid max rate - 1");
1948 return -1;
1949 }
1950 }
1951 else if (32000 == sendCodec.plfreq)
1952 {
1953 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1954 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1955 {
1956 _engineStatisticsPtr->SetLastError(
1957 VE_INVALID_ARGUMENT, kTraceError,
1958 "SetISACMaxRate() invalid max rate - 2");
1959 return -1;
1960 }
1961 }
1962 if (_sending)
1963 {
1964 _engineStatisticsPtr->SetLastError(
1965 VE_SENDING, kTraceError,
1966 "SetISACMaxRate() unable to set max rate while sending");
1967 return -1;
1968 }
1969
1970 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1971 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001972 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 {
1974 _engineStatisticsPtr->SetLastError(
1975 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1976 "SetISACMaxRate() failed to set max rate");
1977 return -1;
1978 }
1979
1980 return 0;
1981}
1982
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001983int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001984Channel::SetISACMaxPayloadSize(int sizeBytes)
1985{
1986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1987 "Channel::SetISACMaxPayloadSize()");
1988 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001989 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001990 {
1991 _engineStatisticsPtr->SetLastError(
1992 VE_CODEC_ERROR, kTraceError,
1993 "SetISACMaxPayloadSize() failed to retrieve send codec");
1994 return -1;
1995 }
1996 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1997 {
1998 _engineStatisticsPtr->SetLastError(
1999 VE_CODEC_ERROR, kTraceError,
2000 "SetISACMaxPayloadSize() send codec is not iSAC");
2001 return -1;
2002 }
2003 if (16000 == sendCodec.plfreq)
2004 {
2005 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2006 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2007 {
2008 _engineStatisticsPtr->SetLastError(
2009 VE_INVALID_ARGUMENT, kTraceError,
2010 "SetISACMaxPayloadSize() invalid max payload - 1");
2011 return -1;
2012 }
2013 }
2014 else if (32000 == sendCodec.plfreq)
2015 {
2016 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2017 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2018 {
2019 _engineStatisticsPtr->SetLastError(
2020 VE_INVALID_ARGUMENT, kTraceError,
2021 "SetISACMaxPayloadSize() invalid max payload - 2");
2022 return -1;
2023 }
2024 }
2025 if (_sending)
2026 {
2027 _engineStatisticsPtr->SetLastError(
2028 VE_SENDING, kTraceError,
2029 "SetISACMaxPayloadSize() unable to set max rate while sending");
2030 return -1;
2031 }
2032
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002033 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002034 {
2035 _engineStatisticsPtr->SetLastError(
2036 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2037 "SetISACMaxPayloadSize() failed to set max payload size");
2038 return -1;
2039 }
2040 return 0;
2041}
2042
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002043int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002044{
2045 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2046 "Channel::RegisterExternalTransport()");
2047
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002048 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002049
niklase@google.com470e71d2011-07-07 08:21:25 +00002050 if (_externalTransport)
2051 {
2052 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2053 kTraceError,
2054 "RegisterExternalTransport() external transport already enabled");
2055 return -1;
2056 }
2057 _externalTransport = true;
2058 _transportPtr = &transport;
2059 return 0;
2060}
2061
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002062int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002063Channel::DeRegisterExternalTransport()
2064{
2065 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2066 "Channel::DeRegisterExternalTransport()");
2067
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002068 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002069
niklase@google.com470e71d2011-07-07 08:21:25 +00002070 if (!_transportPtr)
2071 {
2072 _engineStatisticsPtr->SetLastError(
2073 VE_INVALID_OPERATION, kTraceWarning,
2074 "DeRegisterExternalTransport() external transport already "
2075 "disabled");
2076 return 0;
2077 }
2078 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002079 _transportPtr = NULL;
2080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2081 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002082 return 0;
2083}
2084
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002085int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002086 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2087 "Channel::ReceivedRTPPacket()");
2088
2089 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002090 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002091
2092 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002093 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2094 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002095 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2096 VoEId(_instanceId,_channelId),
2097 "Channel::SendPacket() RTP dump to input file failed");
2098 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002099 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002100 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002101 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2102 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2103 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002104 return -1;
2105 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002106 header.payload_type_frequency =
2107 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002108 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002109 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002110 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002111 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002112 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002113 rtp_payload_registry_->SetIncomingPayloadType(header);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002114 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002115}
2116
2117bool Channel::ReceivePacket(const uint8_t* packet,
2118 int packet_length,
2119 const RTPHeader& header,
2120 bool in_order) {
2121 if (rtp_payload_registry_->IsEncapsulated(header)) {
2122 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002123 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002124 const uint8_t* payload = packet + header.headerLength;
2125 int payload_length = packet_length - header.headerLength;
2126 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002127 PayloadUnion payload_specific;
2128 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002129 &payload_specific)) {
2130 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002131 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002132 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2133 payload_specific, in_order);
2134}
2135
2136bool Channel::HandleEncapsulation(const uint8_t* packet,
2137 int packet_length,
2138 const RTPHeader& header) {
2139 if (!rtp_payload_registry_->IsRtx(header))
2140 return false;
2141
2142 // Remove the RTX header and parse the original RTP header.
2143 if (packet_length < header.headerLength)
2144 return false;
2145 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2146 return false;
2147 if (restored_packet_in_use_) {
2148 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2149 "Multiple RTX headers detected, dropping packet");
2150 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002151 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002152 uint8_t* restored_packet_ptr = restored_packet_;
2153 if (!rtp_payload_registry_->RestoreOriginalPacket(
2154 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2155 header)) {
2156 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2157 "Incoming RTX packet: invalid RTP header");
2158 return false;
2159 }
2160 restored_packet_in_use_ = true;
2161 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2162 restored_packet_in_use_ = false;
2163 return ret;
2164}
2165
2166bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2167 StreamStatistician* statistician =
2168 rtp_receive_statistics_->GetStatistician(header.ssrc);
2169 if (!statistician)
2170 return false;
2171 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002172}
2173
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002174bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2175 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002176 // Retransmissions are handled separately if RTX is enabled.
2177 if (rtp_payload_registry_->RtxEnabled())
2178 return false;
2179 StreamStatistician* statistician =
2180 rtp_receive_statistics_->GetStatistician(header.ssrc);
2181 if (!statistician)
2182 return false;
2183 // Check if this is a retransmission.
2184 uint16_t min_rtt = 0;
2185 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002186 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002187 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002188}
2189
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002190int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002191 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2192 "Channel::ReceivedRTCPPacket()");
2193 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002194 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002195
2196 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002197 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2198 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2200 VoEId(_instanceId,_channelId),
2201 "Channel::SendPacket() RTCP dump to input file failed");
2202 }
2203
2204 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002205 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2206 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002207 _engineStatisticsPtr->SetLastError(
2208 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2209 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2210 }
2211 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002212}
2213
niklase@google.com470e71d2011-07-07 08:21:25 +00002214int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002215 bool loop,
2216 FileFormats format,
2217 int startPosition,
2218 float volumeScaling,
2219 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002220 const CodecInst* codecInst)
2221{
2222 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2223 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2224 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2225 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2226 startPosition, stopPosition);
2227
2228 if (_outputFilePlaying)
2229 {
2230 _engineStatisticsPtr->SetLastError(
2231 VE_ALREADY_PLAYING, kTraceError,
2232 "StartPlayingFileLocally() is already playing");
2233 return -1;
2234 }
2235
niklase@google.com470e71d2011-07-07 08:21:25 +00002236 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002237 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002238
2239 if (_outputFilePlayerPtr)
2240 {
2241 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2242 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2243 _outputFilePlayerPtr = NULL;
2244 }
2245
2246 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2247 _outputFilePlayerId, (const FileFormats)format);
2248
2249 if (_outputFilePlayerPtr == NULL)
2250 {
2251 _engineStatisticsPtr->SetLastError(
2252 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002253 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002254 return -1;
2255 }
2256
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002257 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002258
2259 if (_outputFilePlayerPtr->StartPlayingFile(
2260 fileName,
2261 loop,
2262 startPosition,
2263 volumeScaling,
2264 notificationTime,
2265 stopPosition,
2266 (const CodecInst*)codecInst) != 0)
2267 {
2268 _engineStatisticsPtr->SetLastError(
2269 VE_BAD_FILE, kTraceError,
2270 "StartPlayingFile() failed to start file playout");
2271 _outputFilePlayerPtr->StopPlayingFile();
2272 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2273 _outputFilePlayerPtr = NULL;
2274 return -1;
2275 }
2276 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2277 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002278 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002279
2280 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002281 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002282
2283 return 0;
2284}
2285
2286int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002287 FileFormats format,
2288 int startPosition,
2289 float volumeScaling,
2290 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002291 const CodecInst* codecInst)
2292{
2293 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2294 "Channel::StartPlayingFileLocally(format=%d,"
2295 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2296 format, volumeScaling, startPosition, stopPosition);
2297
2298 if(stream == NULL)
2299 {
2300 _engineStatisticsPtr->SetLastError(
2301 VE_BAD_FILE, kTraceError,
2302 "StartPlayingFileLocally() NULL as input stream");
2303 return -1;
2304 }
2305
2306
2307 if (_outputFilePlaying)
2308 {
2309 _engineStatisticsPtr->SetLastError(
2310 VE_ALREADY_PLAYING, kTraceError,
2311 "StartPlayingFileLocally() is already playing");
2312 return -1;
2313 }
2314
niklase@google.com470e71d2011-07-07 08:21:25 +00002315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002316 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002317
2318 // Destroy the old instance
2319 if (_outputFilePlayerPtr)
2320 {
2321 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2322 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2323 _outputFilePlayerPtr = NULL;
2324 }
2325
2326 // Create the instance
2327 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2328 _outputFilePlayerId,
2329 (const FileFormats)format);
2330
2331 if (_outputFilePlayerPtr == NULL)
2332 {
2333 _engineStatisticsPtr->SetLastError(
2334 VE_INVALID_ARGUMENT, kTraceError,
2335 "StartPlayingFileLocally() filePlayer format isnot correct");
2336 return -1;
2337 }
2338
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002339 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002340
2341 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2342 volumeScaling,
2343 notificationTime,
2344 stopPosition, codecInst) != 0)
2345 {
2346 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2347 "StartPlayingFile() failed to "
2348 "start file playout");
2349 _outputFilePlayerPtr->StopPlayingFile();
2350 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2351 _outputFilePlayerPtr = NULL;
2352 return -1;
2353 }
2354 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2355 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002356 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002357
2358 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002359 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002360
niklase@google.com470e71d2011-07-07 08:21:25 +00002361 return 0;
2362}
2363
2364int Channel::StopPlayingFileLocally()
2365{
2366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2367 "Channel::StopPlayingFileLocally()");
2368
2369 if (!_outputFilePlaying)
2370 {
2371 _engineStatisticsPtr->SetLastError(
2372 VE_INVALID_OPERATION, kTraceWarning,
2373 "StopPlayingFileLocally() isnot playing");
2374 return 0;
2375 }
2376
niklase@google.com470e71d2011-07-07 08:21:25 +00002377 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002378 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002379
2380 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2381 {
2382 _engineStatisticsPtr->SetLastError(
2383 VE_STOP_RECORDING_FAILED, kTraceError,
2384 "StopPlayingFile() could not stop playing");
2385 return -1;
2386 }
2387 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2388 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2389 _outputFilePlayerPtr = NULL;
2390 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002391 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002392 // _fileCritSect cannot be taken while calling
2393 // SetAnonymousMixibilityStatus. Refer to comments in
2394 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002395 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2396 {
2397 _engineStatisticsPtr->SetLastError(
2398 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002399 "StopPlayingFile() failed to stop participant from playing as"
2400 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002401 return -1;
2402 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002403
2404 return 0;
2405}
2406
2407int Channel::IsPlayingFileLocally() const
2408{
2409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2410 "Channel::IsPlayingFileLocally()");
2411
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002412 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002413}
2414
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002415int Channel::RegisterFilePlayingToMixer()
2416{
2417 // Return success for not registering for file playing to mixer if:
2418 // 1. playing file before playout is started on that channel.
2419 // 2. starting playout without file playing on that channel.
2420 if (!_playing || !_outputFilePlaying)
2421 {
2422 return 0;
2423 }
2424
2425 // |_fileCritSect| cannot be taken while calling
2426 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2427 // frames can be pulled by the mixer. Since the frames are generated from
2428 // the file, _fileCritSect will be taken. This would result in a deadlock.
2429 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2430 {
2431 CriticalSectionScoped cs(&_fileCritSect);
2432 _outputFilePlaying = false;
2433 _engineStatisticsPtr->SetLastError(
2434 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2435 "StartPlayingFile() failed to add participant as file to mixer");
2436 _outputFilePlayerPtr->StopPlayingFile();
2437 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2438 _outputFilePlayerPtr = NULL;
2439 return -1;
2440 }
2441
2442 return 0;
2443}
2444
pbos@webrtc.org92135212013-05-14 08:31:39 +00002445int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002446{
2447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2448 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2449
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002450 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002451
2452 if (!_outputFilePlaying)
2453 {
2454 _engineStatisticsPtr->SetLastError(
2455 VE_INVALID_OPERATION, kTraceError,
2456 "ScaleLocalFilePlayout() isnot playing");
2457 return -1;
2458 }
2459 if ((_outputFilePlayerPtr == NULL) ||
2460 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2461 {
2462 _engineStatisticsPtr->SetLastError(
2463 VE_BAD_ARGUMENT, kTraceError,
2464 "SetAudioScaling() failed to scale the playout");
2465 return -1;
2466 }
2467
2468 return 0;
2469}
2470
2471int Channel::GetLocalPlayoutPosition(int& positionMs)
2472{
2473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2474 "Channel::GetLocalPlayoutPosition(position=?)");
2475
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002476 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002477
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002478 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002479
2480 if (_outputFilePlayerPtr == NULL)
2481 {
2482 _engineStatisticsPtr->SetLastError(
2483 VE_INVALID_OPERATION, kTraceError,
2484 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2485 return -1;
2486 }
2487
2488 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2489 {
2490 _engineStatisticsPtr->SetLastError(
2491 VE_BAD_FILE, kTraceError,
2492 "GetLocalPlayoutPosition() failed");
2493 return -1;
2494 }
2495 positionMs = position;
2496
2497 return 0;
2498}
2499
2500int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002501 bool loop,
2502 FileFormats format,
2503 int startPosition,
2504 float volumeScaling,
2505 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002506 const CodecInst* codecInst)
2507{
2508 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2509 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2510 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2511 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2512 startPosition, stopPosition);
2513
2514 if (_inputFilePlaying)
2515 {
2516 _engineStatisticsPtr->SetLastError(
2517 VE_ALREADY_PLAYING, kTraceWarning,
2518 "StartPlayingFileAsMicrophone() filePlayer is playing");
2519 return 0;
2520 }
2521
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002522 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002523
2524 // Destroy the old instance
2525 if (_inputFilePlayerPtr)
2526 {
2527 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2528 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2529 _inputFilePlayerPtr = NULL;
2530 }
2531
2532 // Create the instance
2533 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2534 _inputFilePlayerId, (const FileFormats)format);
2535
2536 if (_inputFilePlayerPtr == NULL)
2537 {
2538 _engineStatisticsPtr->SetLastError(
2539 VE_INVALID_ARGUMENT, kTraceError,
2540 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2541 return -1;
2542 }
2543
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002544 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002545
2546 if (_inputFilePlayerPtr->StartPlayingFile(
2547 fileName,
2548 loop,
2549 startPosition,
2550 volumeScaling,
2551 notificationTime,
2552 stopPosition,
2553 (const CodecInst*)codecInst) != 0)
2554 {
2555 _engineStatisticsPtr->SetLastError(
2556 VE_BAD_FILE, kTraceError,
2557 "StartPlayingFile() failed to start file playout");
2558 _inputFilePlayerPtr->StopPlayingFile();
2559 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2560 _inputFilePlayerPtr = NULL;
2561 return -1;
2562 }
2563 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2564 _inputFilePlaying = true;
2565
2566 return 0;
2567}
2568
2569int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002570 FileFormats format,
2571 int startPosition,
2572 float volumeScaling,
2573 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002574 const CodecInst* codecInst)
2575{
2576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2577 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2578 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2579 format, volumeScaling, startPosition, stopPosition);
2580
2581 if(stream == NULL)
2582 {
2583 _engineStatisticsPtr->SetLastError(
2584 VE_BAD_FILE, kTraceError,
2585 "StartPlayingFileAsMicrophone NULL as input stream");
2586 return -1;
2587 }
2588
2589 if (_inputFilePlaying)
2590 {
2591 _engineStatisticsPtr->SetLastError(
2592 VE_ALREADY_PLAYING, kTraceWarning,
2593 "StartPlayingFileAsMicrophone() is playing");
2594 return 0;
2595 }
2596
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002597 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002598
2599 // Destroy the old instance
2600 if (_inputFilePlayerPtr)
2601 {
2602 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2603 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2604 _inputFilePlayerPtr = NULL;
2605 }
2606
2607 // Create the instance
2608 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2609 _inputFilePlayerId, (const FileFormats)format);
2610
2611 if (_inputFilePlayerPtr == NULL)
2612 {
2613 _engineStatisticsPtr->SetLastError(
2614 VE_INVALID_ARGUMENT, kTraceError,
2615 "StartPlayingInputFile() filePlayer format isnot correct");
2616 return -1;
2617 }
2618
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002619 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002620
2621 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2622 volumeScaling, notificationTime,
2623 stopPosition, codecInst) != 0)
2624 {
2625 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2626 "StartPlayingFile() failed to start "
2627 "file playout");
2628 _inputFilePlayerPtr->StopPlayingFile();
2629 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2630 _inputFilePlayerPtr = NULL;
2631 return -1;
2632 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002633
niklase@google.com470e71d2011-07-07 08:21:25 +00002634 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2635 _inputFilePlaying = true;
2636
2637 return 0;
2638}
2639
2640int Channel::StopPlayingFileAsMicrophone()
2641{
2642 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2643 "Channel::StopPlayingFileAsMicrophone()");
2644
2645 if (!_inputFilePlaying)
2646 {
2647 _engineStatisticsPtr->SetLastError(
2648 VE_INVALID_OPERATION, kTraceWarning,
2649 "StopPlayingFileAsMicrophone() isnot playing");
2650 return 0;
2651 }
2652
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002653 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002654 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2655 {
2656 _engineStatisticsPtr->SetLastError(
2657 VE_STOP_RECORDING_FAILED, kTraceError,
2658 "StopPlayingFile() could not stop playing");
2659 return -1;
2660 }
2661 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2662 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2663 _inputFilePlayerPtr = NULL;
2664 _inputFilePlaying = false;
2665
2666 return 0;
2667}
2668
2669int Channel::IsPlayingFileAsMicrophone() const
2670{
2671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2672 "Channel::IsPlayingFileAsMicrophone()");
2673
2674 return _inputFilePlaying;
2675}
2676
pbos@webrtc.org92135212013-05-14 08:31:39 +00002677int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002678{
2679 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2680 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2681
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002682 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002683
2684 if (!_inputFilePlaying)
2685 {
2686 _engineStatisticsPtr->SetLastError(
2687 VE_INVALID_OPERATION, kTraceError,
2688 "ScaleFileAsMicrophonePlayout() isnot playing");
2689 return -1;
2690 }
2691
2692 if ((_inputFilePlayerPtr == NULL) ||
2693 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2694 {
2695 _engineStatisticsPtr->SetLastError(
2696 VE_BAD_ARGUMENT, kTraceError,
2697 "SetAudioScaling() failed to scale playout");
2698 return -1;
2699 }
2700
2701 return 0;
2702}
2703
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002704int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002705 const CodecInst* codecInst)
2706{
2707 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2708 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2709
2710 if (_outputFileRecording)
2711 {
2712 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2713 "StartRecordingPlayout() is already recording");
2714 return 0;
2715 }
2716
2717 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002718 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002719 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2720
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002721 if ((codecInst != NULL) &&
2722 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002723 {
2724 _engineStatisticsPtr->SetLastError(
2725 VE_BAD_ARGUMENT, kTraceError,
2726 "StartRecordingPlayout() invalid compression");
2727 return(-1);
2728 }
2729 if(codecInst == NULL)
2730 {
2731 format = kFileFormatPcm16kHzFile;
2732 codecInst=&dummyCodec;
2733 }
2734 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2735 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2736 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2737 {
2738 format = kFileFormatWavFile;
2739 }
2740 else
2741 {
2742 format = kFileFormatCompressedFile;
2743 }
2744
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002745 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002746
2747 // Destroy the old instance
2748 if (_outputFileRecorderPtr)
2749 {
2750 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2751 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2752 _outputFileRecorderPtr = NULL;
2753 }
2754
2755 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2756 _outputFileRecorderId, (const FileFormats)format);
2757 if (_outputFileRecorderPtr == NULL)
2758 {
2759 _engineStatisticsPtr->SetLastError(
2760 VE_INVALID_ARGUMENT, kTraceError,
2761 "StartRecordingPlayout() fileRecorder format isnot correct");
2762 return -1;
2763 }
2764
2765 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2766 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2767 {
2768 _engineStatisticsPtr->SetLastError(
2769 VE_BAD_FILE, kTraceError,
2770 "StartRecordingAudioFile() failed to start file recording");
2771 _outputFileRecorderPtr->StopRecording();
2772 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2773 _outputFileRecorderPtr = NULL;
2774 return -1;
2775 }
2776 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2777 _outputFileRecording = true;
2778
2779 return 0;
2780}
2781
2782int Channel::StartRecordingPlayout(OutStream* stream,
2783 const CodecInst* codecInst)
2784{
2785 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2786 "Channel::StartRecordingPlayout()");
2787
2788 if (_outputFileRecording)
2789 {
2790 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2791 "StartRecordingPlayout() is already recording");
2792 return 0;
2793 }
2794
2795 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002796 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2798
2799 if (codecInst != NULL && codecInst->channels != 1)
2800 {
2801 _engineStatisticsPtr->SetLastError(
2802 VE_BAD_ARGUMENT, kTraceError,
2803 "StartRecordingPlayout() invalid compression");
2804 return(-1);
2805 }
2806 if(codecInst == NULL)
2807 {
2808 format = kFileFormatPcm16kHzFile;
2809 codecInst=&dummyCodec;
2810 }
2811 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2812 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2813 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2814 {
2815 format = kFileFormatWavFile;
2816 }
2817 else
2818 {
2819 format = kFileFormatCompressedFile;
2820 }
2821
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002822 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002823
2824 // Destroy the old instance
2825 if (_outputFileRecorderPtr)
2826 {
2827 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2828 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2829 _outputFileRecorderPtr = NULL;
2830 }
2831
2832 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2833 _outputFileRecorderId, (const FileFormats)format);
2834 if (_outputFileRecorderPtr == NULL)
2835 {
2836 _engineStatisticsPtr->SetLastError(
2837 VE_INVALID_ARGUMENT, kTraceError,
2838 "StartRecordingPlayout() fileRecorder format isnot correct");
2839 return -1;
2840 }
2841
2842 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2843 notificationTime) != 0)
2844 {
2845 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2846 "StartRecordingPlayout() failed to "
2847 "start file recording");
2848 _outputFileRecorderPtr->StopRecording();
2849 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2850 _outputFileRecorderPtr = NULL;
2851 return -1;
2852 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002853
niklase@google.com470e71d2011-07-07 08:21:25 +00002854 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2855 _outputFileRecording = true;
2856
2857 return 0;
2858}
2859
2860int Channel::StopRecordingPlayout()
2861{
2862 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2863 "Channel::StopRecordingPlayout()");
2864
2865 if (!_outputFileRecording)
2866 {
2867 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2868 "StopRecordingPlayout() isnot recording");
2869 return -1;
2870 }
2871
2872
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002873 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002874
2875 if (_outputFileRecorderPtr->StopRecording() != 0)
2876 {
2877 _engineStatisticsPtr->SetLastError(
2878 VE_STOP_RECORDING_FAILED, kTraceError,
2879 "StopRecording() could not stop recording");
2880 return(-1);
2881 }
2882 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2883 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2884 _outputFileRecorderPtr = NULL;
2885 _outputFileRecording = false;
2886
2887 return 0;
2888}
2889
2890void
2891Channel::SetMixWithMicStatus(bool mix)
2892{
2893 _mixFileWithMicrophone=mix;
2894}
2895
2896int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002897Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002898{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002899 int8_t currentLevel = _outputAudioLevel.Level();
2900 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2902 VoEId(_instanceId,_channelId),
2903 "GetSpeechOutputLevel() => level=%u", level);
2904 return 0;
2905}
2906
2907int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002908Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002909{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002910 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2911 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002912 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2913 VoEId(_instanceId,_channelId),
2914 "GetSpeechOutputLevelFullRange() => level=%u", level);
2915 return 0;
2916}
2917
2918int
2919Channel::SetMute(bool enable)
2920{
wu@webrtc.org63420662013-10-17 18:28:55 +00002921 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002922 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2923 "Channel::SetMute(enable=%d)", enable);
2924 _mute = enable;
2925 return 0;
2926}
2927
2928bool
2929Channel::Mute() const
2930{
wu@webrtc.org63420662013-10-17 18:28:55 +00002931 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002932 return _mute;
2933}
2934
2935int
2936Channel::SetOutputVolumePan(float left, float right)
2937{
wu@webrtc.org63420662013-10-17 18:28:55 +00002938 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002939 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2940 "Channel::SetOutputVolumePan()");
2941 _panLeft = left;
2942 _panRight = right;
2943 return 0;
2944}
2945
2946int
2947Channel::GetOutputVolumePan(float& left, float& right) const
2948{
wu@webrtc.org63420662013-10-17 18:28:55 +00002949 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002950 left = _panLeft;
2951 right = _panRight;
2952 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2953 VoEId(_instanceId,_channelId),
2954 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2955 return 0;
2956}
2957
2958int
2959Channel::SetChannelOutputVolumeScaling(float scaling)
2960{
wu@webrtc.org63420662013-10-17 18:28:55 +00002961 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002962 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2963 "Channel::SetChannelOutputVolumeScaling()");
2964 _outputGain = scaling;
2965 return 0;
2966}
2967
2968int
2969Channel::GetChannelOutputVolumeScaling(float& scaling) const
2970{
wu@webrtc.org63420662013-10-17 18:28:55 +00002971 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002972 scaling = _outputGain;
2973 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2974 VoEId(_instanceId,_channelId),
2975 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2976 return 0;
2977}
2978
niklase@google.com470e71d2011-07-07 08:21:25 +00002979int
2980Channel::RegisterExternalEncryption(Encryption& encryption)
2981{
2982 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2983 "Channel::RegisterExternalEncryption()");
2984
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002985 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002986
2987 if (_encryptionPtr)
2988 {
2989 _engineStatisticsPtr->SetLastError(
2990 VE_INVALID_OPERATION, kTraceError,
2991 "RegisterExternalEncryption() encryption already enabled");
2992 return -1;
2993 }
2994
2995 _encryptionPtr = &encryption;
2996
2997 _decrypting = true;
2998 _encrypting = true;
2999
3000 return 0;
3001}
3002
3003int
3004Channel::DeRegisterExternalEncryption()
3005{
3006 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3007 "Channel::DeRegisterExternalEncryption()");
3008
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003009 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003010
3011 if (!_encryptionPtr)
3012 {
3013 _engineStatisticsPtr->SetLastError(
3014 VE_INVALID_OPERATION, kTraceWarning,
3015 "DeRegisterExternalEncryption() encryption already disabled");
3016 return 0;
3017 }
3018
3019 _decrypting = false;
3020 _encrypting = false;
3021
3022 _encryptionPtr = NULL;
3023
3024 return 0;
3025}
3026
3027int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003028 int lengthMs, int attenuationDb,
3029 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003030{
3031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3032 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3033 playDtmfEvent);
3034
3035 _playOutbandDtmfEvent = playDtmfEvent;
3036
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003037 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003038 attenuationDb) != 0)
3039 {
3040 _engineStatisticsPtr->SetLastError(
3041 VE_SEND_DTMF_FAILED,
3042 kTraceWarning,
3043 "SendTelephoneEventOutband() failed to send event");
3044 return -1;
3045 }
3046 return 0;
3047}
3048
3049int Channel::SendTelephoneEventInband(unsigned char eventCode,
3050 int lengthMs,
3051 int attenuationDb,
3052 bool playDtmfEvent)
3053{
3054 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3055 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3056 playDtmfEvent);
3057
3058 _playInbandDtmfEvent = playDtmfEvent;
3059 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3060
3061 return 0;
3062}
3063
3064int
3065Channel::SetDtmfPlayoutStatus(bool enable)
3066{
3067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3068 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003069 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003070 {
3071 _engineStatisticsPtr->SetLastError(
3072 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3073 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3074 return -1;
3075 }
3076 return 0;
3077}
3078
3079bool
3080Channel::DtmfPlayoutStatus() const
3081{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003082 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003083}
3084
3085int
3086Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3087{
3088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3089 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003090 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003091 {
3092 _engineStatisticsPtr->SetLastError(
3093 VE_INVALID_ARGUMENT, kTraceError,
3094 "SetSendTelephoneEventPayloadType() invalid type");
3095 return -1;
3096 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003097 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003098 codec.plfreq = 8000;
3099 codec.pltype = type;
3100 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003101 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003102 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003103 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3104 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3105 _engineStatisticsPtr->SetLastError(
3106 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3107 "SetSendTelephoneEventPayloadType() failed to register send"
3108 "payload type");
3109 return -1;
3110 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003111 }
3112 _sendTelephoneEventPayloadType = type;
3113 return 0;
3114}
3115
3116int
3117Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3118{
3119 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3120 "Channel::GetSendTelephoneEventPayloadType()");
3121 type = _sendTelephoneEventPayloadType;
3122 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3123 VoEId(_instanceId,_channelId),
3124 "GetSendTelephoneEventPayloadType() => type=%u", type);
3125 return 0;
3126}
3127
niklase@google.com470e71d2011-07-07 08:21:25 +00003128int
3129Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3130{
3131 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3132 "Channel::UpdateRxVadDetection()");
3133
3134 int vadDecision = 1;
3135
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003136 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003137
3138 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3139 {
3140 OnRxVadDetected(vadDecision);
3141 _oldVadDecision = vadDecision;
3142 }
3143
3144 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3145 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3146 vadDecision);
3147 return 0;
3148}
3149
3150int
3151Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3152{
3153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3154 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003155 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003156
3157 if (_rxVadObserverPtr)
3158 {
3159 _engineStatisticsPtr->SetLastError(
3160 VE_INVALID_OPERATION, kTraceError,
3161 "RegisterRxVadObserver() observer already enabled");
3162 return -1;
3163 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003164 _rxVadObserverPtr = &observer;
3165 _RxVadDetection = true;
3166 return 0;
3167}
3168
3169int
3170Channel::DeRegisterRxVadObserver()
3171{
3172 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3173 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003174 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003175
3176 if (!_rxVadObserverPtr)
3177 {
3178 _engineStatisticsPtr->SetLastError(
3179 VE_INVALID_OPERATION, kTraceWarning,
3180 "DeRegisterRxVadObserver() observer already disabled");
3181 return 0;
3182 }
3183 _rxVadObserverPtr = NULL;
3184 _RxVadDetection = false;
3185 return 0;
3186}
3187
3188int
3189Channel::VoiceActivityIndicator(int &activity)
3190{
3191 activity = _sendFrameType;
3192
3193 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003194 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003195 return 0;
3196}
3197
3198#ifdef WEBRTC_VOICE_ENGINE_AGC
3199
3200int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003201Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003202{
3203 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3204 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3205 (int)enable, (int)mode);
3206
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003207 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003208 switch (mode)
3209 {
3210 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003211 break;
3212 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003213 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003214 break;
3215 case kAgcFixedDigital:
3216 agcMode = GainControl::kFixedDigital;
3217 break;
3218 case kAgcAdaptiveDigital:
3219 agcMode =GainControl::kAdaptiveDigital;
3220 break;
3221 default:
3222 _engineStatisticsPtr->SetLastError(
3223 VE_INVALID_ARGUMENT, kTraceError,
3224 "SetRxAgcStatus() invalid Agc mode");
3225 return -1;
3226 }
3227
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003228 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003229 {
3230 _engineStatisticsPtr->SetLastError(
3231 VE_APM_ERROR, kTraceError,
3232 "SetRxAgcStatus() failed to set Agc mode");
3233 return -1;
3234 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003235 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003236 {
3237 _engineStatisticsPtr->SetLastError(
3238 VE_APM_ERROR, kTraceError,
3239 "SetRxAgcStatus() failed to set Agc state");
3240 return -1;
3241 }
3242
3243 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003244 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3245
3246 return 0;
3247}
3248
3249int
3250Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3251{
3252 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3253 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3254
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003255 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003256 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003257 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003258
3259 enabled = enable;
3260
3261 switch (agcMode)
3262 {
3263 case GainControl::kFixedDigital:
3264 mode = kAgcFixedDigital;
3265 break;
3266 case GainControl::kAdaptiveDigital:
3267 mode = kAgcAdaptiveDigital;
3268 break;
3269 default:
3270 _engineStatisticsPtr->SetLastError(
3271 VE_APM_ERROR, kTraceError,
3272 "GetRxAgcStatus() invalid Agc mode");
3273 return -1;
3274 }
3275
3276 return 0;
3277}
3278
3279int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003280Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003281{
3282 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3283 "Channel::SetRxAgcConfig()");
3284
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003285 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003286 config.targetLeveldBOv) != 0)
3287 {
3288 _engineStatisticsPtr->SetLastError(
3289 VE_APM_ERROR, kTraceError,
3290 "SetRxAgcConfig() failed to set target peak |level|"
3291 "(or envelope) of the Agc");
3292 return -1;
3293 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003294 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003295 config.digitalCompressionGaindB) != 0)
3296 {
3297 _engineStatisticsPtr->SetLastError(
3298 VE_APM_ERROR, kTraceError,
3299 "SetRxAgcConfig() failed to set the range in |gain| the"
3300 " digital compression stage may apply");
3301 return -1;
3302 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003303 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003304 config.limiterEnable) != 0)
3305 {
3306 _engineStatisticsPtr->SetLastError(
3307 VE_APM_ERROR, kTraceError,
3308 "SetRxAgcConfig() failed to set hard limiter to the signal");
3309 return -1;
3310 }
3311
3312 return 0;
3313}
3314
3315int
3316Channel::GetRxAgcConfig(AgcConfig& config)
3317{
3318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3319 "Channel::GetRxAgcConfig(config=%?)");
3320
3321 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003322 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003323 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003324 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003325 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003326 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003327
3328 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3329 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3330 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3331 " limiterEnable=%d",
3332 config.targetLeveldBOv,
3333 config.digitalCompressionGaindB,
3334 config.limiterEnable);
3335
3336 return 0;
3337}
3338
3339#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3340
3341#ifdef WEBRTC_VOICE_ENGINE_NR
3342
3343int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003344Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003345{
3346 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3347 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3348 (int)enable, (int)mode);
3349
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003350 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003351 switch (mode)
3352 {
3353
3354 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003355 break;
3356 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003357 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003358 break;
3359 case kNsConference:
3360 nsLevel = NoiseSuppression::kHigh;
3361 break;
3362 case kNsLowSuppression:
3363 nsLevel = NoiseSuppression::kLow;
3364 break;
3365 case kNsModerateSuppression:
3366 nsLevel = NoiseSuppression::kModerate;
3367 break;
3368 case kNsHighSuppression:
3369 nsLevel = NoiseSuppression::kHigh;
3370 break;
3371 case kNsVeryHighSuppression:
3372 nsLevel = NoiseSuppression::kVeryHigh;
3373 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003374 }
3375
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003376 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003377 != 0)
3378 {
3379 _engineStatisticsPtr->SetLastError(
3380 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003381 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003382 return -1;
3383 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003384 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003385 {
3386 _engineStatisticsPtr->SetLastError(
3387 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003388 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003389 return -1;
3390 }
3391
3392 _rxNsIsEnabled = enable;
3393 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3394
3395 return 0;
3396}
3397
3398int
3399Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3400{
3401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3402 "Channel::GetRxNsStatus(enable=?, mode=?)");
3403
3404 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003405 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003406 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003407 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003408
3409 enabled = enable;
3410
3411 switch (ncLevel)
3412 {
3413 case NoiseSuppression::kLow:
3414 mode = kNsLowSuppression;
3415 break;
3416 case NoiseSuppression::kModerate:
3417 mode = kNsModerateSuppression;
3418 break;
3419 case NoiseSuppression::kHigh:
3420 mode = kNsHighSuppression;
3421 break;
3422 case NoiseSuppression::kVeryHigh:
3423 mode = kNsVeryHighSuppression;
3424 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003425 }
3426
3427 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3428 VoEId(_instanceId,_channelId),
3429 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3430 return 0;
3431}
3432
3433#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3434
3435int
3436Channel::RegisterRTPObserver(VoERTPObserver& observer)
3437{
3438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3439 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003440 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003441
3442 if (_rtpObserverPtr)
3443 {
3444 _engineStatisticsPtr->SetLastError(
3445 VE_INVALID_OPERATION, kTraceError,
3446 "RegisterRTPObserver() observer already enabled");
3447 return -1;
3448 }
3449
3450 _rtpObserverPtr = &observer;
3451 _rtpObserver = true;
3452
3453 return 0;
3454}
3455
3456int
3457Channel::DeRegisterRTPObserver()
3458{
3459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3460 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003461 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003462
3463 if (!_rtpObserverPtr)
3464 {
3465 _engineStatisticsPtr->SetLastError(
3466 VE_INVALID_OPERATION, kTraceWarning,
3467 "DeRegisterRTPObserver() observer already disabled");
3468 return 0;
3469 }
3470
3471 _rtpObserver = false;
3472 _rtpObserverPtr = NULL;
3473
3474 return 0;
3475}
3476
3477int
3478Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3479{
3480 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3481 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003482 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003483
3484 if (_rtcpObserverPtr)
3485 {
3486 _engineStatisticsPtr->SetLastError(
3487 VE_INVALID_OPERATION, kTraceError,
3488 "RegisterRTCPObserver() observer already enabled");
3489 return -1;
3490 }
3491
3492 _rtcpObserverPtr = &observer;
3493 _rtcpObserver = true;
3494
3495 return 0;
3496}
3497
3498int
3499Channel::DeRegisterRTCPObserver()
3500{
3501 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3502 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003503 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003504
3505 if (!_rtcpObserverPtr)
3506 {
3507 _engineStatisticsPtr->SetLastError(
3508 VE_INVALID_OPERATION, kTraceWarning,
3509 "DeRegisterRTCPObserver() observer already disabled");
3510 return 0;
3511 }
3512
3513 _rtcpObserver = false;
3514 _rtcpObserverPtr = NULL;
3515
3516 return 0;
3517}
3518
3519int
3520Channel::SetLocalSSRC(unsigned int ssrc)
3521{
3522 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3523 "Channel::SetLocalSSRC()");
3524 if (_sending)
3525 {
3526 _engineStatisticsPtr->SetLastError(
3527 VE_ALREADY_SENDING, kTraceError,
3528 "SetLocalSSRC() already sending");
3529 return -1;
3530 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003531 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003532 {
3533 _engineStatisticsPtr->SetLastError(
3534 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3535 "SetLocalSSRC() failed to set SSRC");
3536 return -1;
3537 }
3538 return 0;
3539}
3540
3541int
3542Channel::GetLocalSSRC(unsigned int& ssrc)
3543{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003544 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003545 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3546 VoEId(_instanceId,_channelId),
3547 "GetLocalSSRC() => ssrc=%lu", ssrc);
3548 return 0;
3549}
3550
3551int
3552Channel::GetRemoteSSRC(unsigned int& ssrc)
3553{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003554 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003555 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3556 VoEId(_instanceId,_channelId),
3557 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3558 return 0;
3559}
3560
3561int
3562Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3563{
3564 if (arrCSRC == NULL)
3565 {
3566 _engineStatisticsPtr->SetLastError(
3567 VE_INVALID_ARGUMENT, kTraceError,
3568 "GetRemoteCSRCs() invalid array argument");
3569 return -1;
3570 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003571 uint32_t arrOfCSRC[kRtpCsrcSize];
3572 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003573 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003574 if (CSRCs > 0)
3575 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003576 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003577 for (int i = 0; i < (int) CSRCs; i++)
3578 {
3579 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3580 VoEId(_instanceId, _channelId),
3581 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3582 }
3583 } else
3584 {
3585 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3586 VoEId(_instanceId, _channelId),
3587 "GetRemoteCSRCs() => list is empty!");
3588 }
3589 return CSRCs;
3590}
3591
3592int
3593Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3594{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003595 if (rtp_audioproc_.get() == NULL) {
3596 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3597 _channelId)));
3598 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003599
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003600 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3601 AudioProcessing::kNoError) {
3602 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3603 "Failed to enable AudioProcessing::level_estimator()");
3604 return -1;
3605 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003606
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003607 _includeAudioLevelIndication = enable;
3608 if (enable) {
3609 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3610 ID);
3611 } else {
3612 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3613 }
3614 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003615}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003616
niklase@google.com470e71d2011-07-07 08:21:25 +00003617int
3618Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3619{
3620 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3621 VoEId(_instanceId,_channelId),
3622 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3623 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003624 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003625}
3626
3627int
3628Channel::SetRTCPStatus(bool enable)
3629{
3630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3631 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003632 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003633 kRtcpCompound : kRtcpOff) != 0)
3634 {
3635 _engineStatisticsPtr->SetLastError(
3636 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3637 "SetRTCPStatus() failed to set RTCP status");
3638 return -1;
3639 }
3640 return 0;
3641}
3642
3643int
3644Channel::GetRTCPStatus(bool& enabled)
3645{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003646 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003647 enabled = (method != kRtcpOff);
3648 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3649 VoEId(_instanceId,_channelId),
3650 "GetRTCPStatus() => enabled=%d", enabled);
3651 return 0;
3652}
3653
3654int
3655Channel::SetRTCP_CNAME(const char cName[256])
3656{
3657 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3658 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003659 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003660 {
3661 _engineStatisticsPtr->SetLastError(
3662 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3663 "SetRTCP_CNAME() failed to set RTCP CNAME");
3664 return -1;
3665 }
3666 return 0;
3667}
3668
3669int
3670Channel::GetRTCP_CNAME(char cName[256])
3671{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003672 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003673 {
3674 _engineStatisticsPtr->SetLastError(
3675 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3676 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3677 return -1;
3678 }
3679 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3680 VoEId(_instanceId, _channelId),
3681 "GetRTCP_CNAME() => cName=%s", cName);
3682 return 0;
3683}
3684
3685int
3686Channel::GetRemoteRTCP_CNAME(char cName[256])
3687{
3688 if (cName == NULL)
3689 {
3690 _engineStatisticsPtr->SetLastError(
3691 VE_INVALID_ARGUMENT, kTraceError,
3692 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3693 return -1;
3694 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003695 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003696 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003697 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003698 {
3699 _engineStatisticsPtr->SetLastError(
3700 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3701 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3702 return -1;
3703 }
3704 strcpy(cName, cname);
3705 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3706 VoEId(_instanceId, _channelId),
3707 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3708 return 0;
3709}
3710
3711int
3712Channel::GetRemoteRTCPData(
3713 unsigned int& NTPHigh,
3714 unsigned int& NTPLow,
3715 unsigned int& timestamp,
3716 unsigned int& playoutTimestamp,
3717 unsigned int* jitter,
3718 unsigned short* fractionLost)
3719{
3720 // --- Information from sender info in received Sender Reports
3721
3722 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003723 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003727 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003728 "side");
3729 return -1;
3730 }
3731
3732 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3733 // and octet count)
3734 NTPHigh = senderInfo.NTPseconds;
3735 NTPLow = senderInfo.NTPfraction;
3736 timestamp = senderInfo.RTPtimeStamp;
3737
3738 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3739 VoEId(_instanceId, _channelId),
3740 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3741 "timestamp=%lu",
3742 NTPHigh, NTPLow, timestamp);
3743
3744 // --- Locally derived information
3745
3746 // This value is updated on each incoming RTCP packet (0 when no packet
3747 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003748 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003749
3750 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3751 VoEId(_instanceId, _channelId),
3752 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003753 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003754
3755 if (NULL != jitter || NULL != fractionLost)
3756 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003757 // Get all RTCP receiver report blocks that have been received on this
3758 // channel. If we receive RTP packets from a remote source we know the
3759 // remote SSRC and use the report block from him.
3760 // Otherwise use the first report block.
3761 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003762 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003763 remote_stats.empty()) {
3764 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3765 VoEId(_instanceId, _channelId),
3766 "GetRemoteRTCPData() failed to measure statistics due"
3767 " to lack of received RTP and/or RTCP packets");
3768 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003769 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003770
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003771 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003772 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3773 for (; it != remote_stats.end(); ++it) {
3774 if (it->remoteSSRC == remoteSSRC)
3775 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003777
3778 if (it == remote_stats.end()) {
3779 // If we have not received any RTCP packets from this SSRC it probably
3780 // means that we have not received any RTP packets.
3781 // Use the first received report block instead.
3782 it = remote_stats.begin();
3783 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003784 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003785
xians@webrtc.org79af7342012-01-31 12:22:14 +00003786 if (jitter) {
3787 *jitter = it->jitter;
3788 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3789 VoEId(_instanceId, _channelId),
3790 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3791 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003792
xians@webrtc.org79af7342012-01-31 12:22:14 +00003793 if (fractionLost) {
3794 *fractionLost = it->fractionLost;
3795 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3796 VoEId(_instanceId, _channelId),
3797 "GetRemoteRTCPData() => fractionLost = %lu",
3798 *fractionLost);
3799 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003800 }
3801 return 0;
3802}
3803
3804int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003805Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003806 unsigned int name,
3807 const char* data,
3808 unsigned short dataLengthInBytes)
3809{
3810 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3811 "Channel::SendApplicationDefinedRTCPPacket()");
3812 if (!_sending)
3813 {
3814 _engineStatisticsPtr->SetLastError(
3815 VE_NOT_SENDING, kTraceError,
3816 "SendApplicationDefinedRTCPPacket() not sending");
3817 return -1;
3818 }
3819 if (NULL == data)
3820 {
3821 _engineStatisticsPtr->SetLastError(
3822 VE_INVALID_ARGUMENT, kTraceError,
3823 "SendApplicationDefinedRTCPPacket() invalid data value");
3824 return -1;
3825 }
3826 if (dataLengthInBytes % 4 != 0)
3827 {
3828 _engineStatisticsPtr->SetLastError(
3829 VE_INVALID_ARGUMENT, kTraceError,
3830 "SendApplicationDefinedRTCPPacket() invalid length value");
3831 return -1;
3832 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003833 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003834 if (status == kRtcpOff)
3835 {
3836 _engineStatisticsPtr->SetLastError(
3837 VE_RTCP_ERROR, kTraceError,
3838 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3839 return -1;
3840 }
3841
3842 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003843 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003844 subType,
3845 name,
3846 (const unsigned char*) data,
3847 dataLengthInBytes) != 0)
3848 {
3849 _engineStatisticsPtr->SetLastError(
3850 VE_SEND_ERROR, kTraceError,
3851 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3852 return -1;
3853 }
3854 return 0;
3855}
3856
3857int
3858Channel::GetRTPStatistics(
3859 unsigned int& averageJitterMs,
3860 unsigned int& maxJitterMs,
3861 unsigned int& discardedPackets)
3862{
niklase@google.com470e71d2011-07-07 08:21:25 +00003863 // The jitter statistics is updated for each received RTP packet and is
3864 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003865 StreamStatistician::Statistics statistics;
3866 StreamStatistician* statistician =
3867 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3868 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003869 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3870 _engineStatisticsPtr->SetLastError(
3871 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3872 "GetRTPStatistics() failed to read RTP statistics from the "
3873 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003874 }
3875
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003876 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003877 if (playoutFrequency > 0)
3878 {
3879 // Scale RTP statistics given the current playout frequency
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003880 maxJitterMs = statistics.max_jitter / (playoutFrequency / 1000);
3881 averageJitterMs = statistics.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003882 }
3883
3884 discardedPackets = _numberOfDiscardedPackets;
3885
3886 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3887 VoEId(_instanceId, _channelId),
3888 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003889 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 averageJitterMs, maxJitterMs, discardedPackets);
3891 return 0;
3892}
3893
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003894int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3895 if (sender_info == NULL) {
3896 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3897 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3898 return -1;
3899 }
3900
3901 // Get the sender info from the latest received RTCP Sender Report.
3902 RTCPSenderInfo rtcp_sender_info;
3903 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3904 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3905 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3906 return -1;
3907 }
3908
3909 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3910 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3911 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3912 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3913 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3914 return 0;
3915}
3916
3917int Channel::GetRemoteRTCPReportBlocks(
3918 std::vector<ReportBlock>* report_blocks) {
3919 if (report_blocks == NULL) {
3920 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3921 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3922 return -1;
3923 }
3924
3925 // Get the report blocks from the latest received RTCP Sender or Receiver
3926 // Report. Each element in the vector contains the sender's SSRC and a
3927 // report block according to RFC 3550.
3928 std::vector<RTCPReportBlock> rtcp_report_blocks;
3929 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3930 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3931 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3932 return -1;
3933 }
3934
3935 if (rtcp_report_blocks.empty())
3936 return 0;
3937
3938 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3939 for (; it != rtcp_report_blocks.end(); ++it) {
3940 ReportBlock report_block;
3941 report_block.sender_SSRC = it->remoteSSRC;
3942 report_block.source_SSRC = it->sourceSSRC;
3943 report_block.fraction_lost = it->fractionLost;
3944 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3945 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3946 report_block.interarrival_jitter = it->jitter;
3947 report_block.last_SR_timestamp = it->lastSR;
3948 report_block.delay_since_last_SR = it->delaySinceLastSR;
3949 report_blocks->push_back(report_block);
3950 }
3951 return 0;
3952}
3953
niklase@google.com470e71d2011-07-07 08:21:25 +00003954int
3955Channel::GetRTPStatistics(CallStatistics& stats)
3956{
niklase@google.com470e71d2011-07-07 08:21:25 +00003957 // --- Part one of the final structure (four values)
3958
3959 // The jitter statistics is updated for each received RTP packet and is
3960 // based on received packets.
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003961 StreamStatistician::Statistics statistics;
3962 StreamStatistician* statistician =
3963 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3964 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003965 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3966 _engineStatisticsPtr->SetLastError(
3967 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3968 "GetRTPStatistics() failed to read RTP statistics from the "
3969 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003970 }
3971
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003972 stats.fractionLost = statistics.fraction_lost;
3973 stats.cumulativeLost = statistics.cumulative_lost;
3974 stats.extendedMax = statistics.extended_max_sequence_number;
3975 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003976
3977 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3978 VoEId(_instanceId, _channelId),
3979 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003980 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003981 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3982 stats.jitterSamples);
3983
3984 // --- Part two of the final structure (one value)
3985
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003986 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003987 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003988 if (method == kRtcpOff)
3989 {
3990 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3991 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003992 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003993 "measurements cannot be retrieved");
3994 } else
3995 {
3996 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003997 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003998 if (remoteSSRC > 0)
3999 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004000 uint16_t avgRTT(0);
4001 uint16_t maxRTT(0);
4002 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004003
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004004 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004005 != 0)
4006 {
4007 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4008 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004009 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004010 "the RTP/RTCP module");
4011 }
4012 } else
4013 {
4014 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4015 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004016 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004017 "RTP packets have been received yet");
4018 }
4019 }
4020
4021 stats.rttMs = static_cast<int> (RTT);
4022
4023 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4024 VoEId(_instanceId, _channelId),
4025 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4026
4027 // --- Part three of the final structure (four values)
4028
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004029 uint32_t bytesSent(0);
4030 uint32_t packetsSent(0);
4031 uint32_t bytesReceived(0);
4032 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004033
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004034 if (statistician) {
4035 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4036 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004037
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004038 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004039 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004040 {
4041 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4042 VoEId(_instanceId, _channelId),
4043 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004044 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004045 }
4046
4047 stats.bytesSent = bytesSent;
4048 stats.packetsSent = packetsSent;
4049 stats.bytesReceived = bytesReceived;
4050 stats.packetsReceived = packetsReceived;
4051
4052 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4053 VoEId(_instanceId, _channelId),
4054 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004055 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004056 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4057 stats.packetsReceived);
4058
4059 return 0;
4060}
4061
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004062int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4064 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004065
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004066 if (enable) {
4067 if (redPayloadtype < 0 || redPayloadtype > 127) {
4068 _engineStatisticsPtr->SetLastError(
4069 VE_PLTYPE_ERROR, kTraceError,
4070 "SetFECStatus() invalid RED payload type");
4071 return -1;
4072 }
4073
4074 if (SetRedPayloadType(redPayloadtype) < 0) {
4075 _engineStatisticsPtr->SetLastError(
4076 VE_CODEC_ERROR, kTraceError,
4077 "SetSecondarySendCodec() Failed to register RED ACM");
4078 return -1;
4079 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004080 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004081
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004082 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004083 _engineStatisticsPtr->SetLastError(
4084 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4085 "SetFECStatus() failed to set FEC state in the ACM");
4086 return -1;
4087 }
4088 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004089}
4090
4091int
4092Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4093{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004094 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004095 if (enabled)
4096 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004097 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004098 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004099 {
4100 _engineStatisticsPtr->SetLastError(
4101 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4102 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4103 "module");
4104 return -1;
4105 }
4106 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4107 VoEId(_instanceId, _channelId),
4108 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4109 enabled, redPayloadtype);
4110 return 0;
4111 }
4112 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4113 VoEId(_instanceId, _channelId),
4114 "GetFECStatus() => enabled=%d", enabled);
4115 return 0;
4116}
4117
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004118void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4119 // None of these functions can fail.
4120 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004121 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4122 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004123 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004124 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004125 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004126 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004127}
4128
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004129// Called when we are missing one or more packets.
4130int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004131 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4132}
4133
niklase@google.com470e71d2011-07-07 08:21:25 +00004134int
niklase@google.com470e71d2011-07-07 08:21:25 +00004135Channel::StartRTPDump(const char fileNameUTF8[1024],
4136 RTPDirections direction)
4137{
4138 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4139 "Channel::StartRTPDump()");
4140 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4141 {
4142 _engineStatisticsPtr->SetLastError(
4143 VE_INVALID_ARGUMENT, kTraceError,
4144 "StartRTPDump() invalid RTP direction");
4145 return -1;
4146 }
4147 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4148 &_rtpDumpIn : &_rtpDumpOut;
4149 if (rtpDumpPtr == NULL)
4150 {
4151 assert(false);
4152 return -1;
4153 }
4154 if (rtpDumpPtr->IsActive())
4155 {
4156 rtpDumpPtr->Stop();
4157 }
4158 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4159 {
4160 _engineStatisticsPtr->SetLastError(
4161 VE_BAD_FILE, kTraceError,
4162 "StartRTPDump() failed to create file");
4163 return -1;
4164 }
4165 return 0;
4166}
4167
4168int
4169Channel::StopRTPDump(RTPDirections direction)
4170{
4171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4172 "Channel::StopRTPDump()");
4173 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4174 {
4175 _engineStatisticsPtr->SetLastError(
4176 VE_INVALID_ARGUMENT, kTraceError,
4177 "StopRTPDump() invalid RTP direction");
4178 return -1;
4179 }
4180 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4181 &_rtpDumpIn : &_rtpDumpOut;
4182 if (rtpDumpPtr == NULL)
4183 {
4184 assert(false);
4185 return -1;
4186 }
4187 if (!rtpDumpPtr->IsActive())
4188 {
4189 return 0;
4190 }
4191 return rtpDumpPtr->Stop();
4192}
4193
4194bool
4195Channel::RTPDumpIsActive(RTPDirections direction)
4196{
4197 if ((direction != kRtpIncoming) &&
4198 (direction != kRtpOutgoing))
4199 {
4200 _engineStatisticsPtr->SetLastError(
4201 VE_INVALID_ARGUMENT, kTraceError,
4202 "RTPDumpIsActive() invalid RTP direction");
4203 return false;
4204 }
4205 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4206 &_rtpDumpIn : &_rtpDumpOut;
4207 return rtpDumpPtr->IsActive();
4208}
4209
4210int
4211Channel::InsertExtraRTPPacket(unsigned char payloadType,
4212 bool markerBit,
4213 const char* payloadData,
4214 unsigned short payloadSize)
4215{
4216 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4217 "Channel::InsertExtraRTPPacket()");
4218 if (payloadType > 127)
4219 {
4220 _engineStatisticsPtr->SetLastError(
4221 VE_INVALID_PLTYPE, kTraceError,
4222 "InsertExtraRTPPacket() invalid payload type");
4223 return -1;
4224 }
4225 if (payloadData == NULL)
4226 {
4227 _engineStatisticsPtr->SetLastError(
4228 VE_INVALID_ARGUMENT, kTraceError,
4229 "InsertExtraRTPPacket() invalid payload data");
4230 return -1;
4231 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004232 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004233 {
4234 _engineStatisticsPtr->SetLastError(
4235 VE_INVALID_ARGUMENT, kTraceError,
4236 "InsertExtraRTPPacket() invalid payload size");
4237 return -1;
4238 }
4239 if (!_sending)
4240 {
4241 _engineStatisticsPtr->SetLastError(
4242 VE_NOT_SENDING, kTraceError,
4243 "InsertExtraRTPPacket() not sending");
4244 return -1;
4245 }
4246
4247 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4248 // Transport::SendPacket() will be called by the module when the RTP packet
4249 // is created.
4250 // The call to SendOutgoingData() does *not* modify the timestamp and
4251 // payloadtype to ensure that the RTP module generates a valid RTP packet
4252 // (user might utilize a non-registered payload type).
4253 // The marker bit and payload type will be replaced just before the actual
4254 // transmission, i.e., the actual modification is done *after* the RTP
4255 // module has delivered its RTP packet back to the VoE.
4256 // We will use the stored values above when the packet is modified
4257 // (see Channel::SendPacket()).
4258
4259 _extraPayloadType = payloadType;
4260 _extraMarkerBit = markerBit;
4261 _insertExtraRTPPacket = true;
4262
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004263 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004264 _lastPayloadType,
4265 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004266 // Leaving the time when this frame was
4267 // received from the capture device as
4268 // undefined for voice for now.
4269 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004270 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004271 payloadSize) != 0)
4272 {
4273 _engineStatisticsPtr->SetLastError(
4274 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4275 "InsertExtraRTPPacket() failed to send extra RTP packet");
4276 return -1;
4277 }
4278
4279 return 0;
4280}
4281
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004282uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004283Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004284{
4285 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004286 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004287 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004288 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004289 return 0;
4290}
4291
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004292// TODO(xians): This method borrows quite some code from
4293// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4294// code duplication.
4295void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004296 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004297 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004298 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004299 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4300 static const int kMaxNumberOfFrames = 960;
4301 assert(number_of_frames <= kMaxNumberOfFrames);
4302
4303 // Get the send codec information for doing resampling or downmixing later on.
4304 CodecInst codec;
4305 GetSendCodec(codec);
4306 assert(codec.channels == 1 || codec.channels == 2);
4307 int support_sample_rate = std::min(32000,
4308 std::min(sample_rate, codec.plfreq));
4309
4310 // Downmix the data to mono if needed.
4311 const int16_t* audio_ptr = audio_data;
4312 if (number_of_channels == 2 && codec.channels == 1) {
4313 if (!mono_recording_audio_.get())
4314 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4315
4316 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4317 mono_recording_audio_.get());
4318 audio_ptr = mono_recording_audio_.get();
4319 }
4320
4321 // Resample the data to the sample rate that the codec is using.
4322 if (input_resampler_.InitializeIfNeeded(sample_rate,
4323 support_sample_rate,
4324 codec.channels)) {
4325 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4326 "Channel::Demultiplex() unable to resample");
4327 return;
4328 }
4329
4330 int out_length = input_resampler_.Resample(audio_ptr,
4331 number_of_frames * codec.channels,
4332 _audioFrame.data_,
4333 AudioFrame::kMaxDataSizeSamples);
4334 if (out_length == -1) {
4335 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4336 "Channel::Demultiplex() resampling failed");
4337 return;
4338 }
4339
4340 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4341 _audioFrame.timestamp_ = -1;
4342 _audioFrame.sample_rate_hz_ = support_sample_rate;
4343 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4344 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4345 _audioFrame.num_channels_ = codec.channels;
4346 _audioFrame.id_ = _channelId;
4347}
4348
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004349uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004350Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004351{
4352 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4353 "Channel::PrepareEncodeAndSend()");
4354
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004355 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004356 {
4357 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4358 "Channel::PrepareEncodeAndSend() invalid audio frame");
4359 return -1;
4360 }
4361
4362 if (_inputFilePlaying)
4363 {
4364 MixOrReplaceAudioWithFile(mixingFrequency);
4365 }
4366
wu@webrtc.org63420662013-10-17 18:28:55 +00004367 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004368 {
4369 AudioFrameOperations::Mute(_audioFrame);
4370 }
4371
4372 if (_inputExternalMedia)
4373 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004374 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004375 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004376 if (_inputExternalMediaCallbackPtr)
4377 {
4378 _inputExternalMediaCallbackPtr->Process(
4379 _channelId,
4380 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004381 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004382 _audioFrame.samples_per_channel_,
4383 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004384 isStereo);
4385 }
4386 }
4387
4388 InsertInbandDtmfTone();
4389
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004390 if (_includeAudioLevelIndication)
4391 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004392 if (rtp_audioproc_->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4393 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004394 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004395 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4396 VoEId(_instanceId, _channelId),
4397 "Error setting AudioProcessing sample rate");
4398 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004399 }
4400
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004401 if (rtp_audioproc_->set_num_channels(_audioFrame.num_channels_,
4402 _audioFrame.num_channels_) !=
4403 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004404 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004405 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4406 VoEId(_instanceId, _channelId),
4407 "Error setting AudioProcessing channels");
4408 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004409 }
4410
4411 // Performs level analysis only; does not affect the signal.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004412 rtp_audioproc_->ProcessStream(&_audioFrame);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004413 }
4414
niklase@google.com470e71d2011-07-07 08:21:25 +00004415 return 0;
4416}
4417
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004418uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004419Channel::EncodeAndSend()
4420{
4421 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4422 "Channel::EncodeAndSend()");
4423
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004424 assert(_audioFrame.num_channels_ <= 2);
4425 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004426 {
4427 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4428 "Channel::EncodeAndSend() invalid audio frame");
4429 return -1;
4430 }
4431
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004432 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004433
4434 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4435
4436 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004437 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004438 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004439 {
4440 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4441 "Channel::EncodeAndSend() ACM encoding failed");
4442 return -1;
4443 }
4444
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004445 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004446
4447 // --- Encode if complete frame is ready
4448
4449 // This call will trigger AudioPacketizationCallback::SendData if encoding
4450 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004451 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004452}
4453
4454int Channel::RegisterExternalMediaProcessing(
4455 ProcessingTypes type,
4456 VoEMediaProcess& processObject)
4457{
4458 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4459 "Channel::RegisterExternalMediaProcessing()");
4460
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004461 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004462
4463 if (kPlaybackPerChannel == type)
4464 {
4465 if (_outputExternalMediaCallbackPtr)
4466 {
4467 _engineStatisticsPtr->SetLastError(
4468 VE_INVALID_OPERATION, kTraceError,
4469 "Channel::RegisterExternalMediaProcessing() "
4470 "output external media already enabled");
4471 return -1;
4472 }
4473 _outputExternalMediaCallbackPtr = &processObject;
4474 _outputExternalMedia = true;
4475 }
4476 else if (kRecordingPerChannel == type)
4477 {
4478 if (_inputExternalMediaCallbackPtr)
4479 {
4480 _engineStatisticsPtr->SetLastError(
4481 VE_INVALID_OPERATION, kTraceError,
4482 "Channel::RegisterExternalMediaProcessing() "
4483 "output external media already enabled");
4484 return -1;
4485 }
4486 _inputExternalMediaCallbackPtr = &processObject;
4487 _inputExternalMedia = true;
4488 }
4489 return 0;
4490}
4491
4492int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4493{
4494 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4495 "Channel::DeRegisterExternalMediaProcessing()");
4496
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004497 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004498
4499 if (kPlaybackPerChannel == type)
4500 {
4501 if (!_outputExternalMediaCallbackPtr)
4502 {
4503 _engineStatisticsPtr->SetLastError(
4504 VE_INVALID_OPERATION, kTraceWarning,
4505 "Channel::DeRegisterExternalMediaProcessing() "
4506 "output external media already disabled");
4507 return 0;
4508 }
4509 _outputExternalMedia = false;
4510 _outputExternalMediaCallbackPtr = NULL;
4511 }
4512 else if (kRecordingPerChannel == type)
4513 {
4514 if (!_inputExternalMediaCallbackPtr)
4515 {
4516 _engineStatisticsPtr->SetLastError(
4517 VE_INVALID_OPERATION, kTraceWarning,
4518 "Channel::DeRegisterExternalMediaProcessing() "
4519 "input external media already disabled");
4520 return 0;
4521 }
4522 _inputExternalMedia = false;
4523 _inputExternalMediaCallbackPtr = NULL;
4524 }
4525
4526 return 0;
4527}
4528
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004529int Channel::SetExternalMixing(bool enabled) {
4530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4531 "Channel::SetExternalMixing(enabled=%d)", enabled);
4532
4533 if (_playing)
4534 {
4535 _engineStatisticsPtr->SetLastError(
4536 VE_INVALID_OPERATION, kTraceError,
4537 "Channel::SetExternalMixing() "
4538 "external mixing cannot be changed while playing.");
4539 return -1;
4540 }
4541
4542 _externalMixing = enabled;
4543
4544 return 0;
4545}
4546
niklase@google.com470e71d2011-07-07 08:21:25 +00004547int
4548Channel::ResetRTCPStatistics()
4549{
4550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4551 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004552 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004553 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004554 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004555}
4556
4557int
4558Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4559{
4560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4561 "Channel::GetRoundTripTimeSummary()");
4562 // Override default module outputs for the case when RTCP is disabled.
4563 // This is done to ensure that we are backward compatible with the
4564 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004565 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004566 {
4567 delaysMs.min = -1;
4568 delaysMs.max = -1;
4569 delaysMs.average = -1;
4570 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4571 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4572 " valid RTT measurements cannot be retrieved");
4573 return 0;
4574 }
4575
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004576 uint32_t remoteSSRC;
4577 uint16_t RTT;
4578 uint16_t avgRTT;
4579 uint16_t maxRTT;
4580 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004581 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004582 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004583 if (remoteSSRC == 0)
4584 {
4585 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4586 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4587 " since no RTP packet has been received yet");
4588 }
4589
4590 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4591 // channel and SSRC. The SSRC is required to parse out the correct source
4592 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004593 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004594 {
4595 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4596 "GetRoundTripTimeSummary unable to retrieve RTT values"
4597 " from the RTCP layer");
4598 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4599 }
4600 else
4601 {
4602 delaysMs.min = minRTT;
4603 delaysMs.max = maxRTT;
4604 delaysMs.average = avgRTT;
4605 }
4606 return 0;
4607}
4608
4609int
4610Channel::GetNetworkStatistics(NetworkStatistics& stats)
4611{
4612 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4613 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004614 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004615 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004616 if (return_value >= 0) {
4617 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4618 }
4619 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004620}
4621
wu@webrtc.org24301a62013-12-13 19:17:43 +00004622void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4623 audio_coding_->GetDecodingCallStatistics(stats);
4624}
4625
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004626bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4627 int* playout_buffer_delay_ms) const {
4628 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004629 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004630 "Channel::GetDelayEstimate() no valid estimate.");
4631 return false;
4632 }
4633 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4634 _recPacketDelayMs;
4635 *playout_buffer_delay_ms = playout_delay_ms_;
4636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4637 "Channel::GetDelayEstimate()");
4638 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004639}
4640
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004641int Channel::SetInitialPlayoutDelay(int delay_ms)
4642{
4643 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4644 "Channel::SetInitialPlayoutDelay()");
4645 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4646 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4647 {
4648 _engineStatisticsPtr->SetLastError(
4649 VE_INVALID_ARGUMENT, kTraceError,
4650 "SetInitialPlayoutDelay() invalid min delay");
4651 return -1;
4652 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004653 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004654 {
4655 _engineStatisticsPtr->SetLastError(
4656 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4657 "SetInitialPlayoutDelay() failed to set min playout delay");
4658 return -1;
4659 }
4660 return 0;
4661}
4662
4663
niklase@google.com470e71d2011-07-07 08:21:25 +00004664int
4665Channel::SetMinimumPlayoutDelay(int delayMs)
4666{
4667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4668 "Channel::SetMinimumPlayoutDelay()");
4669 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4670 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4671 {
4672 _engineStatisticsPtr->SetLastError(
4673 VE_INVALID_ARGUMENT, kTraceError,
4674 "SetMinimumPlayoutDelay() invalid min delay");
4675 return -1;
4676 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004677 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004678 {
4679 _engineStatisticsPtr->SetLastError(
4680 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4681 "SetMinimumPlayoutDelay() failed to set min playout delay");
4682 return -1;
4683 }
4684 return 0;
4685}
4686
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004687void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4688 uint32_t playout_timestamp = 0;
4689
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004690 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004691 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4692 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4693 " timestamp from the ACM");
4694 _engineStatisticsPtr->SetLastError(
4695 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4696 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4697 return;
4698 }
4699
4700 uint16_t delay_ms = 0;
4701 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4702 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4703 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4704 " delay from the ADM");
4705 _engineStatisticsPtr->SetLastError(
4706 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4707 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4708 return;
4709 }
4710
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004711 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004712 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004713 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004714 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4715 playout_frequency = 8000;
4716 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4717 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004718 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004719 }
4720
4721 // Remove the playout delay.
4722 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4723
4724 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4725 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4726 playout_timestamp);
4727
4728 if (rtcp) {
4729 playout_timestamp_rtcp_ = playout_timestamp;
4730 } else {
4731 playout_timestamp_rtp_ = playout_timestamp;
4732 }
4733 playout_delay_ms_ = delay_ms;
4734}
4735
4736int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4737 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4738 "Channel::GetPlayoutTimestamp()");
4739 if (playout_timestamp_rtp_ == 0) {
4740 _engineStatisticsPtr->SetLastError(
4741 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4742 "GetPlayoutTimestamp() failed to retrieve timestamp");
4743 return -1;
4744 }
4745 timestamp = playout_timestamp_rtp_;
4746 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4747 VoEId(_instanceId,_channelId),
4748 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4749 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004750}
4751
4752int
4753Channel::SetInitTimestamp(unsigned int timestamp)
4754{
4755 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4756 "Channel::SetInitTimestamp()");
4757 if (_sending)
4758 {
4759 _engineStatisticsPtr->SetLastError(
4760 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4761 return -1;
4762 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004763 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004764 {
4765 _engineStatisticsPtr->SetLastError(
4766 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4767 "SetInitTimestamp() failed to set timestamp");
4768 return -1;
4769 }
4770 return 0;
4771}
4772
4773int
4774Channel::SetInitSequenceNumber(short sequenceNumber)
4775{
4776 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4777 "Channel::SetInitSequenceNumber()");
4778 if (_sending)
4779 {
4780 _engineStatisticsPtr->SetLastError(
4781 VE_SENDING, kTraceError,
4782 "SetInitSequenceNumber() already sending");
4783 return -1;
4784 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004785 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004786 {
4787 _engineStatisticsPtr->SetLastError(
4788 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4789 "SetInitSequenceNumber() failed to set sequence number");
4790 return -1;
4791 }
4792 return 0;
4793}
4794
4795int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004796Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004797{
4798 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4799 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004800 *rtpRtcpModule = _rtpRtcpModule.get();
4801 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004802 return 0;
4803}
4804
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004805// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4806// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004807int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004808Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004809{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004810 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004811 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004812
4813 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004814 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004815
4816 if (_inputFilePlayerPtr == NULL)
4817 {
4818 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4819 VoEId(_instanceId, _channelId),
4820 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4821 " doesnt exist");
4822 return -1;
4823 }
4824
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004825 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004826 fileSamples,
4827 mixingFrequency) == -1)
4828 {
4829 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4830 VoEId(_instanceId, _channelId),
4831 "Channel::MixOrReplaceAudioWithFile() file mixing "
4832 "failed");
4833 return -1;
4834 }
4835 if (fileSamples == 0)
4836 {
4837 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4838 VoEId(_instanceId, _channelId),
4839 "Channel::MixOrReplaceAudioWithFile() file is ended");
4840 return 0;
4841 }
4842 }
4843
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004844 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004845
4846 if (_mixFileWithMicrophone)
4847 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004848 // Currently file stream is always mono.
4849 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004850 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004851 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004852 fileBuffer.get(),
4853 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004854 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004855 }
4856 else
4857 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004858 // Replace ACM audio with file.
4859 // Currently file stream is always mono.
4860 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004861 _audioFrame.UpdateFrame(_channelId,
4862 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004863 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004864 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004865 mixingFrequency,
4866 AudioFrame::kNormalSpeech,
4867 AudioFrame::kVadUnknown,
4868 1);
4869
4870 }
4871 return 0;
4872}
4873
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004874int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004875Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004876 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004877{
4878 assert(mixingFrequency <= 32000);
4879
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004880 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004881 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004882
4883 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004884 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004885
4886 if (_outputFilePlayerPtr == NULL)
4887 {
4888 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4889 VoEId(_instanceId, _channelId),
4890 "Channel::MixAudioWithFile() file mixing failed");
4891 return -1;
4892 }
4893
4894 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004895 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004896 fileSamples,
4897 mixingFrequency) == -1)
4898 {
4899 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4900 VoEId(_instanceId, _channelId),
4901 "Channel::MixAudioWithFile() file mixing failed");
4902 return -1;
4903 }
4904 }
4905
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004906 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004907 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004908 // Currently file stream is always mono.
4909 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004910 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004911 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004912 fileBuffer.get(),
4913 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004914 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004915 }
4916 else
4917 {
4918 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004919 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004920 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004921 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004922 return -1;
4923 }
4924
4925 return 0;
4926}
4927
4928int
4929Channel::InsertInbandDtmfTone()
4930{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004931 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004932 if (_inbandDtmfQueue.PendingDtmf() &&
4933 !_inbandDtmfGenerator.IsAddingTone() &&
4934 _inbandDtmfGenerator.DelaySinceLastTone() >
4935 kMinTelephoneEventSeparationMs)
4936 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004937 int8_t eventCode(0);
4938 uint16_t lengthMs(0);
4939 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004940
4941 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4942 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4943 if (_playInbandDtmfEvent)
4944 {
4945 // Add tone to output mixer using a reduced length to minimize
4946 // risk of echo.
4947 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4948 attenuationDb);
4949 }
4950 }
4951
4952 if (_inbandDtmfGenerator.IsAddingTone())
4953 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004954 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004955 _inbandDtmfGenerator.GetSampleRate(frequency);
4956
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004957 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004958 {
4959 // Update sample rate of Dtmf tone since the mixing frequency
4960 // has changed.
4961 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004962 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004963 // Reset the tone to be added taking the new sample rate into
4964 // account.
4965 _inbandDtmfGenerator.ResetTone();
4966 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004967
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004968 int16_t toneBuffer[320];
4969 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004970 // Get 10ms tone segment and set time since last tone to zero
4971 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4972 {
4973 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4974 VoEId(_instanceId, _channelId),
4975 "Channel::EncodeAndSend() inserting Dtmf failed");
4976 return -1;
4977 }
4978
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004979 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004980 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004981 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004982 sample++)
4983 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004984 for (int channel = 0;
4985 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004986 channel++)
4987 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004988 const int index = sample * _audioFrame.num_channels_ + channel;
4989 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004990 }
4991 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004992
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004993 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004994 } else
4995 {
4996 // Add 10ms to "delay-since-last-tone" counter
4997 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4998 }
4999 return 0;
5000}
5001
niklase@google.com470e71d2011-07-07 08:21:25 +00005002void
5003Channel::ResetDeadOrAliveCounters()
5004{
5005 _countDeadDetections = 0;
5006 _countAliveDetections = 0;
5007}
5008
5009void
5010Channel::UpdateDeadOrAliveCounters(bool alive)
5011{
5012 if (alive)
5013 _countAliveDetections++;
5014 else
5015 _countDeadDetections++;
5016}
5017
5018int
5019Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5020{
niklase@google.com470e71d2011-07-07 08:21:25 +00005021 return 0;
5022}
5023
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005024int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005025Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5026{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00005027 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005028 if (_transportPtr == NULL)
5029 {
5030 return -1;
5031 }
5032 if (!RTCP)
5033 {
5034 return _transportPtr->SendPacket(_channelId, data, len);
5035 }
5036 else
5037 {
5038 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5039 }
5040}
5041
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005042// Called for incoming RTP packets after successful RTP header parsing.
5043void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5044 uint16_t sequence_number) {
5045 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5046 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5047 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005048
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005049 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005050 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005051
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005052 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005053 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005054 return;
5055 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005056
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005057 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005058 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005059
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005060 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5061 // Even though the actual sampling rate for G.722 audio is
5062 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5063 // 8,000 Hz because that value was erroneously assigned in
5064 // RFC 1890 and must remain unchanged for backward compatibility.
5065 rtp_receive_frequency = 8000;
5066 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5067 // We are resampling Opus internally to 32,000 Hz until all our
5068 // DSP routines can operate at 48,000 Hz, but the RTP clock
5069 // rate for the Opus payload format is standardized to 48,000 Hz,
5070 // because that is the maximum supported decoding sampling rate.
5071 rtp_receive_frequency = 48000;
5072 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005073
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005074 // playout_timestamp_rtp_ updated in UpdatePlayoutTimestamp for every incoming
5075 // packet.
5076 uint32_t timestamp_diff_ms = (rtp_timestamp - playout_timestamp_rtp_) /
5077 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005078
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005079 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5080 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005081
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005082 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005083
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005084 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5085 timestamp_diff_ms = 0;
5086 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005087
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005088 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005089
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005090 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5091 _recPacketDelayMs = packet_delay_ms;
5092 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005093
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005094 if (_average_jitter_buffer_delay_us == 0) {
5095 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5096 return;
5097 }
5098
5099 // Filter average delay value using exponential filter (alpha is
5100 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5101 // risk of rounding error) and compensate for it in GetDelayEstimate()
5102 // later.
5103 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5104 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005105}
5106
5107void
5108Channel::RegisterReceiveCodecsToRTPModule()
5109{
5110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5111 "Channel::RegisterReceiveCodecsToRTPModule()");
5112
5113
5114 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005115 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005116
5117 for (int idx = 0; idx < nSupportedCodecs; idx++)
5118 {
5119 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005120 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005121 (rtp_receiver_->RegisterReceivePayload(
5122 codec.plname,
5123 codec.pltype,
5124 codec.plfreq,
5125 codec.channels,
5126 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005127 {
5128 WEBRTC_TRACE(
5129 kTraceWarning,
5130 kTraceVoice,
5131 VoEId(_instanceId, _channelId),
5132 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5133 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5134 codec.plname, codec.pltype, codec.plfreq,
5135 codec.channels, codec.rate);
5136 }
5137 else
5138 {
5139 WEBRTC_TRACE(
5140 kTraceInfo,
5141 kTraceVoice,
5142 VoEId(_instanceId, _channelId),
5143 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005144 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005145 "receiver",
5146 codec.plname, codec.pltype, codec.plfreq,
5147 codec.channels, codec.rate);
5148 }
5149 }
5150}
5151
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005152int Channel::ApmProcessRx(AudioFrame& frame) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005153 // Register the (possibly new) frame parameters.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005154 if (rx_audioproc_->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005155 assert(false);
5156 LOG_FERR1(LS_ERROR, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005157 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005158 if (rx_audioproc_->set_num_channels(frame.num_channels_,
5159 frame.num_channels_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005160 assert(false);
5161 LOG_FERR2(LS_ERROR, set_num_channels, frame.num_channels_,
5162 frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005163 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005164 if (rx_audioproc_->ProcessStream(&frame) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005165 assert(false);
5166 LOG_FERR0(LS_ERROR, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005167 }
5168 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005169}
5170
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005171int Channel::SetSecondarySendCodec(const CodecInst& codec,
5172 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005173 // Sanity check for payload type.
5174 if (red_payload_type < 0 || red_payload_type > 127) {
5175 _engineStatisticsPtr->SetLastError(
5176 VE_PLTYPE_ERROR, kTraceError,
5177 "SetRedPayloadType() invalid RED payload type");
5178 return -1;
5179 }
5180
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005181 if (SetRedPayloadType(red_payload_type) < 0) {
5182 _engineStatisticsPtr->SetLastError(
5183 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5184 "SetSecondarySendCodec() Failed to register RED ACM");
5185 return -1;
5186 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005187 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005188 _engineStatisticsPtr->SetLastError(
5189 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5190 "SetSecondarySendCodec() Failed to register secondary send codec in "
5191 "ACM");
5192 return -1;
5193 }
5194
5195 return 0;
5196}
5197
5198void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005199 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005200}
5201
5202int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005203 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005204 _engineStatisticsPtr->SetLastError(
5205 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5206 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5207 return -1;
5208 }
5209 return 0;
5210}
5211
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005212// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005213int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005214 CodecInst codec;
5215 bool found_red = false;
5216
5217 // Get default RED settings from the ACM database
5218 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5219 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005220 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005221 if (!STR_CASE_CMP(codec.plname, "RED")) {
5222 found_red = true;
5223 break;
5224 }
5225 }
5226
5227 if (!found_red) {
5228 _engineStatisticsPtr->SetLastError(
5229 VE_CODEC_ERROR, kTraceError,
5230 "SetRedPayloadType() RED is not supported");
5231 return -1;
5232 }
5233
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005234 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005235 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005236 _engineStatisticsPtr->SetLastError(
5237 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5238 "SetRedPayloadType() RED registration in ACM module failed");
5239 return -1;
5240 }
5241
5242 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5243 _engineStatisticsPtr->SetLastError(
5244 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5245 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5246 return -1;
5247 }
5248 return 0;
5249}
5250
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005251} // namespace voe
5252} // namespace webrtc