blob: 3f45feab793acc115a1c21424297506fa1caa0fd [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
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000041// Extend the default RTCP statistics struct with max_jitter, defined as the
42// maximum jitter value seen in an RTCP report block.
43struct ChannelStatistics : public RtcpStatistics {
44 ChannelStatistics() : rtcp(), max_jitter(0) {}
45
46 RtcpStatistics rtcp;
47 uint32_t max_jitter;
48};
49
50// Statistics callback, called at each generation of a new RTCP report block.
51class StatisticsProxy : public RtcpStatisticsCallback {
52 public:
53 StatisticsProxy(uint32_t ssrc)
54 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
55 ssrc_(ssrc) {}
56 virtual ~StatisticsProxy() {}
57
58 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
59 uint32_t ssrc) OVERRIDE {
60 if (ssrc != ssrc_)
61 return;
62
63 CriticalSectionScoped cs(stats_lock_.get());
64 stats_.rtcp = statistics;
65 if (statistics.jitter > stats_.max_jitter) {
66 stats_.max_jitter = statistics.jitter;
67 }
68 }
69
70 void ResetStatistics() {
71 CriticalSectionScoped cs(stats_lock_.get());
72 stats_ = ChannelStatistics();
73 }
74
75 ChannelStatistics GetStats() {
76 CriticalSectionScoped cs(stats_lock_.get());
77 return stats_;
78 }
79
80 private:
81 // StatisticsUpdated calls are triggered from threads in the RTP module,
82 // while GetStats calls can be triggered from the public voice engine API,
83 // hence synchronization is needed.
84 scoped_ptr<CriticalSectionWrapper> stats_lock_;
85 const uint32_t ssrc_;
86 ChannelStatistics stats_;
87};
88
pbos@webrtc.org6141e132013-04-09 10:09:10 +000089int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000090Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000091 uint8_t payloadType,
92 uint32_t timeStamp,
93 const uint8_t* payloadData,
94 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000095 const RTPFragmentationHeader* fragmentation)
96{
97 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
98 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
99 " payloadSize=%u, fragmentation=0x%x)",
100 frameType, payloadType, timeStamp, payloadSize, fragmentation);
101
102 if (_includeAudioLevelIndication)
103 {
104 // Store current audio level in the RTP/RTCP module.
105 // The level will be used in combination with voice-activity state
106 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000107 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 }
109
110 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
111 // packetization.
112 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000113 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 payloadType,
115 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000116 // Leaving the time when this frame was
117 // received from the capture device as
118 // undefined for voice for now.
119 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 payloadData,
121 payloadSize,
122 fragmentation) == -1)
123 {
124 _engineStatisticsPtr->SetLastError(
125 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
126 "Channel::SendData() failed to send data to RTP/RTCP module");
127 return -1;
128 }
129
130 _lastLocalTimeStamp = timeStamp;
131 _lastPayloadType = payloadType;
132
133 return 0;
134}
135
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136int32_t
137Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
140 "Channel::InFrameType(frameType=%d)", frameType);
141
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000142 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 // 1 indicates speech
144 _sendFrameType = (frameType == 1) ? 1 : 0;
145 return 0;
146}
147
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000148int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000149Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000150{
151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
152 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
153
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000154 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 if (_rxVadObserverPtr)
156 {
157 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
158 }
159
160 return 0;
161}
162
163int
164Channel::SendPacket(int channel, const void *data, int len)
165{
166 channel = VoEChannelId(channel);
167 assert(channel == _channelId);
168
169 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
170 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
171
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000172 CriticalSectionScoped cs(&_callbackCritSect);
173
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 if (_transportPtr == NULL)
175 {
176 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
177 "Channel::SendPacket() failed to send RTP packet due to"
178 " invalid transport object");
179 return -1;
180 }
181
182 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
183 // API
184 if (_insertExtraRTPPacket)
185 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000186 uint8_t* rtpHdr = (uint8_t*)data;
187 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 if (_extraMarkerBit)
189 {
190 M_PT = 0x80; // set the M-bit
191 }
192 M_PT += _extraPayloadType; // set the payload type
193 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
194 _insertExtraRTPPacket = false; // insert one packet only
195 }
196
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000197 uint8_t* bufferToSendPtr = (uint8_t*)data;
198 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
200 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000201 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 {
203 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
204 VoEId(_instanceId,_channelId),
205 "Channel::SendPacket() RTP dump to output file failed");
206 }
207
208 // SRTP or External encryption
209 if (_encrypting)
210 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 if (_encryptionPtr)
212 {
213 if (!_encryptionRTPBufferPtr)
214 {
215 // Allocate memory for encryption buffer one time only
216 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000217 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000218 memset(_encryptionRTPBufferPtr, 0,
219 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 }
221
222 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000223 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 _encryptionPtr->encrypt(_channelId,
225 bufferToSendPtr,
226 _encryptionRTPBufferPtr,
227 bufferLength,
228 (int*)&encryptedBufferLength);
229 if (encryptedBufferLength <= 0)
230 {
231 _engineStatisticsPtr->SetLastError(
232 VE_ENCRYPTION_FAILED,
233 kTraceError, "Channel::SendPacket() encryption failed");
234 return -1;
235 }
236
237 // Replace default data buffer with encrypted buffer
238 bufferToSendPtr = _encryptionRTPBufferPtr;
239 bufferLength = encryptedBufferLength;
240 }
241 }
242
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000243 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
244 bufferLength);
245 if (n < 0) {
246 std::string transport_name =
247 _externalTransport ? "external transport" : "WebRtc sockets";
248 WEBRTC_TRACE(kTraceError, kTraceVoice,
249 VoEId(_instanceId,_channelId),
250 "Channel::SendPacket() RTP transmission using %s failed",
251 transport_name.c_str());
252 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000254 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000255}
256
257int
258Channel::SendRTCPPacket(int channel, const void *data, int len)
259{
260 channel = VoEChannelId(channel);
261 assert(channel == _channelId);
262
263 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
264 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
265
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000266 CriticalSectionScoped cs(&_callbackCritSect);
267 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000269 WEBRTC_TRACE(kTraceError, kTraceVoice,
270 VoEId(_instanceId,_channelId),
271 "Channel::SendRTCPPacket() failed to send RTCP packet"
272 " due to invalid transport object");
273 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000276 uint8_t* bufferToSendPtr = (uint8_t*)data;
277 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278
279 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000280 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 {
282 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
283 VoEId(_instanceId,_channelId),
284 "Channel::SendPacket() RTCP dump to output file failed");
285 }
286
287 // SRTP or External encryption
288 if (_encrypting)
289 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 if (_encryptionPtr)
291 {
292 if (!_encryptionRTCPBufferPtr)
293 {
294 // Allocate memory for encryption buffer one time only
295 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000296 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 }
298
299 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000300 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000301 _encryptionPtr->encrypt_rtcp(_channelId,
302 bufferToSendPtr,
303 _encryptionRTCPBufferPtr,
304 bufferLength,
305 (int*)&encryptedBufferLength);
306 if (encryptedBufferLength <= 0)
307 {
308 _engineStatisticsPtr->SetLastError(
309 VE_ENCRYPTION_FAILED, kTraceError,
310 "Channel::SendRTCPPacket() encryption failed");
311 return -1;
312 }
313
314 // Replace default data buffer with encrypted buffer
315 bufferToSendPtr = _encryptionRTCPBufferPtr;
316 bufferLength = encryptedBufferLength;
317 }
318 }
319
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000320 int n = _transportPtr->SendRTCPPacket(channel,
321 bufferToSendPtr,
322 bufferLength);
323 if (n < 0) {
324 std::string transport_name =
325 _externalTransport ? "external transport" : "WebRtc sockets";
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using %s failed",
329 transport_name.c_str());
330 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000332 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333}
334
335void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000336Channel::OnPlayTelephoneEvent(int32_t id,
337 uint8_t event,
338 uint16_t lengthMs,
339 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000340{
341 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
342 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000343 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 if (!_playOutbandDtmfEvent || (event > 15))
346 {
347 // Ignore callback since feedback is disabled or event is not a
348 // Dtmf tone event.
349 return;
350 }
351
352 assert(_outputMixerPtr != NULL);
353
354 // Start playing out the Dtmf tone (if playout is enabled).
355 // Reduce length of tone with 80ms to the reduce risk of echo.
356 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
357}
358
359void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000360Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000361{
362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
363 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000364 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000366 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 assert(channel == _channelId);
368
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000369 // Update ssrc so that NTP for AV sync can be updated.
370 _rtpRtcpModule->SetRemoteSSRC(ssrc);
371
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 if (_rtpObserver)
373 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000374 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 if (_rtpObserverPtr)
377 {
378 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000379 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 }
381 }
382}
383
pbos@webrtc.org92135212013-05-14 08:31:39 +0000384void Channel::OnIncomingCSRCChanged(int32_t id,
385 uint32_t CSRC,
386 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000387{
388 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
389 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
390 id, CSRC, added);
391
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000392 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 assert(channel == _channelId);
394
395 if (_rtpObserver)
396 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000397 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
399 if (_rtpObserverPtr)
400 {
401 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
402 }
403 }
404}
405
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000406void Channel::ResetStatistics(uint32_t ssrc) {
407 StreamStatistician* statistician =
408 rtp_receive_statistics_->GetStatistician(ssrc);
409 if (statistician) {
410 statistician->ResetStatistics();
411 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000412 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000413}
414
niklase@google.com470e71d2011-07-07 08:21:25 +0000415void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000416Channel::OnApplicationDataReceived(int32_t id,
417 uint8_t subType,
418 uint32_t name,
419 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000420 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000421{
422 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
423 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
424 " name=%u, length=%u)",
425 id, subType, name, length);
426
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000427 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 assert(channel == _channelId);
429
430 if (_rtcpObserver)
431 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000432 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
434 if (_rtcpObserverPtr)
435 {
436 _rtcpObserverPtr->OnApplicationDataReceived(channel,
437 subType,
438 name,
439 data,
440 length);
441 }
442 }
443}
444
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000445int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000446Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000447 int32_t id,
448 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000449 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000450 int frequency,
451 uint8_t channels,
452 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000453{
454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
455 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
456 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
457 id, payloadType, payloadName, frequency, channels, rate);
458
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000459 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000460
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000461 CodecInst receiveCodec = {0};
462 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
464 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 receiveCodec.plfreq = frequency;
466 receiveCodec.channels = channels;
467 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000468 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000469
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000470 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 receiveCodec.pacsize = dummyCodec.pacsize;
472
473 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000474 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 {
476 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000477 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 "Channel::OnInitializeDecoder() invalid codec ("
479 "pt=%d, name=%s) received - 1", payloadType, payloadName);
480 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
481 return -1;
482 }
483
484 return 0;
485}
486
487void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000488Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000489{
490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
491 "Channel::OnPacketTimeout(id=%d)", id);
492
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000493 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 if (_voiceEngineObserverPtr)
495 {
496 if (_receiving || _externalTransport)
497 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000498 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 assert(channel == _channelId);
500 // Ensure that next OnReceivedPacket() callback will trigger
501 // a VE_PACKET_RECEIPT_RESTARTED callback.
502 _rtpPacketTimedOut = true;
503 // Deliver callback to the observer
504 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
505 VoEId(_instanceId,_channelId),
506 "Channel::OnPacketTimeout() => "
507 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
508 _voiceEngineObserverPtr->CallbackOnError(channel,
509 VE_RECEIVE_PACKET_TIMEOUT);
510 }
511 }
512}
513
514void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000515Channel::OnReceivedPacket(int32_t id,
516 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000517{
518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
519 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
520 id, packetType);
521
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000522 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000523
524 // Notify only for the case when we have restarted an RTP session.
525 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
526 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000527 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 if (_voiceEngineObserverPtr)
529 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000530 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 assert(channel == _channelId);
532 // Reset timeout mechanism
533 _rtpPacketTimedOut = false;
534 // Deliver callback to the observer
535 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
536 VoEId(_instanceId,_channelId),
537 "Channel::OnPacketTimeout() =>"
538 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
539 _voiceEngineObserverPtr->CallbackOnError(
540 channel,
541 VE_PACKET_RECEIPT_RESTARTED);
542 }
543 }
544}
545
546void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000547Channel::OnPeriodicDeadOrAlive(int32_t id,
548 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000549{
550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
551 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
552
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000553 {
554 CriticalSectionScoped cs(&_callbackCritSect);
555 if (!_connectionObserver)
556 return;
557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000559 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 assert(channel == _channelId);
561
562 // Use Alive as default to limit risk of false Dead detections
563 bool isAlive(true);
564
565 // Always mark the connection as Dead when the module reports kRtpDead
566 if (kRtpDead == alive)
567 {
568 isAlive = false;
569 }
570
571 // It is possible that the connection is alive even if no RTP packet has
572 // been received for a long time since the other side might use VAD/DTX
573 // and a low SID-packet update rate.
574 if ((kRtpNoRtp == alive) && _playing)
575 {
576 // Detect Alive for all NetEQ states except for the case when we are
577 // in PLC_CNG state.
578 // PLC_CNG <=> background noise only due to long expand or error.
579 // Note that, the case where the other side stops sending during CNG
580 // state will be detected as Alive. Dead is is not set until after
581 // missing RTCP packets for at least twelve seconds (handled
582 // internally by the RTP/RTCP module).
583 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
584 }
585
586 UpdateDeadOrAliveCounters(isAlive);
587
588 // Send callback to the registered observer
589 if (_connectionObserver)
590 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000591 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 if (_connectionObserverPtr)
593 {
594 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
595 }
596 }
597}
598
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000599int32_t
600Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000601 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 const WebRtcRTPHeader* rtpHeader)
603{
604 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
605 "Channel::OnReceivedPayloadData(payloadSize=%d,"
606 " payloadType=%u, audioChannel=%u)",
607 payloadSize,
608 rtpHeader->header.payloadType,
609 rtpHeader->type.Audio.channel);
610
roosa@google.com0870f022012-12-12 21:31:41 +0000611 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
612
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 if (!_playing)
614 {
615 // Avoid inserting into NetEQ when we are not playing. Count the
616 // packet as discarded.
617 WEBRTC_TRACE(kTraceStream, kTraceVoice,
618 VoEId(_instanceId, _channelId),
619 "received packet is discarded since playing is not"
620 " activated");
621 _numberOfDiscardedPackets++;
622 return 0;
623 }
624
625 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000626 if (audio_coding_->IncomingPacket(payloadData,
627 payloadSize,
628 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 {
630 _engineStatisticsPtr->SetLastError(
631 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
632 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
633 return -1;
634 }
635
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000636 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 UpdatePacketDelay(rtpHeader->header.timestamp,
638 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000639
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000640 uint16_t round_trip_time = 0;
641 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
642 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000643
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000644 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000645 round_trip_time);
646 if (!nack_list.empty()) {
647 // Can't use nack_list.data() since it's not supported by all
648 // compilers.
649 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000650 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 return 0;
652}
653
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000654bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
655 int rtp_packet_length) {
656 RTPHeader header;
657 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
658 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
659 "IncomingPacket invalid RTP header");
660 return false;
661 }
662 header.payload_type_frequency =
663 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
664 if (header.payload_type_frequency < 0)
665 return false;
666 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
667}
668
pbos@webrtc.org92135212013-05-14 08:31:39 +0000669int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670{
671 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
672 "Channel::GetAudioFrame(id=%d)", id);
673
674 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000675 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
676 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 {
678 WEBRTC_TRACE(kTraceError, kTraceVoice,
679 VoEId(_instanceId,_channelId),
680 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000681 // In all likelihood, the audio in this frame is garbage. We return an
682 // error so that the audio mixer module doesn't add it to the mix. As
683 // a result, it won't be played out and the actions skipped here are
684 // irrelevant.
685 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 }
687
688 if (_RxVadDetection)
689 {
690 UpdateRxVadDetection(audioFrame);
691 }
692
693 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000694 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000697
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000698 if (_rxApmIsEnabled) {
699 int err = rx_audioproc_->ProcessStream(&audioFrame);
700 if (err) {
701 LOG(LS_ERROR) << "ProcessStream() error: " << err;
702 assert(false);
703 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 }
705
wu@webrtc.org63420662013-10-17 18:28:55 +0000706 float output_gain = 1.0f;
707 float left_pan = 1.0f;
708 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000710 CriticalSectionScoped cs(&volume_settings_critsect_);
711 output_gain = _outputGain;
712 left_pan = _panLeft;
713 right_pan= _panRight;
714 }
715
716 // Output volume scaling
717 if (output_gain < 0.99f || output_gain > 1.01f)
718 {
719 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
721
722 // Scale left and/or right channel(s) if stereo and master balance is
723 // active
724
wu@webrtc.org63420662013-10-17 18:28:55 +0000725 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000727 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 {
729 // Emulate stereo mode since panning is active.
730 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000731 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 }
733 // For true stereo mode (when we are receiving a stereo signal), no
734 // action is needed.
735
736 // Do the panning operation (the audio frame contains stereo at this
737 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000738 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000739 }
740
741 // Mix decoded PCM output with file if file mixing is enabled
742 if (_outputFilePlaying)
743 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000744 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 }
746
747 // Place channel in on-hold state (~muted) if on-hold is activated
748 if (_outputIsOnHold)
749 {
750 AudioFrameOperations::Mute(audioFrame);
751 }
752
753 // External media
754 if (_outputExternalMedia)
755 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000756 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000757 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000758 if (_outputExternalMediaCallbackPtr)
759 {
760 _outputExternalMediaCallbackPtr->Process(
761 _channelId,
762 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000763 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000764 audioFrame.samples_per_channel_,
765 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 isStereo);
767 }
768 }
769
770 // Record playout if enabled
771 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000772 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000773
774 if (_outputFileRecording && _outputFileRecorderPtr)
775 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000776 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000777 }
778 }
779
780 // Measure audio level (0-9)
781 _outputAudioLevel.ComputeLevel(audioFrame);
782
783 return 0;
784}
785
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000786int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000787Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000788{
789 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
790 "Channel::NeededFrequency(id=%d)", id);
791
792 int highestNeeded = 0;
793
794 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000795 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000796
797 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000798 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000800 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000801 }
802 else
803 {
804 highestNeeded = receiveFrequency;
805 }
806
807 // Special case, if we're playing a file on the playout side
808 // we take that frequency into consideration as well
809 // This is not needed on sending side, since the codec will
810 // limit the spectrum anyway.
811 if (_outputFilePlaying)
812 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000813 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000814 if (_outputFilePlayerPtr && _outputFilePlaying)
815 {
816 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
817 {
818 highestNeeded=_outputFilePlayerPtr->Frequency();
819 }
820 }
821 }
822
823 return(highestNeeded);
824}
825
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000826int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000827Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000828 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000829 uint32_t instanceId,
830 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000831{
832 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
833 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
834 channelId, instanceId);
835
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000836 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 if (channel == NULL)
838 {
839 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
840 VoEId(instanceId,channelId),
841 "Channel::CreateChannel() unable to allocate memory for"
842 " channel");
843 return -1;
844 }
845 return 0;
846}
847
848void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000849Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000850{
851 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
852 "Channel::PlayNotification(id=%d, durationMs=%d)",
853 id, durationMs);
854
855 // Not implement yet
856}
857
858void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000859Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860{
861 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
862 "Channel::RecordNotification(id=%d, durationMs=%d)",
863 id, durationMs);
864
865 // Not implement yet
866}
867
868void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000869Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000870{
871 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
872 "Channel::PlayFileEnded(id=%d)", id);
873
874 if (id == _inputFilePlayerId)
875 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000876 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000877
878 _inputFilePlaying = false;
879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
880 VoEId(_instanceId,_channelId),
881 "Channel::PlayFileEnded() => input file player module is"
882 " shutdown");
883 }
884 else if (id == _outputFilePlayerId)
885 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000886 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000887
888 _outputFilePlaying = false;
889 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
890 VoEId(_instanceId,_channelId),
891 "Channel::PlayFileEnded() => output file player module is"
892 " shutdown");
893 }
894}
895
896void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000897Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000898{
899 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
900 "Channel::RecordFileEnded(id=%d)", id);
901
902 assert(id == _outputFileRecorderId);
903
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000904 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000905
906 _outputFileRecording = false;
907 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
908 VoEId(_instanceId,_channelId),
909 "Channel::RecordFileEnded() => output file recorder module is"
910 " shutdown");
911}
912
pbos@webrtc.org92135212013-05-14 08:31:39 +0000913Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000914 uint32_t instanceId,
915 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
917 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000918 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000920 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000921 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000922 rtp_payload_registry_(
923 new RTPPayloadRegistry(channelId,
924 RTPPayloadStrategy::CreateStrategy(true))),
925 rtp_receive_statistics_(ReceiveStatistics::Create(
926 Clock::GetRealTimeClock())),
927 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
928 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
929 this, this, rtp_payload_registry_.get())),
930 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000931 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000932 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 _rtpDumpIn(*RtpDump::CreateRtpDump()),
934 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000937 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000938 _inputFilePlayerPtr(NULL),
939 _outputFilePlayerPtr(NULL),
940 _outputFileRecorderPtr(NULL),
941 // Avoid conflict with other channels by adding 1024 - 1026,
942 // won't use as much as 1024 channels.
943 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
944 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
945 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
946 _inputFilePlaying(false),
947 _outputFilePlaying(false),
948 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000949 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
950 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000951 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000952 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 _inputExternalMediaCallbackPtr(NULL),
954 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000955 _encryptionRTPBufferPtr(NULL),
956 _decryptionRTPBufferPtr(NULL),
957 _encryptionRTCPBufferPtr(NULL),
958 _decryptionRTCPBufferPtr(NULL),
959 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
960 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000961 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000962 playout_timestamp_rtp_(0),
963 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000964 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000965 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000966 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000967 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000968 _outputMixerPtr(NULL),
969 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000970 _moduleProcessThreadPtr(NULL),
971 _audioDeviceModulePtr(NULL),
972 _voiceEngineObserverPtr(NULL),
973 _callbackCritSectPtr(NULL),
974 _transportPtr(NULL),
975 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000976 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000977 _rxVadObserverPtr(NULL),
978 _oldVadDecision(-1),
979 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000980 _rtpObserverPtr(NULL),
981 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000982 _outputIsOnHold(false),
983 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000984 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000985 _inputIsOnHold(false),
986 _playing(false),
987 _sending(false),
988 _receiving(false),
989 _mixFileWithMicrophone(false),
990 _rtpObserver(false),
991 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 _mute(false),
993 _panLeft(1.0f),
994 _panRight(1.0f),
995 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000996 _encrypting(false),
997 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 _playOutbandDtmfEvent(false),
999 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 _extraPayloadType(0),
1001 _insertExtraRTPPacket(false),
1002 _extraMarkerBit(false),
1003 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +00001004 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +00001006 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 _rtpPacketTimedOut(false),
1008 _rtpPacketTimeOutIsEnabled(false),
1009 _rtpTimeOutSeconds(0),
1010 _connectionObserver(false),
1011 _connectionObserverPtr(NULL),
1012 _countAliveDetections(0),
1013 _countDeadDetections(0),
1014 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001015 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00001016 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 _previousTimestamp(0),
1018 _recPacketDelayMs(20),
1019 _RxVadDetection(false),
1020 _rxApmIsEnabled(false),
1021 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001022 _rxNsIsEnabled(false),
1023 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001024{
1025 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1026 "Channel::Channel() - ctor");
1027 _inbandDtmfQueue.ResetDtmf();
1028 _inbandDtmfGenerator.Init();
1029 _outputAudioLevel.Clear();
1030
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001031 RtpRtcp::Configuration configuration;
1032 configuration.id = VoEModuleId(instanceId, channelId);
1033 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001034 configuration.outgoing_transport = this;
1035 configuration.rtcp_feedback = this;
1036 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001037 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001038
1039 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001040
1041 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
1042 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
1043 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001044}
1045
1046Channel::~Channel()
1047{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001048 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1050 "Channel::~Channel() - dtor");
1051
1052 if (_outputExternalMedia)
1053 {
1054 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1055 }
1056 if (_inputExternalMedia)
1057 {
1058 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1059 }
1060 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 StopPlayout();
1062
1063 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001064 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 if (_inputFilePlayerPtr)
1066 {
1067 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1068 _inputFilePlayerPtr->StopPlayingFile();
1069 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1070 _inputFilePlayerPtr = NULL;
1071 }
1072 if (_outputFilePlayerPtr)
1073 {
1074 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1075 _outputFilePlayerPtr->StopPlayingFile();
1076 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1077 _outputFilePlayerPtr = NULL;
1078 }
1079 if (_outputFileRecorderPtr)
1080 {
1081 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1082 _outputFileRecorderPtr->StopRecording();
1083 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1084 _outputFileRecorderPtr = NULL;
1085 }
1086 }
1087
1088 // The order to safely shutdown modules in a channel is:
1089 // 1. De-register callbacks in modules
1090 // 2. De-register modules in process thread
1091 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001092 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 {
1094 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1095 VoEId(_instanceId,_channelId),
1096 "~Channel() failed to de-register transport callback"
1097 " (Audio coding module)");
1098 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001099 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 {
1101 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1102 VoEId(_instanceId,_channelId),
1103 "~Channel() failed to de-register VAD callback"
1104 " (Audio coding module)");
1105 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001107 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 {
1109 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1110 VoEId(_instanceId,_channelId),
1111 "~Channel() failed to deregister RTP/RTCP module");
1112 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001113 // End of modules shutdown
1114
1115 // Delete other objects
1116 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1117 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1118 delete [] _encryptionRTPBufferPtr;
1119 delete [] _decryptionRTPBufferPtr;
1120 delete [] _encryptionRTCPBufferPtr;
1121 delete [] _decryptionRTCPBufferPtr;
1122 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001124 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001125}
1126
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001127int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001128Channel::Init()
1129{
1130 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1131 "Channel::Init()");
1132
1133 // --- Initial sanity
1134
1135 if ((_engineStatisticsPtr == NULL) ||
1136 (_moduleProcessThreadPtr == NULL))
1137 {
1138 WEBRTC_TRACE(kTraceError, kTraceVoice,
1139 VoEId(_instanceId,_channelId),
1140 "Channel::Init() must call SetEngineInformation() first");
1141 return -1;
1142 }
1143
1144 // --- Add modules to process thread (for periodic schedulation)
1145
1146 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001147 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 if (processThreadFail)
1150 {
1151 _engineStatisticsPtr->SetLastError(
1152 VE_CANNOT_INIT_CHANNEL, kTraceError,
1153 "Channel::Init() modules not registered");
1154 return -1;
1155 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001156 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001157
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001158 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001159#ifdef WEBRTC_CODEC_AVT
1160 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001161 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001162#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001163 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001164 {
1165 _engineStatisticsPtr->SetLastError(
1166 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1167 "Channel::Init() unable to initialize the ACM - 1");
1168 return -1;
1169 }
1170
1171 // --- RTP/RTCP module initialization
1172
1173 // Ensure that RTCP is enabled by default for the created channel.
1174 // Note that, the module will keep generating RTCP until it is explicitly
1175 // disabled by the user.
1176 // After StopListen (when no sockets exists), RTCP packets will no longer
1177 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001178 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1179 // RTCP is enabled by default.
1180 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 {
1182 _engineStatisticsPtr->SetLastError(
1183 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1184 "Channel::Init() RTP/RTCP module not initialized");
1185 return -1;
1186 }
1187
1188 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001190 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1191 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001192
1193 if (fail)
1194 {
1195 _engineStatisticsPtr->SetLastError(
1196 VE_CANNOT_INIT_CHANNEL, kTraceError,
1197 "Channel::Init() callbacks not registered");
1198 return -1;
1199 }
1200
1201 // --- Register all supported codecs to the receiving side of the
1202 // RTP/RTCP module
1203
1204 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001205 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001206
1207 for (int idx = 0; idx < nSupportedCodecs; idx++)
1208 {
1209 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001210 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001211 (rtp_receiver_->RegisterReceivePayload(
1212 codec.plname,
1213 codec.pltype,
1214 codec.plfreq,
1215 codec.channels,
1216 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 {
1218 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1219 VoEId(_instanceId,_channelId),
1220 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1221 "to RTP/RTCP receiver",
1222 codec.plname, codec.pltype, codec.plfreq,
1223 codec.channels, codec.rate);
1224 }
1225 else
1226 {
1227 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1228 VoEId(_instanceId,_channelId),
1229 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1230 "the RTP/RTCP receiver",
1231 codec.plname, codec.pltype, codec.plfreq,
1232 codec.channels, codec.rate);
1233 }
1234
1235 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001236 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001237 {
1238 SetSendCodec(codec);
1239 }
1240
1241 // Register default PT for outband 'telephone-event'
1242 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1243 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001244 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001245 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 {
1247 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1248 VoEId(_instanceId,_channelId),
1249 "Channel::Init() failed to register outband "
1250 "'telephone-event' (%d/%d) correctly",
1251 codec.pltype, codec.plfreq);
1252 }
1253 }
1254
1255 if (!STR_CASE_CMP(codec.plname, "CN"))
1256 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001257 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1258 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001259 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 {
1261 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1262 VoEId(_instanceId,_channelId),
1263 "Channel::Init() failed to register CN (%d/%d) "
1264 "correctly - 1",
1265 codec.pltype, codec.plfreq);
1266 }
1267 }
1268#ifdef WEBRTC_CODEC_RED
1269 // Register RED to the receiving side of the ACM.
1270 // We will not receive an OnInitializeDecoder() callback for RED.
1271 if (!STR_CASE_CMP(codec.plname, "RED"))
1272 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001273 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 {
1275 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1276 VoEId(_instanceId,_channelId),
1277 "Channel::Init() failed to register RED (%d/%d) "
1278 "correctly",
1279 codec.pltype, codec.plfreq);
1280 }
1281 }
1282#endif
1283 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001284
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001285 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1286 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1287 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001288 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001289 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1290 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1291 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001292 }
1293
1294 return 0;
1295}
1296
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001297int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001298Channel::SetEngineInformation(Statistics& engineStatistics,
1299 OutputMixer& outputMixer,
1300 voe::TransmitMixer& transmitMixer,
1301 ProcessThread& moduleProcessThread,
1302 AudioDeviceModule& audioDeviceModule,
1303 VoiceEngineObserver* voiceEngineObserver,
1304 CriticalSectionWrapper* callbackCritSect)
1305{
1306 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1307 "Channel::SetEngineInformation()");
1308 _engineStatisticsPtr = &engineStatistics;
1309 _outputMixerPtr = &outputMixer;
1310 _transmitMixerPtr = &transmitMixer,
1311 _moduleProcessThreadPtr = &moduleProcessThread;
1312 _audioDeviceModulePtr = &audioDeviceModule;
1313 _voiceEngineObserverPtr = voiceEngineObserver;
1314 _callbackCritSectPtr = callbackCritSect;
1315 return 0;
1316}
1317
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001318int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001319Channel::UpdateLocalTimeStamp()
1320{
1321
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001322 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001323 return 0;
1324}
1325
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001326int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001327Channel::StartPlayout()
1328{
1329 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1330 "Channel::StartPlayout()");
1331 if (_playing)
1332 {
1333 return 0;
1334 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001335
1336 if (!_externalMixing) {
1337 // Add participant as candidates for mixing.
1338 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1339 {
1340 _engineStatisticsPtr->SetLastError(
1341 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1342 "StartPlayout() failed to add participant to mixer");
1343 return -1;
1344 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001345 }
1346
1347 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001348
1349 if (RegisterFilePlayingToMixer() != 0)
1350 return -1;
1351
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 return 0;
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::StopPlayout()
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::StopPlayout()");
1360 if (!_playing)
1361 {
1362 return 0;
1363 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001364
1365 if (!_externalMixing) {
1366 // Remove participant as candidates for mixing
1367 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1368 {
1369 _engineStatisticsPtr->SetLastError(
1370 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1371 "StopPlayout() failed to remove participant from mixer");
1372 return -1;
1373 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 }
1375
1376 _playing = false;
1377 _outputAudioLevel.Clear();
1378
1379 return 0;
1380}
1381
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001382int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001383Channel::StartSend()
1384{
1385 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1386 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001387 // Resume the previous sequence number which was reset by StopSend().
1388 // This needs to be done before |_sending| is set to true.
1389 if (send_sequence_number_)
1390 SetInitSequenceNumber(send_sequence_number_);
1391
niklase@google.com470e71d2011-07-07 08:21:25 +00001392 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001393 // A lock is needed because |_sending| can be accessed or modified by
1394 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001395 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001396
1397 if (_sending)
1398 {
1399 return 0;
1400 }
1401 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001402 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001403
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001404 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001405 {
1406 _engineStatisticsPtr->SetLastError(
1407 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1408 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001409 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001410 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 return -1;
1412 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001413
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 return 0;
1415}
1416
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001417int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001418Channel::StopSend()
1419{
1420 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1421 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001422 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001423 // A lock is needed because |_sending| can be accessed or modified by
1424 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001425 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001426
1427 if (!_sending)
1428 {
1429 return 0;
1430 }
1431 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001432 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001433
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001434 // Store the sequence number to be able to pick up the same sequence for
1435 // the next StartSend(). This is needed for restarting device, otherwise
1436 // it might cause libSRTP to complain about packets being replayed.
1437 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1438 // CL is landed. See issue
1439 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1440 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1441
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 // Reset sending SSRC and sequence number and triggers direct transmission
1443 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001444 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1445 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 {
1447 _engineStatisticsPtr->SetLastError(
1448 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1449 "StartSend() RTP/RTCP failed to stop sending");
1450 }
1451
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 return 0;
1453}
1454
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001455int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001456Channel::StartReceiving()
1457{
1458 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1459 "Channel::StartReceiving()");
1460 if (_receiving)
1461 {
1462 return 0;
1463 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 _receiving = true;
1465 _numberOfDiscardedPackets = 0;
1466 return 0;
1467}
1468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001469int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001470Channel::StopReceiving()
1471{
1472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1473 "Channel::StopReceiving()");
1474 if (!_receiving)
1475 {
1476 return 0;
1477 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001478
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001479 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001480 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 RegisterReceiveCodecsToRTPModule();
1482 _receiving = false;
1483 return 0;
1484}
1485
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001486int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001487Channel::SetNetEQPlayoutMode(NetEqModes mode)
1488{
1489 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1490 "Channel::SetNetEQPlayoutMode()");
1491 AudioPlayoutMode playoutMode(voice);
1492 switch (mode)
1493 {
1494 case kNetEqDefault:
1495 playoutMode = voice;
1496 break;
1497 case kNetEqStreaming:
1498 playoutMode = streaming;
1499 break;
1500 case kNetEqFax:
1501 playoutMode = fax;
1502 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001503 case kNetEqOff:
1504 playoutMode = off;
1505 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001507 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001508 {
1509 _engineStatisticsPtr->SetLastError(
1510 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1511 "SetNetEQPlayoutMode() failed to set playout mode");
1512 return -1;
1513 }
1514 return 0;
1515}
1516
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001517int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001518Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1519{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001520 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001521 switch (playoutMode)
1522 {
1523 case voice:
1524 mode = kNetEqDefault;
1525 break;
1526 case streaming:
1527 mode = kNetEqStreaming;
1528 break;
1529 case fax:
1530 mode = kNetEqFax;
1531 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001532 case off:
1533 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 }
1535 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1536 VoEId(_instanceId,_channelId),
1537 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1538 return 0;
1539}
1540
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001541int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001542Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1543{
1544 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1545 "Channel::SetOnHoldStatus()");
1546 if (mode == kHoldSendAndPlay)
1547 {
1548 _outputIsOnHold = enable;
1549 _inputIsOnHold = enable;
1550 }
1551 else if (mode == kHoldPlayOnly)
1552 {
1553 _outputIsOnHold = enable;
1554 }
1555 if (mode == kHoldSendOnly)
1556 {
1557 _inputIsOnHold = enable;
1558 }
1559 return 0;
1560}
1561
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001562int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001563Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1564{
1565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1566 "Channel::GetOnHoldStatus()");
1567 enabled = (_outputIsOnHold || _inputIsOnHold);
1568 if (_outputIsOnHold && _inputIsOnHold)
1569 {
1570 mode = kHoldSendAndPlay;
1571 }
1572 else if (_outputIsOnHold && !_inputIsOnHold)
1573 {
1574 mode = kHoldPlayOnly;
1575 }
1576 else if (!_outputIsOnHold && _inputIsOnHold)
1577 {
1578 mode = kHoldSendOnly;
1579 }
1580 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1581 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1582 enabled, mode);
1583 return 0;
1584}
1585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001586int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001587Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1588{
1589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001591 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001592
1593 if (_voiceEngineObserverPtr)
1594 {
1595 _engineStatisticsPtr->SetLastError(
1596 VE_INVALID_OPERATION, kTraceError,
1597 "RegisterVoiceEngineObserver() observer already enabled");
1598 return -1;
1599 }
1600 _voiceEngineObserverPtr = &observer;
1601 return 0;
1602}
1603
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001604int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001605Channel::DeRegisterVoiceEngineObserver()
1606{
1607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1608 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001609 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001610
1611 if (!_voiceEngineObserverPtr)
1612 {
1613 _engineStatisticsPtr->SetLastError(
1614 VE_INVALID_OPERATION, kTraceWarning,
1615 "DeRegisterVoiceEngineObserver() observer already disabled");
1616 return 0;
1617 }
1618 _voiceEngineObserverPtr = NULL;
1619 return 0;
1620}
1621
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001622int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001623Channel::GetSendCodec(CodecInst& codec)
1624{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001625 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001626}
1627
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001628int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001629Channel::GetRecCodec(CodecInst& codec)
1630{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001631 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001632}
1633
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001634int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001635Channel::SetSendCodec(const CodecInst& codec)
1636{
1637 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1638 "Channel::SetSendCodec()");
1639
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001640 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001641 {
1642 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1643 "SetSendCodec() failed to register codec to ACM");
1644 return -1;
1645 }
1646
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001647 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001648 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001649 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1650 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001651 {
1652 WEBRTC_TRACE(
1653 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1654 "SetSendCodec() failed to register codec to"
1655 " RTP/RTCP module");
1656 return -1;
1657 }
1658 }
1659
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001660 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001661 {
1662 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1663 "SetSendCodec() failed to set audio packet size");
1664 return -1;
1665 }
1666
1667 return 0;
1668}
1669
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001670int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001671Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1672{
1673 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1674 "Channel::SetVADStatus(mode=%d)", mode);
1675 // To disable VAD, DTX must be disabled too
1676 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001677 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001678 {
1679 _engineStatisticsPtr->SetLastError(
1680 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1681 "SetVADStatus() failed to set VAD");
1682 return -1;
1683 }
1684 return 0;
1685}
1686
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001687int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001688Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1689{
1690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1691 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001692 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001693 {
1694 _engineStatisticsPtr->SetLastError(
1695 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1696 "GetVADStatus() failed to get VAD status");
1697 return -1;
1698 }
1699 disabledDTX = !disabledDTX;
1700 return 0;
1701}
1702
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001703int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001704Channel::SetRecPayloadType(const CodecInst& codec)
1705{
1706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1707 "Channel::SetRecPayloadType()");
1708
1709 if (_playing)
1710 {
1711 _engineStatisticsPtr->SetLastError(
1712 VE_ALREADY_PLAYING, kTraceError,
1713 "SetRecPayloadType() unable to set PT while playing");
1714 return -1;
1715 }
1716 if (_receiving)
1717 {
1718 _engineStatisticsPtr->SetLastError(
1719 VE_ALREADY_LISTENING, kTraceError,
1720 "SetRecPayloadType() unable to set PT while listening");
1721 return -1;
1722 }
1723
1724 if (codec.pltype == -1)
1725 {
1726 // De-register the selected codec (RTP/RTCP module and ACM)
1727
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001728 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001729 CodecInst rxCodec = codec;
1730
1731 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001732 rtp_payload_registry_->ReceivePayloadType(
1733 rxCodec.plname,
1734 rxCodec.plfreq,
1735 rxCodec.channels,
1736 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1737 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001738 rxCodec.pltype = pltype;
1739
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001740 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001741 {
1742 _engineStatisticsPtr->SetLastError(
1743 VE_RTP_RTCP_MODULE_ERROR,
1744 kTraceError,
1745 "SetRecPayloadType() RTP/RTCP-module deregistration "
1746 "failed");
1747 return -1;
1748 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001749 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001750 {
1751 _engineStatisticsPtr->SetLastError(
1752 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1753 "SetRecPayloadType() ACM deregistration failed - 1");
1754 return -1;
1755 }
1756 return 0;
1757 }
1758
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001759 if (rtp_receiver_->RegisterReceivePayload(
1760 codec.plname,
1761 codec.pltype,
1762 codec.plfreq,
1763 codec.channels,
1764 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001765 {
1766 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001767 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1768 if (rtp_receiver_->RegisterReceivePayload(
1769 codec.plname,
1770 codec.pltype,
1771 codec.plfreq,
1772 codec.channels,
1773 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001774 {
1775 _engineStatisticsPtr->SetLastError(
1776 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1777 "SetRecPayloadType() RTP/RTCP-module registration failed");
1778 return -1;
1779 }
1780 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001781 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001782 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001783 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1784 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001785 {
1786 _engineStatisticsPtr->SetLastError(
1787 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1788 "SetRecPayloadType() ACM registration failed - 1");
1789 return -1;
1790 }
1791 }
1792 return 0;
1793}
1794
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001795int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001796Channel::GetRecPayloadType(CodecInst& codec)
1797{
1798 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1799 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001800 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001801 if (rtp_payload_registry_->ReceivePayloadType(
1802 codec.plname,
1803 codec.plfreq,
1804 codec.channels,
1805 (codec.rate < 0) ? 0 : codec.rate,
1806 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001807 {
1808 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001809 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001810 "GetRecPayloadType() failed to retrieve RX payload type");
1811 return -1;
1812 }
1813 codec.pltype = payloadType;
1814 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1815 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1816 return 0;
1817}
1818
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001819int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001820Channel::SetAMREncFormat(AmrMode mode)
1821{
1822 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1823 "Channel::SetAMREncFormat()");
1824
1825 // ACM doesn't support AMR
1826 return -1;
1827}
1828
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001829int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001830Channel::SetAMRDecFormat(AmrMode mode)
1831{
1832 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1833 "Channel::SetAMRDecFormat()");
1834
1835 // ACM doesn't support AMR
1836 return -1;
1837}
1838
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001839int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001840Channel::SetAMRWbEncFormat(AmrMode mode)
1841{
1842 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1843 "Channel::SetAMRWbEncFormat()");
1844
1845 // ACM doesn't support AMR
1846 return -1;
1847
1848}
1849
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001850int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001851Channel::SetAMRWbDecFormat(AmrMode mode)
1852{
1853 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1854 "Channel::SetAMRWbDecFormat()");
1855
1856 // ACM doesn't support AMR
1857 return -1;
1858}
1859
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001860int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001861Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1862{
1863 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1864 "Channel::SetSendCNPayloadType()");
1865
1866 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001867 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001868 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001869 if (frequency == kFreq32000Hz)
1870 samplingFreqHz = 32000;
1871 else if (frequency == kFreq16000Hz)
1872 samplingFreqHz = 16000;
1873
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001874 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001875 {
1876 _engineStatisticsPtr->SetLastError(
1877 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1878 "SetSendCNPayloadType() failed to retrieve default CN codec "
1879 "settings");
1880 return -1;
1881 }
1882
1883 // Modify the payload type (must be set to dynamic range)
1884 codec.pltype = type;
1885
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001886 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001887 {
1888 _engineStatisticsPtr->SetLastError(
1889 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1890 "SetSendCNPayloadType() failed to register CN to ACM");
1891 return -1;
1892 }
1893
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001894 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001895 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001896 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1897 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001898 {
1899 _engineStatisticsPtr->SetLastError(
1900 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1901 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1902 "module");
1903 return -1;
1904 }
1905 }
1906 return 0;
1907}
1908
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001909int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001910Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1911{
1912 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1913 "Channel::SetISACInitTargetRate()");
1914
1915 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001916 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_CODEC_ERROR, kTraceError,
1920 "SetISACInitTargetRate() failed to retrieve send codec");
1921 return -1;
1922 }
1923 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1924 {
1925 // This API is only valid if iSAC is setup to run in channel-adaptive
1926 // mode.
1927 // We do not validate the adaptive mode here. It is done later in the
1928 // ConfigISACBandwidthEstimator() API.
1929 _engineStatisticsPtr->SetLastError(
1930 VE_CODEC_ERROR, kTraceError,
1931 "SetISACInitTargetRate() send codec is not iSAC");
1932 return -1;
1933 }
1934
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001935 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001936 if (16000 == sendCodec.plfreq)
1937 {
1938 // Note that 0 is a valid and corresponds to "use default
1939 if ((rateBps != 0 &&
1940 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1941 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1942 {
1943 _engineStatisticsPtr->SetLastError(
1944 VE_INVALID_ARGUMENT, kTraceError,
1945 "SetISACInitTargetRate() invalid target rate - 1");
1946 return -1;
1947 }
1948 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001949 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001950 }
1951 else if (32000 == sendCodec.plfreq)
1952 {
1953 if ((rateBps != 0 &&
1954 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1955 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1956 {
1957 _engineStatisticsPtr->SetLastError(
1958 VE_INVALID_ARGUMENT, kTraceError,
1959 "SetISACInitTargetRate() invalid target rate - 2");
1960 return -1;
1961 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001962 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001963 }
1964
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001965 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001966 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1967 {
1968 _engineStatisticsPtr->SetLastError(
1969 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1970 "SetISACInitTargetRate() iSAC BWE config failed");
1971 return -1;
1972 }
1973
1974 return 0;
1975}
1976
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001977int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001978Channel::SetISACMaxRate(int rateBps)
1979{
1980 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1981 "Channel::SetISACMaxRate()");
1982
1983 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001984 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001985 {
1986 _engineStatisticsPtr->SetLastError(
1987 VE_CODEC_ERROR, kTraceError,
1988 "SetISACMaxRate() failed to retrieve send codec");
1989 return -1;
1990 }
1991 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1992 {
1993 // This API is only valid if iSAC is selected as sending codec.
1994 _engineStatisticsPtr->SetLastError(
1995 VE_CODEC_ERROR, kTraceError,
1996 "SetISACMaxRate() send codec is not iSAC");
1997 return -1;
1998 }
1999 if (16000 == sendCodec.plfreq)
2000 {
2001 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2002 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2003 {
2004 _engineStatisticsPtr->SetLastError(
2005 VE_INVALID_ARGUMENT, kTraceError,
2006 "SetISACMaxRate() invalid max rate - 1");
2007 return -1;
2008 }
2009 }
2010 else if (32000 == sendCodec.plfreq)
2011 {
2012 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2013 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2014 {
2015 _engineStatisticsPtr->SetLastError(
2016 VE_INVALID_ARGUMENT, kTraceError,
2017 "SetISACMaxRate() invalid max rate - 2");
2018 return -1;
2019 }
2020 }
2021 if (_sending)
2022 {
2023 _engineStatisticsPtr->SetLastError(
2024 VE_SENDING, kTraceError,
2025 "SetISACMaxRate() unable to set max rate while sending");
2026 return -1;
2027 }
2028
2029 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2030 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002031 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 {
2033 _engineStatisticsPtr->SetLastError(
2034 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2035 "SetISACMaxRate() failed to set max rate");
2036 return -1;
2037 }
2038
2039 return 0;
2040}
2041
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002042int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002043Channel::SetISACMaxPayloadSize(int sizeBytes)
2044{
2045 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2046 "Channel::SetISACMaxPayloadSize()");
2047 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002048 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002049 {
2050 _engineStatisticsPtr->SetLastError(
2051 VE_CODEC_ERROR, kTraceError,
2052 "SetISACMaxPayloadSize() failed to retrieve send codec");
2053 return -1;
2054 }
2055 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_CODEC_ERROR, kTraceError,
2059 "SetISACMaxPayloadSize() send codec is not iSAC");
2060 return -1;
2061 }
2062 if (16000 == sendCodec.plfreq)
2063 {
2064 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2065 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2066 {
2067 _engineStatisticsPtr->SetLastError(
2068 VE_INVALID_ARGUMENT, kTraceError,
2069 "SetISACMaxPayloadSize() invalid max payload - 1");
2070 return -1;
2071 }
2072 }
2073 else if (32000 == sendCodec.plfreq)
2074 {
2075 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2076 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2077 {
2078 _engineStatisticsPtr->SetLastError(
2079 VE_INVALID_ARGUMENT, kTraceError,
2080 "SetISACMaxPayloadSize() invalid max payload - 2");
2081 return -1;
2082 }
2083 }
2084 if (_sending)
2085 {
2086 _engineStatisticsPtr->SetLastError(
2087 VE_SENDING, kTraceError,
2088 "SetISACMaxPayloadSize() unable to set max rate while sending");
2089 return -1;
2090 }
2091
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002092 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002093 {
2094 _engineStatisticsPtr->SetLastError(
2095 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2096 "SetISACMaxPayloadSize() failed to set max payload size");
2097 return -1;
2098 }
2099 return 0;
2100}
2101
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002102int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002103{
2104 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2105 "Channel::RegisterExternalTransport()");
2106
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002107 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002108
niklase@google.com470e71d2011-07-07 08:21:25 +00002109 if (_externalTransport)
2110 {
2111 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2112 kTraceError,
2113 "RegisterExternalTransport() external transport already enabled");
2114 return -1;
2115 }
2116 _externalTransport = true;
2117 _transportPtr = &transport;
2118 return 0;
2119}
2120
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002121int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002122Channel::DeRegisterExternalTransport()
2123{
2124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2125 "Channel::DeRegisterExternalTransport()");
2126
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002127 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002128
niklase@google.com470e71d2011-07-07 08:21:25 +00002129 if (!_transportPtr)
2130 {
2131 _engineStatisticsPtr->SetLastError(
2132 VE_INVALID_OPERATION, kTraceWarning,
2133 "DeRegisterExternalTransport() external transport already "
2134 "disabled");
2135 return 0;
2136 }
2137 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002138 _transportPtr = NULL;
2139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2140 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002141 return 0;
2142}
2143
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002144int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002145 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2146 "Channel::ReceivedRTPPacket()");
2147
2148 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002149 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002150
2151 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002152 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2153 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002154 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2155 VoEId(_instanceId,_channelId),
2156 "Channel::SendPacket() RTP dump to input file failed");
2157 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002158 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002159 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002160 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2161 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2162 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002163 return -1;
2164 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002165 header.payload_type_frequency =
2166 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002167 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002168 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002169 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002170 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002171 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002172 rtp_payload_registry_->SetIncomingPayloadType(header);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002173 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002174}
2175
2176bool Channel::ReceivePacket(const uint8_t* packet,
2177 int packet_length,
2178 const RTPHeader& header,
2179 bool in_order) {
2180 if (rtp_payload_registry_->IsEncapsulated(header)) {
2181 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002182 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002183 const uint8_t* payload = packet + header.headerLength;
2184 int payload_length = packet_length - header.headerLength;
2185 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002186 PayloadUnion payload_specific;
2187 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002188 &payload_specific)) {
2189 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002190 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002191 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2192 payload_specific, in_order);
2193}
2194
2195bool Channel::HandleEncapsulation(const uint8_t* packet,
2196 int packet_length,
2197 const RTPHeader& header) {
2198 if (!rtp_payload_registry_->IsRtx(header))
2199 return false;
2200
2201 // Remove the RTX header and parse the original RTP header.
2202 if (packet_length < header.headerLength)
2203 return false;
2204 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2205 return false;
2206 if (restored_packet_in_use_) {
2207 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2208 "Multiple RTX headers detected, dropping packet");
2209 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002210 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002211 uint8_t* restored_packet_ptr = restored_packet_;
2212 if (!rtp_payload_registry_->RestoreOriginalPacket(
2213 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2214 header)) {
2215 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2216 "Incoming RTX packet: invalid RTP header");
2217 return false;
2218 }
2219 restored_packet_in_use_ = true;
2220 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2221 restored_packet_in_use_ = false;
2222 return ret;
2223}
2224
2225bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2226 StreamStatistician* statistician =
2227 rtp_receive_statistics_->GetStatistician(header.ssrc);
2228 if (!statistician)
2229 return false;
2230 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002231}
2232
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002233bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2234 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002235 // Retransmissions are handled separately if RTX is enabled.
2236 if (rtp_payload_registry_->RtxEnabled())
2237 return false;
2238 StreamStatistician* statistician =
2239 rtp_receive_statistics_->GetStatistician(header.ssrc);
2240 if (!statistician)
2241 return false;
2242 // Check if this is a retransmission.
2243 uint16_t min_rtt = 0;
2244 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002245 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002246 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002247}
2248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002249int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002250 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2251 "Channel::ReceivedRTCPPacket()");
2252 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002253 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002254
2255 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002256 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2257 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002258 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2259 VoEId(_instanceId,_channelId),
2260 "Channel::SendPacket() RTCP dump to input file failed");
2261 }
2262
2263 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002264 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2265 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002266 _engineStatisticsPtr->SetLastError(
2267 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2268 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2269 }
2270 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002271}
2272
niklase@google.com470e71d2011-07-07 08:21:25 +00002273int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002274 bool loop,
2275 FileFormats format,
2276 int startPosition,
2277 float volumeScaling,
2278 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002279 const CodecInst* codecInst)
2280{
2281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2282 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2283 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2284 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2285 startPosition, stopPosition);
2286
2287 if (_outputFilePlaying)
2288 {
2289 _engineStatisticsPtr->SetLastError(
2290 VE_ALREADY_PLAYING, kTraceError,
2291 "StartPlayingFileLocally() is already playing");
2292 return -1;
2293 }
2294
niklase@google.com470e71d2011-07-07 08:21:25 +00002295 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002296 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002297
2298 if (_outputFilePlayerPtr)
2299 {
2300 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2301 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2302 _outputFilePlayerPtr = NULL;
2303 }
2304
2305 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2306 _outputFilePlayerId, (const FileFormats)format);
2307
2308 if (_outputFilePlayerPtr == NULL)
2309 {
2310 _engineStatisticsPtr->SetLastError(
2311 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002312 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002313 return -1;
2314 }
2315
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002316 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002317
2318 if (_outputFilePlayerPtr->StartPlayingFile(
2319 fileName,
2320 loop,
2321 startPosition,
2322 volumeScaling,
2323 notificationTime,
2324 stopPosition,
2325 (const CodecInst*)codecInst) != 0)
2326 {
2327 _engineStatisticsPtr->SetLastError(
2328 VE_BAD_FILE, kTraceError,
2329 "StartPlayingFile() failed to start file playout");
2330 _outputFilePlayerPtr->StopPlayingFile();
2331 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2332 _outputFilePlayerPtr = NULL;
2333 return -1;
2334 }
2335 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2336 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002337 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002338
2339 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002340 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002341
2342 return 0;
2343}
2344
2345int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002346 FileFormats format,
2347 int startPosition,
2348 float volumeScaling,
2349 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002350 const CodecInst* codecInst)
2351{
2352 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2353 "Channel::StartPlayingFileLocally(format=%d,"
2354 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2355 format, volumeScaling, startPosition, stopPosition);
2356
2357 if(stream == NULL)
2358 {
2359 _engineStatisticsPtr->SetLastError(
2360 VE_BAD_FILE, kTraceError,
2361 "StartPlayingFileLocally() NULL as input stream");
2362 return -1;
2363 }
2364
2365
2366 if (_outputFilePlaying)
2367 {
2368 _engineStatisticsPtr->SetLastError(
2369 VE_ALREADY_PLAYING, kTraceError,
2370 "StartPlayingFileLocally() is already playing");
2371 return -1;
2372 }
2373
niklase@google.com470e71d2011-07-07 08:21:25 +00002374 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002375 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002376
2377 // Destroy the old instance
2378 if (_outputFilePlayerPtr)
2379 {
2380 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2381 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2382 _outputFilePlayerPtr = NULL;
2383 }
2384
2385 // Create the instance
2386 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2387 _outputFilePlayerId,
2388 (const FileFormats)format);
2389
2390 if (_outputFilePlayerPtr == NULL)
2391 {
2392 _engineStatisticsPtr->SetLastError(
2393 VE_INVALID_ARGUMENT, kTraceError,
2394 "StartPlayingFileLocally() filePlayer format isnot correct");
2395 return -1;
2396 }
2397
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002398 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002399
2400 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2401 volumeScaling,
2402 notificationTime,
2403 stopPosition, codecInst) != 0)
2404 {
2405 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2406 "StartPlayingFile() failed to "
2407 "start file playout");
2408 _outputFilePlayerPtr->StopPlayingFile();
2409 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2410 _outputFilePlayerPtr = NULL;
2411 return -1;
2412 }
2413 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2414 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002415 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002416
2417 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002418 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002419
niklase@google.com470e71d2011-07-07 08:21:25 +00002420 return 0;
2421}
2422
2423int Channel::StopPlayingFileLocally()
2424{
2425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2426 "Channel::StopPlayingFileLocally()");
2427
2428 if (!_outputFilePlaying)
2429 {
2430 _engineStatisticsPtr->SetLastError(
2431 VE_INVALID_OPERATION, kTraceWarning,
2432 "StopPlayingFileLocally() isnot playing");
2433 return 0;
2434 }
2435
niklase@google.com470e71d2011-07-07 08:21:25 +00002436 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002437 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002438
2439 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2440 {
2441 _engineStatisticsPtr->SetLastError(
2442 VE_STOP_RECORDING_FAILED, kTraceError,
2443 "StopPlayingFile() could not stop playing");
2444 return -1;
2445 }
2446 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2447 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2448 _outputFilePlayerPtr = NULL;
2449 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002450 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002451 // _fileCritSect cannot be taken while calling
2452 // SetAnonymousMixibilityStatus. Refer to comments in
2453 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002454 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2455 {
2456 _engineStatisticsPtr->SetLastError(
2457 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002458 "StopPlayingFile() failed to stop participant from playing as"
2459 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002460 return -1;
2461 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002462
2463 return 0;
2464}
2465
2466int Channel::IsPlayingFileLocally() const
2467{
2468 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2469 "Channel::IsPlayingFileLocally()");
2470
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002471 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002472}
2473
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002474int Channel::RegisterFilePlayingToMixer()
2475{
2476 // Return success for not registering for file playing to mixer if:
2477 // 1. playing file before playout is started on that channel.
2478 // 2. starting playout without file playing on that channel.
2479 if (!_playing || !_outputFilePlaying)
2480 {
2481 return 0;
2482 }
2483
2484 // |_fileCritSect| cannot be taken while calling
2485 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2486 // frames can be pulled by the mixer. Since the frames are generated from
2487 // the file, _fileCritSect will be taken. This would result in a deadlock.
2488 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2489 {
2490 CriticalSectionScoped cs(&_fileCritSect);
2491 _outputFilePlaying = false;
2492 _engineStatisticsPtr->SetLastError(
2493 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2494 "StartPlayingFile() failed to add participant as file to mixer");
2495 _outputFilePlayerPtr->StopPlayingFile();
2496 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2497 _outputFilePlayerPtr = NULL;
2498 return -1;
2499 }
2500
2501 return 0;
2502}
2503
pbos@webrtc.org92135212013-05-14 08:31:39 +00002504int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002505{
2506 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2507 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2508
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002509 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002510
2511 if (!_outputFilePlaying)
2512 {
2513 _engineStatisticsPtr->SetLastError(
2514 VE_INVALID_OPERATION, kTraceError,
2515 "ScaleLocalFilePlayout() isnot playing");
2516 return -1;
2517 }
2518 if ((_outputFilePlayerPtr == NULL) ||
2519 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2520 {
2521 _engineStatisticsPtr->SetLastError(
2522 VE_BAD_ARGUMENT, kTraceError,
2523 "SetAudioScaling() failed to scale the playout");
2524 return -1;
2525 }
2526
2527 return 0;
2528}
2529
2530int Channel::GetLocalPlayoutPosition(int& positionMs)
2531{
2532 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2533 "Channel::GetLocalPlayoutPosition(position=?)");
2534
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002535 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002536
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002537 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002538
2539 if (_outputFilePlayerPtr == NULL)
2540 {
2541 _engineStatisticsPtr->SetLastError(
2542 VE_INVALID_OPERATION, kTraceError,
2543 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2544 return -1;
2545 }
2546
2547 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2548 {
2549 _engineStatisticsPtr->SetLastError(
2550 VE_BAD_FILE, kTraceError,
2551 "GetLocalPlayoutPosition() failed");
2552 return -1;
2553 }
2554 positionMs = position;
2555
2556 return 0;
2557}
2558
2559int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002560 bool loop,
2561 FileFormats format,
2562 int startPosition,
2563 float volumeScaling,
2564 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002565 const CodecInst* codecInst)
2566{
2567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2568 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2569 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2570 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2571 startPosition, stopPosition);
2572
2573 if (_inputFilePlaying)
2574 {
2575 _engineStatisticsPtr->SetLastError(
2576 VE_ALREADY_PLAYING, kTraceWarning,
2577 "StartPlayingFileAsMicrophone() filePlayer is playing");
2578 return 0;
2579 }
2580
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002581 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002582
2583 // Destroy the old instance
2584 if (_inputFilePlayerPtr)
2585 {
2586 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2587 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2588 _inputFilePlayerPtr = NULL;
2589 }
2590
2591 // Create the instance
2592 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2593 _inputFilePlayerId, (const FileFormats)format);
2594
2595 if (_inputFilePlayerPtr == NULL)
2596 {
2597 _engineStatisticsPtr->SetLastError(
2598 VE_INVALID_ARGUMENT, kTraceError,
2599 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2600 return -1;
2601 }
2602
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002603 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002604
2605 if (_inputFilePlayerPtr->StartPlayingFile(
2606 fileName,
2607 loop,
2608 startPosition,
2609 volumeScaling,
2610 notificationTime,
2611 stopPosition,
2612 (const CodecInst*)codecInst) != 0)
2613 {
2614 _engineStatisticsPtr->SetLastError(
2615 VE_BAD_FILE, kTraceError,
2616 "StartPlayingFile() failed to start file playout");
2617 _inputFilePlayerPtr->StopPlayingFile();
2618 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2619 _inputFilePlayerPtr = NULL;
2620 return -1;
2621 }
2622 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2623 _inputFilePlaying = true;
2624
2625 return 0;
2626}
2627
2628int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002629 FileFormats format,
2630 int startPosition,
2631 float volumeScaling,
2632 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002633 const CodecInst* codecInst)
2634{
2635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2636 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2637 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2638 format, volumeScaling, startPosition, stopPosition);
2639
2640 if(stream == NULL)
2641 {
2642 _engineStatisticsPtr->SetLastError(
2643 VE_BAD_FILE, kTraceError,
2644 "StartPlayingFileAsMicrophone NULL as input stream");
2645 return -1;
2646 }
2647
2648 if (_inputFilePlaying)
2649 {
2650 _engineStatisticsPtr->SetLastError(
2651 VE_ALREADY_PLAYING, kTraceWarning,
2652 "StartPlayingFileAsMicrophone() is playing");
2653 return 0;
2654 }
2655
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002656 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002657
2658 // Destroy the old instance
2659 if (_inputFilePlayerPtr)
2660 {
2661 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2662 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2663 _inputFilePlayerPtr = NULL;
2664 }
2665
2666 // Create the instance
2667 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2668 _inputFilePlayerId, (const FileFormats)format);
2669
2670 if (_inputFilePlayerPtr == NULL)
2671 {
2672 _engineStatisticsPtr->SetLastError(
2673 VE_INVALID_ARGUMENT, kTraceError,
2674 "StartPlayingInputFile() filePlayer format isnot correct");
2675 return -1;
2676 }
2677
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002678 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002679
2680 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2681 volumeScaling, notificationTime,
2682 stopPosition, codecInst) != 0)
2683 {
2684 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2685 "StartPlayingFile() failed to start "
2686 "file playout");
2687 _inputFilePlayerPtr->StopPlayingFile();
2688 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2689 _inputFilePlayerPtr = NULL;
2690 return -1;
2691 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002692
niklase@google.com470e71d2011-07-07 08:21:25 +00002693 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2694 _inputFilePlaying = true;
2695
2696 return 0;
2697}
2698
2699int Channel::StopPlayingFileAsMicrophone()
2700{
2701 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2702 "Channel::StopPlayingFileAsMicrophone()");
2703
2704 if (!_inputFilePlaying)
2705 {
2706 _engineStatisticsPtr->SetLastError(
2707 VE_INVALID_OPERATION, kTraceWarning,
2708 "StopPlayingFileAsMicrophone() isnot playing");
2709 return 0;
2710 }
2711
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002712 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002713 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2714 {
2715 _engineStatisticsPtr->SetLastError(
2716 VE_STOP_RECORDING_FAILED, kTraceError,
2717 "StopPlayingFile() could not stop playing");
2718 return -1;
2719 }
2720 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2721 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2722 _inputFilePlayerPtr = NULL;
2723 _inputFilePlaying = false;
2724
2725 return 0;
2726}
2727
2728int Channel::IsPlayingFileAsMicrophone() const
2729{
2730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2731 "Channel::IsPlayingFileAsMicrophone()");
2732
2733 return _inputFilePlaying;
2734}
2735
pbos@webrtc.org92135212013-05-14 08:31:39 +00002736int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002737{
2738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2739 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2740
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002741 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002742
2743 if (!_inputFilePlaying)
2744 {
2745 _engineStatisticsPtr->SetLastError(
2746 VE_INVALID_OPERATION, kTraceError,
2747 "ScaleFileAsMicrophonePlayout() isnot playing");
2748 return -1;
2749 }
2750
2751 if ((_inputFilePlayerPtr == NULL) ||
2752 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2753 {
2754 _engineStatisticsPtr->SetLastError(
2755 VE_BAD_ARGUMENT, kTraceError,
2756 "SetAudioScaling() failed to scale playout");
2757 return -1;
2758 }
2759
2760 return 0;
2761}
2762
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002763int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 const CodecInst* codecInst)
2765{
2766 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2767 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2768
2769 if (_outputFileRecording)
2770 {
2771 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2772 "StartRecordingPlayout() is already recording");
2773 return 0;
2774 }
2775
2776 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002777 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002778 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2779
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002780 if ((codecInst != NULL) &&
2781 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002782 {
2783 _engineStatisticsPtr->SetLastError(
2784 VE_BAD_ARGUMENT, kTraceError,
2785 "StartRecordingPlayout() invalid compression");
2786 return(-1);
2787 }
2788 if(codecInst == NULL)
2789 {
2790 format = kFileFormatPcm16kHzFile;
2791 codecInst=&dummyCodec;
2792 }
2793 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2794 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2795 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2796 {
2797 format = kFileFormatWavFile;
2798 }
2799 else
2800 {
2801 format = kFileFormatCompressedFile;
2802 }
2803
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002804 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002805
2806 // Destroy the old instance
2807 if (_outputFileRecorderPtr)
2808 {
2809 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2810 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2811 _outputFileRecorderPtr = NULL;
2812 }
2813
2814 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2815 _outputFileRecorderId, (const FileFormats)format);
2816 if (_outputFileRecorderPtr == NULL)
2817 {
2818 _engineStatisticsPtr->SetLastError(
2819 VE_INVALID_ARGUMENT, kTraceError,
2820 "StartRecordingPlayout() fileRecorder format isnot correct");
2821 return -1;
2822 }
2823
2824 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2825 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2826 {
2827 _engineStatisticsPtr->SetLastError(
2828 VE_BAD_FILE, kTraceError,
2829 "StartRecordingAudioFile() failed to start file recording");
2830 _outputFileRecorderPtr->StopRecording();
2831 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2832 _outputFileRecorderPtr = NULL;
2833 return -1;
2834 }
2835 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2836 _outputFileRecording = true;
2837
2838 return 0;
2839}
2840
2841int Channel::StartRecordingPlayout(OutStream* stream,
2842 const CodecInst* codecInst)
2843{
2844 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2845 "Channel::StartRecordingPlayout()");
2846
2847 if (_outputFileRecording)
2848 {
2849 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2850 "StartRecordingPlayout() is already recording");
2851 return 0;
2852 }
2853
2854 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002855 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002856 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2857
2858 if (codecInst != NULL && codecInst->channels != 1)
2859 {
2860 _engineStatisticsPtr->SetLastError(
2861 VE_BAD_ARGUMENT, kTraceError,
2862 "StartRecordingPlayout() invalid compression");
2863 return(-1);
2864 }
2865 if(codecInst == NULL)
2866 {
2867 format = kFileFormatPcm16kHzFile;
2868 codecInst=&dummyCodec;
2869 }
2870 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2871 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2872 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2873 {
2874 format = kFileFormatWavFile;
2875 }
2876 else
2877 {
2878 format = kFileFormatCompressedFile;
2879 }
2880
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002881 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002882
2883 // Destroy the old instance
2884 if (_outputFileRecorderPtr)
2885 {
2886 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2887 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2888 _outputFileRecorderPtr = NULL;
2889 }
2890
2891 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2892 _outputFileRecorderId, (const FileFormats)format);
2893 if (_outputFileRecorderPtr == NULL)
2894 {
2895 _engineStatisticsPtr->SetLastError(
2896 VE_INVALID_ARGUMENT, kTraceError,
2897 "StartRecordingPlayout() fileRecorder format isnot correct");
2898 return -1;
2899 }
2900
2901 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2902 notificationTime) != 0)
2903 {
2904 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2905 "StartRecordingPlayout() failed to "
2906 "start file recording");
2907 _outputFileRecorderPtr->StopRecording();
2908 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2909 _outputFileRecorderPtr = NULL;
2910 return -1;
2911 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002912
niklase@google.com470e71d2011-07-07 08:21:25 +00002913 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2914 _outputFileRecording = true;
2915
2916 return 0;
2917}
2918
2919int Channel::StopRecordingPlayout()
2920{
2921 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2922 "Channel::StopRecordingPlayout()");
2923
2924 if (!_outputFileRecording)
2925 {
2926 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2927 "StopRecordingPlayout() isnot recording");
2928 return -1;
2929 }
2930
2931
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002932 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002933
2934 if (_outputFileRecorderPtr->StopRecording() != 0)
2935 {
2936 _engineStatisticsPtr->SetLastError(
2937 VE_STOP_RECORDING_FAILED, kTraceError,
2938 "StopRecording() could not stop recording");
2939 return(-1);
2940 }
2941 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2942 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2943 _outputFileRecorderPtr = NULL;
2944 _outputFileRecording = false;
2945
2946 return 0;
2947}
2948
2949void
2950Channel::SetMixWithMicStatus(bool mix)
2951{
2952 _mixFileWithMicrophone=mix;
2953}
2954
2955int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002956Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002957{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002958 int8_t currentLevel = _outputAudioLevel.Level();
2959 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002960 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2961 VoEId(_instanceId,_channelId),
2962 "GetSpeechOutputLevel() => level=%u", level);
2963 return 0;
2964}
2965
2966int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002967Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002968{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002969 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2970 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002971 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2972 VoEId(_instanceId,_channelId),
2973 "GetSpeechOutputLevelFullRange() => level=%u", level);
2974 return 0;
2975}
2976
2977int
2978Channel::SetMute(bool enable)
2979{
wu@webrtc.org63420662013-10-17 18:28:55 +00002980 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002981 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2982 "Channel::SetMute(enable=%d)", enable);
2983 _mute = enable;
2984 return 0;
2985}
2986
2987bool
2988Channel::Mute() const
2989{
wu@webrtc.org63420662013-10-17 18:28:55 +00002990 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002991 return _mute;
2992}
2993
2994int
2995Channel::SetOutputVolumePan(float left, float right)
2996{
wu@webrtc.org63420662013-10-17 18:28:55 +00002997 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2999 "Channel::SetOutputVolumePan()");
3000 _panLeft = left;
3001 _panRight = right;
3002 return 0;
3003}
3004
3005int
3006Channel::GetOutputVolumePan(float& left, float& right) const
3007{
wu@webrtc.org63420662013-10-17 18:28:55 +00003008 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003009 left = _panLeft;
3010 right = _panRight;
3011 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3012 VoEId(_instanceId,_channelId),
3013 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3014 return 0;
3015}
3016
3017int
3018Channel::SetChannelOutputVolumeScaling(float scaling)
3019{
wu@webrtc.org63420662013-10-17 18:28:55 +00003020 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003021 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3022 "Channel::SetChannelOutputVolumeScaling()");
3023 _outputGain = scaling;
3024 return 0;
3025}
3026
3027int
3028Channel::GetChannelOutputVolumeScaling(float& scaling) const
3029{
wu@webrtc.org63420662013-10-17 18:28:55 +00003030 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003031 scaling = _outputGain;
3032 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3033 VoEId(_instanceId,_channelId),
3034 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3035 return 0;
3036}
3037
niklase@google.com470e71d2011-07-07 08:21:25 +00003038int
3039Channel::RegisterExternalEncryption(Encryption& encryption)
3040{
3041 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3042 "Channel::RegisterExternalEncryption()");
3043
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003044 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003045
3046 if (_encryptionPtr)
3047 {
3048 _engineStatisticsPtr->SetLastError(
3049 VE_INVALID_OPERATION, kTraceError,
3050 "RegisterExternalEncryption() encryption already enabled");
3051 return -1;
3052 }
3053
3054 _encryptionPtr = &encryption;
3055
3056 _decrypting = true;
3057 _encrypting = true;
3058
3059 return 0;
3060}
3061
3062int
3063Channel::DeRegisterExternalEncryption()
3064{
3065 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3066 "Channel::DeRegisterExternalEncryption()");
3067
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003068 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003069
3070 if (!_encryptionPtr)
3071 {
3072 _engineStatisticsPtr->SetLastError(
3073 VE_INVALID_OPERATION, kTraceWarning,
3074 "DeRegisterExternalEncryption() encryption already disabled");
3075 return 0;
3076 }
3077
3078 _decrypting = false;
3079 _encrypting = false;
3080
3081 _encryptionPtr = NULL;
3082
3083 return 0;
3084}
3085
3086int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003087 int lengthMs, int attenuationDb,
3088 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003089{
3090 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3091 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3092 playDtmfEvent);
3093
3094 _playOutbandDtmfEvent = playDtmfEvent;
3095
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003096 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003097 attenuationDb) != 0)
3098 {
3099 _engineStatisticsPtr->SetLastError(
3100 VE_SEND_DTMF_FAILED,
3101 kTraceWarning,
3102 "SendTelephoneEventOutband() failed to send event");
3103 return -1;
3104 }
3105 return 0;
3106}
3107
3108int Channel::SendTelephoneEventInband(unsigned char eventCode,
3109 int lengthMs,
3110 int attenuationDb,
3111 bool playDtmfEvent)
3112{
3113 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3114 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3115 playDtmfEvent);
3116
3117 _playInbandDtmfEvent = playDtmfEvent;
3118 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3119
3120 return 0;
3121}
3122
3123int
3124Channel::SetDtmfPlayoutStatus(bool enable)
3125{
3126 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3127 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003128 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003129 {
3130 _engineStatisticsPtr->SetLastError(
3131 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3132 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3133 return -1;
3134 }
3135 return 0;
3136}
3137
3138bool
3139Channel::DtmfPlayoutStatus() const
3140{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003141 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003142}
3143
3144int
3145Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3146{
3147 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3148 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003149 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003150 {
3151 _engineStatisticsPtr->SetLastError(
3152 VE_INVALID_ARGUMENT, kTraceError,
3153 "SetSendTelephoneEventPayloadType() invalid type");
3154 return -1;
3155 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003156 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003157 codec.plfreq = 8000;
3158 codec.pltype = type;
3159 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003160 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003161 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003162 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3163 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3164 _engineStatisticsPtr->SetLastError(
3165 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3166 "SetSendTelephoneEventPayloadType() failed to register send"
3167 "payload type");
3168 return -1;
3169 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003170 }
3171 _sendTelephoneEventPayloadType = type;
3172 return 0;
3173}
3174
3175int
3176Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3177{
3178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3179 "Channel::GetSendTelephoneEventPayloadType()");
3180 type = _sendTelephoneEventPayloadType;
3181 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3182 VoEId(_instanceId,_channelId),
3183 "GetSendTelephoneEventPayloadType() => type=%u", type);
3184 return 0;
3185}
3186
niklase@google.com470e71d2011-07-07 08:21:25 +00003187int
3188Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3189{
3190 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3191 "Channel::UpdateRxVadDetection()");
3192
3193 int vadDecision = 1;
3194
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003195 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003196
3197 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3198 {
3199 OnRxVadDetected(vadDecision);
3200 _oldVadDecision = vadDecision;
3201 }
3202
3203 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3204 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3205 vadDecision);
3206 return 0;
3207}
3208
3209int
3210Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3211{
3212 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3213 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003214 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003215
3216 if (_rxVadObserverPtr)
3217 {
3218 _engineStatisticsPtr->SetLastError(
3219 VE_INVALID_OPERATION, kTraceError,
3220 "RegisterRxVadObserver() observer already enabled");
3221 return -1;
3222 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003223 _rxVadObserverPtr = &observer;
3224 _RxVadDetection = true;
3225 return 0;
3226}
3227
3228int
3229Channel::DeRegisterRxVadObserver()
3230{
3231 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3232 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003233 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003234
3235 if (!_rxVadObserverPtr)
3236 {
3237 _engineStatisticsPtr->SetLastError(
3238 VE_INVALID_OPERATION, kTraceWarning,
3239 "DeRegisterRxVadObserver() observer already disabled");
3240 return 0;
3241 }
3242 _rxVadObserverPtr = NULL;
3243 _RxVadDetection = false;
3244 return 0;
3245}
3246
3247int
3248Channel::VoiceActivityIndicator(int &activity)
3249{
3250 activity = _sendFrameType;
3251
3252 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003253 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003254 return 0;
3255}
3256
3257#ifdef WEBRTC_VOICE_ENGINE_AGC
3258
3259int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003260Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003261{
3262 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3263 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3264 (int)enable, (int)mode);
3265
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003266 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003267 switch (mode)
3268 {
3269 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 break;
3271 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003272 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003273 break;
3274 case kAgcFixedDigital:
3275 agcMode = GainControl::kFixedDigital;
3276 break;
3277 case kAgcAdaptiveDigital:
3278 agcMode =GainControl::kAdaptiveDigital;
3279 break;
3280 default:
3281 _engineStatisticsPtr->SetLastError(
3282 VE_INVALID_ARGUMENT, kTraceError,
3283 "SetRxAgcStatus() invalid Agc mode");
3284 return -1;
3285 }
3286
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003287 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 {
3289 _engineStatisticsPtr->SetLastError(
3290 VE_APM_ERROR, kTraceError,
3291 "SetRxAgcStatus() failed to set Agc mode");
3292 return -1;
3293 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003294 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003295 {
3296 _engineStatisticsPtr->SetLastError(
3297 VE_APM_ERROR, kTraceError,
3298 "SetRxAgcStatus() failed to set Agc state");
3299 return -1;
3300 }
3301
3302 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003303 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3304
3305 return 0;
3306}
3307
3308int
3309Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3310{
3311 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3312 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3313
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003314 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003315 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003316 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003317
3318 enabled = enable;
3319
3320 switch (agcMode)
3321 {
3322 case GainControl::kFixedDigital:
3323 mode = kAgcFixedDigital;
3324 break;
3325 case GainControl::kAdaptiveDigital:
3326 mode = kAgcAdaptiveDigital;
3327 break;
3328 default:
3329 _engineStatisticsPtr->SetLastError(
3330 VE_APM_ERROR, kTraceError,
3331 "GetRxAgcStatus() invalid Agc mode");
3332 return -1;
3333 }
3334
3335 return 0;
3336}
3337
3338int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003339Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003340{
3341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3342 "Channel::SetRxAgcConfig()");
3343
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003344 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003345 config.targetLeveldBOv) != 0)
3346 {
3347 _engineStatisticsPtr->SetLastError(
3348 VE_APM_ERROR, kTraceError,
3349 "SetRxAgcConfig() failed to set target peak |level|"
3350 "(or envelope) of the Agc");
3351 return -1;
3352 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003353 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003354 config.digitalCompressionGaindB) != 0)
3355 {
3356 _engineStatisticsPtr->SetLastError(
3357 VE_APM_ERROR, kTraceError,
3358 "SetRxAgcConfig() failed to set the range in |gain| the"
3359 " digital compression stage may apply");
3360 return -1;
3361 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003362 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003363 config.limiterEnable) != 0)
3364 {
3365 _engineStatisticsPtr->SetLastError(
3366 VE_APM_ERROR, kTraceError,
3367 "SetRxAgcConfig() failed to set hard limiter to the signal");
3368 return -1;
3369 }
3370
3371 return 0;
3372}
3373
3374int
3375Channel::GetRxAgcConfig(AgcConfig& config)
3376{
3377 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3378 "Channel::GetRxAgcConfig(config=%?)");
3379
3380 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003381 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003382 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003383 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003384 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003385 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003386
3387 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3388 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3389 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3390 " limiterEnable=%d",
3391 config.targetLeveldBOv,
3392 config.digitalCompressionGaindB,
3393 config.limiterEnable);
3394
3395 return 0;
3396}
3397
3398#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3399
3400#ifdef WEBRTC_VOICE_ENGINE_NR
3401
3402int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003403Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003404{
3405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3406 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3407 (int)enable, (int)mode);
3408
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003409 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 switch (mode)
3411 {
3412
3413 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003414 break;
3415 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003416 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003417 break;
3418 case kNsConference:
3419 nsLevel = NoiseSuppression::kHigh;
3420 break;
3421 case kNsLowSuppression:
3422 nsLevel = NoiseSuppression::kLow;
3423 break;
3424 case kNsModerateSuppression:
3425 nsLevel = NoiseSuppression::kModerate;
3426 break;
3427 case kNsHighSuppression:
3428 nsLevel = NoiseSuppression::kHigh;
3429 break;
3430 case kNsVeryHighSuppression:
3431 nsLevel = NoiseSuppression::kVeryHigh;
3432 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003433 }
3434
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003435 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003436 != 0)
3437 {
3438 _engineStatisticsPtr->SetLastError(
3439 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003440 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003441 return -1;
3442 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003443 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003444 {
3445 _engineStatisticsPtr->SetLastError(
3446 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003447 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003448 return -1;
3449 }
3450
3451 _rxNsIsEnabled = enable;
3452 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3453
3454 return 0;
3455}
3456
3457int
3458Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3459{
3460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3461 "Channel::GetRxNsStatus(enable=?, mode=?)");
3462
3463 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003464 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003465 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003466 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003467
3468 enabled = enable;
3469
3470 switch (ncLevel)
3471 {
3472 case NoiseSuppression::kLow:
3473 mode = kNsLowSuppression;
3474 break;
3475 case NoiseSuppression::kModerate:
3476 mode = kNsModerateSuppression;
3477 break;
3478 case NoiseSuppression::kHigh:
3479 mode = kNsHighSuppression;
3480 break;
3481 case NoiseSuppression::kVeryHigh:
3482 mode = kNsVeryHighSuppression;
3483 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003484 }
3485
3486 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3487 VoEId(_instanceId,_channelId),
3488 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3489 return 0;
3490}
3491
3492#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3493
3494int
3495Channel::RegisterRTPObserver(VoERTPObserver& observer)
3496{
3497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3498 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003499 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003500
3501 if (_rtpObserverPtr)
3502 {
3503 _engineStatisticsPtr->SetLastError(
3504 VE_INVALID_OPERATION, kTraceError,
3505 "RegisterRTPObserver() observer already enabled");
3506 return -1;
3507 }
3508
3509 _rtpObserverPtr = &observer;
3510 _rtpObserver = true;
3511
3512 return 0;
3513}
3514
3515int
3516Channel::DeRegisterRTPObserver()
3517{
3518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3519 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003520 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003521
3522 if (!_rtpObserverPtr)
3523 {
3524 _engineStatisticsPtr->SetLastError(
3525 VE_INVALID_OPERATION, kTraceWarning,
3526 "DeRegisterRTPObserver() observer already disabled");
3527 return 0;
3528 }
3529
3530 _rtpObserver = false;
3531 _rtpObserverPtr = NULL;
3532
3533 return 0;
3534}
3535
3536int
3537Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3538{
3539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3540 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003541 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003542
3543 if (_rtcpObserverPtr)
3544 {
3545 _engineStatisticsPtr->SetLastError(
3546 VE_INVALID_OPERATION, kTraceError,
3547 "RegisterRTCPObserver() observer already enabled");
3548 return -1;
3549 }
3550
3551 _rtcpObserverPtr = &observer;
3552 _rtcpObserver = true;
3553
3554 return 0;
3555}
3556
3557int
3558Channel::DeRegisterRTCPObserver()
3559{
3560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3561 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003562 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003563
3564 if (!_rtcpObserverPtr)
3565 {
3566 _engineStatisticsPtr->SetLastError(
3567 VE_INVALID_OPERATION, kTraceWarning,
3568 "DeRegisterRTCPObserver() observer already disabled");
3569 return 0;
3570 }
3571
3572 _rtcpObserver = false;
3573 _rtcpObserverPtr = NULL;
3574
3575 return 0;
3576}
3577
3578int
3579Channel::SetLocalSSRC(unsigned int ssrc)
3580{
3581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3582 "Channel::SetLocalSSRC()");
3583 if (_sending)
3584 {
3585 _engineStatisticsPtr->SetLastError(
3586 VE_ALREADY_SENDING, kTraceError,
3587 "SetLocalSSRC() already sending");
3588 return -1;
3589 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003590 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003591 {
3592 _engineStatisticsPtr->SetLastError(
3593 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3594 "SetLocalSSRC() failed to set SSRC");
3595 return -1;
3596 }
3597 return 0;
3598}
3599
3600int
3601Channel::GetLocalSSRC(unsigned int& ssrc)
3602{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003603 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003604 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3605 VoEId(_instanceId,_channelId),
3606 "GetLocalSSRC() => ssrc=%lu", ssrc);
3607 return 0;
3608}
3609
3610int
3611Channel::GetRemoteSSRC(unsigned int& ssrc)
3612{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003613 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003614 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3615 VoEId(_instanceId,_channelId),
3616 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3617 return 0;
3618}
3619
3620int
3621Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3622{
3623 if (arrCSRC == NULL)
3624 {
3625 _engineStatisticsPtr->SetLastError(
3626 VE_INVALID_ARGUMENT, kTraceError,
3627 "GetRemoteCSRCs() invalid array argument");
3628 return -1;
3629 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003630 uint32_t arrOfCSRC[kRtpCsrcSize];
3631 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003632 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003633 if (CSRCs > 0)
3634 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003635 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003636 for (int i = 0; i < (int) CSRCs; i++)
3637 {
3638 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3639 VoEId(_instanceId, _channelId),
3640 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3641 }
3642 } else
3643 {
3644 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3645 VoEId(_instanceId, _channelId),
3646 "GetRemoteCSRCs() => list is empty!");
3647 }
3648 return CSRCs;
3649}
3650
3651int
3652Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3653{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003654 if (rtp_audioproc_.get() == NULL) {
3655 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3656 _channelId)));
3657 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003658
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003659 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3660 AudioProcessing::kNoError) {
3661 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3662 "Failed to enable AudioProcessing::level_estimator()");
3663 return -1;
3664 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003665
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003666 _includeAudioLevelIndication = enable;
3667 if (enable) {
3668 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3669 ID);
3670 } else {
3671 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3672 }
3673 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003674}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003675
niklase@google.com470e71d2011-07-07 08:21:25 +00003676int
3677Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3678{
3679 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3680 VoEId(_instanceId,_channelId),
3681 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3682 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003683 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003684}
3685
3686int
3687Channel::SetRTCPStatus(bool enable)
3688{
3689 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3690 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003691 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003692 kRtcpCompound : kRtcpOff) != 0)
3693 {
3694 _engineStatisticsPtr->SetLastError(
3695 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3696 "SetRTCPStatus() failed to set RTCP status");
3697 return -1;
3698 }
3699 return 0;
3700}
3701
3702int
3703Channel::GetRTCPStatus(bool& enabled)
3704{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003705 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003706 enabled = (method != kRtcpOff);
3707 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3708 VoEId(_instanceId,_channelId),
3709 "GetRTCPStatus() => enabled=%d", enabled);
3710 return 0;
3711}
3712
3713int
3714Channel::SetRTCP_CNAME(const char cName[256])
3715{
3716 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3717 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003718 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003719 {
3720 _engineStatisticsPtr->SetLastError(
3721 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3722 "SetRTCP_CNAME() failed to set RTCP CNAME");
3723 return -1;
3724 }
3725 return 0;
3726}
3727
3728int
3729Channel::GetRTCP_CNAME(char cName[256])
3730{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003731 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003732 {
3733 _engineStatisticsPtr->SetLastError(
3734 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3735 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3736 return -1;
3737 }
3738 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3739 VoEId(_instanceId, _channelId),
3740 "GetRTCP_CNAME() => cName=%s", cName);
3741 return 0;
3742}
3743
3744int
3745Channel::GetRemoteRTCP_CNAME(char cName[256])
3746{
3747 if (cName == NULL)
3748 {
3749 _engineStatisticsPtr->SetLastError(
3750 VE_INVALID_ARGUMENT, kTraceError,
3751 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3752 return -1;
3753 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003754 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003755 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003756 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 {
3758 _engineStatisticsPtr->SetLastError(
3759 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3760 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3761 return -1;
3762 }
3763 strcpy(cName, cname);
3764 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3765 VoEId(_instanceId, _channelId),
3766 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3767 return 0;
3768}
3769
3770int
3771Channel::GetRemoteRTCPData(
3772 unsigned int& NTPHigh,
3773 unsigned int& NTPLow,
3774 unsigned int& timestamp,
3775 unsigned int& playoutTimestamp,
3776 unsigned int* jitter,
3777 unsigned short* fractionLost)
3778{
3779 // --- Information from sender info in received Sender Reports
3780
3781 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003782 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003783 {
3784 _engineStatisticsPtr->SetLastError(
3785 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003786 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003787 "side");
3788 return -1;
3789 }
3790
3791 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3792 // and octet count)
3793 NTPHigh = senderInfo.NTPseconds;
3794 NTPLow = senderInfo.NTPfraction;
3795 timestamp = senderInfo.RTPtimeStamp;
3796
3797 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3798 VoEId(_instanceId, _channelId),
3799 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3800 "timestamp=%lu",
3801 NTPHigh, NTPLow, timestamp);
3802
3803 // --- Locally derived information
3804
3805 // This value is updated on each incoming RTCP packet (0 when no packet
3806 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003807 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003808
3809 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3810 VoEId(_instanceId, _channelId),
3811 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003812 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003813
3814 if (NULL != jitter || NULL != fractionLost)
3815 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003816 // Get all RTCP receiver report blocks that have been received on this
3817 // channel. If we receive RTP packets from a remote source we know the
3818 // remote SSRC and use the report block from him.
3819 // Otherwise use the first report block.
3820 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003821 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003822 remote_stats.empty()) {
3823 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3824 VoEId(_instanceId, _channelId),
3825 "GetRemoteRTCPData() failed to measure statistics due"
3826 " to lack of received RTP and/or RTCP packets");
3827 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003828 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003829
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003830 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003831 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3832 for (; it != remote_stats.end(); ++it) {
3833 if (it->remoteSSRC == remoteSSRC)
3834 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003835 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003836
3837 if (it == remote_stats.end()) {
3838 // If we have not received any RTCP packets from this SSRC it probably
3839 // means that we have not received any RTP packets.
3840 // Use the first received report block instead.
3841 it = remote_stats.begin();
3842 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003843 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003844
xians@webrtc.org79af7342012-01-31 12:22:14 +00003845 if (jitter) {
3846 *jitter = it->jitter;
3847 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3848 VoEId(_instanceId, _channelId),
3849 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3850 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003851
xians@webrtc.org79af7342012-01-31 12:22:14 +00003852 if (fractionLost) {
3853 *fractionLost = it->fractionLost;
3854 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3855 VoEId(_instanceId, _channelId),
3856 "GetRemoteRTCPData() => fractionLost = %lu",
3857 *fractionLost);
3858 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003859 }
3860 return 0;
3861}
3862
3863int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003864Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003865 unsigned int name,
3866 const char* data,
3867 unsigned short dataLengthInBytes)
3868{
3869 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3870 "Channel::SendApplicationDefinedRTCPPacket()");
3871 if (!_sending)
3872 {
3873 _engineStatisticsPtr->SetLastError(
3874 VE_NOT_SENDING, kTraceError,
3875 "SendApplicationDefinedRTCPPacket() not sending");
3876 return -1;
3877 }
3878 if (NULL == data)
3879 {
3880 _engineStatisticsPtr->SetLastError(
3881 VE_INVALID_ARGUMENT, kTraceError,
3882 "SendApplicationDefinedRTCPPacket() invalid data value");
3883 return -1;
3884 }
3885 if (dataLengthInBytes % 4 != 0)
3886 {
3887 _engineStatisticsPtr->SetLastError(
3888 VE_INVALID_ARGUMENT, kTraceError,
3889 "SendApplicationDefinedRTCPPacket() invalid length value");
3890 return -1;
3891 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003892 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003893 if (status == kRtcpOff)
3894 {
3895 _engineStatisticsPtr->SetLastError(
3896 VE_RTCP_ERROR, kTraceError,
3897 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3898 return -1;
3899 }
3900
3901 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003902 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003903 subType,
3904 name,
3905 (const unsigned char*) data,
3906 dataLengthInBytes) != 0)
3907 {
3908 _engineStatisticsPtr->SetLastError(
3909 VE_SEND_ERROR, kTraceError,
3910 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3911 return -1;
3912 }
3913 return 0;
3914}
3915
3916int
3917Channel::GetRTPStatistics(
3918 unsigned int& averageJitterMs,
3919 unsigned int& maxJitterMs,
3920 unsigned int& discardedPackets)
3921{
niklase@google.com470e71d2011-07-07 08:21:25 +00003922 // The jitter statistics is updated for each received RTP packet and is
3923 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003924 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3925 // If RTCP is off, there is no timed thread in the RTCP module regularly
3926 // generating new stats, trigger the update manually here instead.
3927 StreamStatistician* statistician =
3928 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3929 if (statistician) {
3930 // Don't use returned statistics, use data from proxy instead so that
3931 // max jitter can be fetched atomically.
3932 RtcpStatistics s;
3933 statistician->GetStatistics(&s, true);
3934 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003935 }
3936
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003937 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003938 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003939 if (playoutFrequency > 0) {
3940 // Scale RTP statistics given the current playout frequency
3941 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3942 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003943 }
3944
3945 discardedPackets = _numberOfDiscardedPackets;
3946
3947 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3948 VoEId(_instanceId, _channelId),
3949 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003950 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003951 averageJitterMs, maxJitterMs, discardedPackets);
3952 return 0;
3953}
3954
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003955int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3956 if (sender_info == NULL) {
3957 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3958 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3959 return -1;
3960 }
3961
3962 // Get the sender info from the latest received RTCP Sender Report.
3963 RTCPSenderInfo rtcp_sender_info;
3964 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3965 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3966 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3967 return -1;
3968 }
3969
3970 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3971 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3972 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3973 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3974 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3975 return 0;
3976}
3977
3978int Channel::GetRemoteRTCPReportBlocks(
3979 std::vector<ReportBlock>* report_blocks) {
3980 if (report_blocks == NULL) {
3981 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3982 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3983 return -1;
3984 }
3985
3986 // Get the report blocks from the latest received RTCP Sender or Receiver
3987 // Report. Each element in the vector contains the sender's SSRC and a
3988 // report block according to RFC 3550.
3989 std::vector<RTCPReportBlock> rtcp_report_blocks;
3990 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3991 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3992 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3993 return -1;
3994 }
3995
3996 if (rtcp_report_blocks.empty())
3997 return 0;
3998
3999 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
4000 for (; it != rtcp_report_blocks.end(); ++it) {
4001 ReportBlock report_block;
4002 report_block.sender_SSRC = it->remoteSSRC;
4003 report_block.source_SSRC = it->sourceSSRC;
4004 report_block.fraction_lost = it->fractionLost;
4005 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4006 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4007 report_block.interarrival_jitter = it->jitter;
4008 report_block.last_SR_timestamp = it->lastSR;
4009 report_block.delay_since_last_SR = it->delaySinceLastSR;
4010 report_blocks->push_back(report_block);
4011 }
4012 return 0;
4013}
4014
niklase@google.com470e71d2011-07-07 08:21:25 +00004015int
4016Channel::GetRTPStatistics(CallStatistics& stats)
4017{
niklase@google.com470e71d2011-07-07 08:21:25 +00004018 // --- Part one of the final structure (four values)
4019
4020 // The jitter statistics is updated for each received RTP packet and is
4021 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00004022 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004023 StreamStatistician* statistician =
4024 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
4025 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004026 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4027 _engineStatisticsPtr->SetLastError(
4028 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4029 "GetRTPStatistics() failed to read RTP statistics from the "
4030 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004031 }
4032
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004033 stats.fractionLost = statistics.fraction_lost;
4034 stats.cumulativeLost = statistics.cumulative_lost;
4035 stats.extendedMax = statistics.extended_max_sequence_number;
4036 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004037
4038 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4039 VoEId(_instanceId, _channelId),
4040 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004041 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004042 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4043 stats.jitterSamples);
4044
4045 // --- Part two of the final structure (one value)
4046
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004047 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004048 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004049 if (method == kRtcpOff)
4050 {
4051 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4052 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004053 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004054 "measurements cannot be retrieved");
4055 } else
4056 {
4057 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004058 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004059 if (remoteSSRC > 0)
4060 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004061 uint16_t avgRTT(0);
4062 uint16_t maxRTT(0);
4063 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004064
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004065 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004066 != 0)
4067 {
4068 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4069 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004070 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004071 "the RTP/RTCP module");
4072 }
4073 } else
4074 {
4075 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4076 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004077 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004078 "RTP packets have been received yet");
4079 }
4080 }
4081
4082 stats.rttMs = static_cast<int> (RTT);
4083
4084 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4085 VoEId(_instanceId, _channelId),
4086 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4087
4088 // --- Part three of the final structure (four values)
4089
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004090 uint32_t bytesSent(0);
4091 uint32_t packetsSent(0);
4092 uint32_t bytesReceived(0);
4093 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004094
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004095 if (statistician) {
4096 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4097 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004098
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004099 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004100 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004101 {
4102 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4103 VoEId(_instanceId, _channelId),
4104 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004105 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004106 }
4107
4108 stats.bytesSent = bytesSent;
4109 stats.packetsSent = packetsSent;
4110 stats.bytesReceived = bytesReceived;
4111 stats.packetsReceived = packetsReceived;
4112
4113 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4114 VoEId(_instanceId, _channelId),
4115 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004116 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004117 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4118 stats.packetsReceived);
4119
4120 return 0;
4121}
4122
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004123int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4125 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004126
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004127 if (enable) {
4128 if (redPayloadtype < 0 || redPayloadtype > 127) {
4129 _engineStatisticsPtr->SetLastError(
4130 VE_PLTYPE_ERROR, kTraceError,
4131 "SetFECStatus() invalid RED payload type");
4132 return -1;
4133 }
4134
4135 if (SetRedPayloadType(redPayloadtype) < 0) {
4136 _engineStatisticsPtr->SetLastError(
4137 VE_CODEC_ERROR, kTraceError,
4138 "SetSecondarySendCodec() Failed to register RED ACM");
4139 return -1;
4140 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004141 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004142
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004143 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004144 _engineStatisticsPtr->SetLastError(
4145 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4146 "SetFECStatus() failed to set FEC state in the ACM");
4147 return -1;
4148 }
4149 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004150}
4151
4152int
4153Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4154{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004155 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004156 if (enabled)
4157 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004158 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004159 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004160 {
4161 _engineStatisticsPtr->SetLastError(
4162 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4163 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4164 "module");
4165 return -1;
4166 }
4167 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4168 VoEId(_instanceId, _channelId),
4169 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4170 enabled, redPayloadtype);
4171 return 0;
4172 }
4173 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4174 VoEId(_instanceId, _channelId),
4175 "GetFECStatus() => enabled=%d", enabled);
4176 return 0;
4177}
4178
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004179void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4180 // None of these functions can fail.
4181 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004182 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4183 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004184 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004185 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004186 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004187 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004188}
4189
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004190// Called when we are missing one or more packets.
4191int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004192 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4193}
4194
niklase@google.com470e71d2011-07-07 08:21:25 +00004195int
niklase@google.com470e71d2011-07-07 08:21:25 +00004196Channel::StartRTPDump(const char fileNameUTF8[1024],
4197 RTPDirections direction)
4198{
4199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4200 "Channel::StartRTPDump()");
4201 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4202 {
4203 _engineStatisticsPtr->SetLastError(
4204 VE_INVALID_ARGUMENT, kTraceError,
4205 "StartRTPDump() invalid RTP direction");
4206 return -1;
4207 }
4208 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4209 &_rtpDumpIn : &_rtpDumpOut;
4210 if (rtpDumpPtr == NULL)
4211 {
4212 assert(false);
4213 return -1;
4214 }
4215 if (rtpDumpPtr->IsActive())
4216 {
4217 rtpDumpPtr->Stop();
4218 }
4219 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4220 {
4221 _engineStatisticsPtr->SetLastError(
4222 VE_BAD_FILE, kTraceError,
4223 "StartRTPDump() failed to create file");
4224 return -1;
4225 }
4226 return 0;
4227}
4228
4229int
4230Channel::StopRTPDump(RTPDirections direction)
4231{
4232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4233 "Channel::StopRTPDump()");
4234 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4235 {
4236 _engineStatisticsPtr->SetLastError(
4237 VE_INVALID_ARGUMENT, kTraceError,
4238 "StopRTPDump() invalid RTP direction");
4239 return -1;
4240 }
4241 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4242 &_rtpDumpIn : &_rtpDumpOut;
4243 if (rtpDumpPtr == NULL)
4244 {
4245 assert(false);
4246 return -1;
4247 }
4248 if (!rtpDumpPtr->IsActive())
4249 {
4250 return 0;
4251 }
4252 return rtpDumpPtr->Stop();
4253}
4254
4255bool
4256Channel::RTPDumpIsActive(RTPDirections direction)
4257{
4258 if ((direction != kRtpIncoming) &&
4259 (direction != kRtpOutgoing))
4260 {
4261 _engineStatisticsPtr->SetLastError(
4262 VE_INVALID_ARGUMENT, kTraceError,
4263 "RTPDumpIsActive() invalid RTP direction");
4264 return false;
4265 }
4266 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4267 &_rtpDumpIn : &_rtpDumpOut;
4268 return rtpDumpPtr->IsActive();
4269}
4270
4271int
4272Channel::InsertExtraRTPPacket(unsigned char payloadType,
4273 bool markerBit,
4274 const char* payloadData,
4275 unsigned short payloadSize)
4276{
4277 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4278 "Channel::InsertExtraRTPPacket()");
4279 if (payloadType > 127)
4280 {
4281 _engineStatisticsPtr->SetLastError(
4282 VE_INVALID_PLTYPE, kTraceError,
4283 "InsertExtraRTPPacket() invalid payload type");
4284 return -1;
4285 }
4286 if (payloadData == NULL)
4287 {
4288 _engineStatisticsPtr->SetLastError(
4289 VE_INVALID_ARGUMENT, kTraceError,
4290 "InsertExtraRTPPacket() invalid payload data");
4291 return -1;
4292 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004293 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004294 {
4295 _engineStatisticsPtr->SetLastError(
4296 VE_INVALID_ARGUMENT, kTraceError,
4297 "InsertExtraRTPPacket() invalid payload size");
4298 return -1;
4299 }
4300 if (!_sending)
4301 {
4302 _engineStatisticsPtr->SetLastError(
4303 VE_NOT_SENDING, kTraceError,
4304 "InsertExtraRTPPacket() not sending");
4305 return -1;
4306 }
4307
4308 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4309 // Transport::SendPacket() will be called by the module when the RTP packet
4310 // is created.
4311 // The call to SendOutgoingData() does *not* modify the timestamp and
4312 // payloadtype to ensure that the RTP module generates a valid RTP packet
4313 // (user might utilize a non-registered payload type).
4314 // The marker bit and payload type will be replaced just before the actual
4315 // transmission, i.e., the actual modification is done *after* the RTP
4316 // module has delivered its RTP packet back to the VoE.
4317 // We will use the stored values above when the packet is modified
4318 // (see Channel::SendPacket()).
4319
4320 _extraPayloadType = payloadType;
4321 _extraMarkerBit = markerBit;
4322 _insertExtraRTPPacket = true;
4323
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004324 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004325 _lastPayloadType,
4326 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004327 // Leaving the time when this frame was
4328 // received from the capture device as
4329 // undefined for voice for now.
4330 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004331 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004332 payloadSize) != 0)
4333 {
4334 _engineStatisticsPtr->SetLastError(
4335 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4336 "InsertExtraRTPPacket() failed to send extra RTP packet");
4337 return -1;
4338 }
4339
4340 return 0;
4341}
4342
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004343uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004344Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004345{
4346 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004347 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004348 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004349 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004350 return 0;
4351}
4352
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004353// TODO(xians): This method borrows quite some code from
4354// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4355// code duplication.
4356void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004357 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004358 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004359 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004360 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4361 static const int kMaxNumberOfFrames = 960;
4362 assert(number_of_frames <= kMaxNumberOfFrames);
4363
4364 // Get the send codec information for doing resampling or downmixing later on.
4365 CodecInst codec;
4366 GetSendCodec(codec);
4367 assert(codec.channels == 1 || codec.channels == 2);
4368 int support_sample_rate = std::min(32000,
4369 std::min(sample_rate, codec.plfreq));
4370
4371 // Downmix the data to mono if needed.
4372 const int16_t* audio_ptr = audio_data;
4373 if (number_of_channels == 2 && codec.channels == 1) {
4374 if (!mono_recording_audio_.get())
4375 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4376
4377 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4378 mono_recording_audio_.get());
4379 audio_ptr = mono_recording_audio_.get();
4380 }
4381
4382 // Resample the data to the sample rate that the codec is using.
4383 if (input_resampler_.InitializeIfNeeded(sample_rate,
4384 support_sample_rate,
4385 codec.channels)) {
4386 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4387 "Channel::Demultiplex() unable to resample");
4388 return;
4389 }
4390
4391 int out_length = input_resampler_.Resample(audio_ptr,
4392 number_of_frames * codec.channels,
4393 _audioFrame.data_,
4394 AudioFrame::kMaxDataSizeSamples);
4395 if (out_length == -1) {
4396 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4397 "Channel::Demultiplex() resampling failed");
4398 return;
4399 }
4400
4401 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4402 _audioFrame.timestamp_ = -1;
4403 _audioFrame.sample_rate_hz_ = support_sample_rate;
4404 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4405 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4406 _audioFrame.num_channels_ = codec.channels;
4407 _audioFrame.id_ = _channelId;
4408}
4409
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004410uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004411Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004412{
4413 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4414 "Channel::PrepareEncodeAndSend()");
4415
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004416 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004417 {
4418 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4419 "Channel::PrepareEncodeAndSend() invalid audio frame");
4420 return -1;
4421 }
4422
4423 if (_inputFilePlaying)
4424 {
4425 MixOrReplaceAudioWithFile(mixingFrequency);
4426 }
4427
wu@webrtc.org63420662013-10-17 18:28:55 +00004428 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004429 {
4430 AudioFrameOperations::Mute(_audioFrame);
4431 }
4432
4433 if (_inputExternalMedia)
4434 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004435 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004436 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004437 if (_inputExternalMediaCallbackPtr)
4438 {
4439 _inputExternalMediaCallbackPtr->Process(
4440 _channelId,
4441 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004442 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004443 _audioFrame.samples_per_channel_,
4444 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004445 isStereo);
4446 }
4447 }
4448
4449 InsertInbandDtmfTone();
4450
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004451 if (_includeAudioLevelIndication) {
4452 // Performs level analysis only; does not affect the signal.
4453 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4454 if (err) {
4455 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4456 assert(false);
4457 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004458 }
4459
niklase@google.com470e71d2011-07-07 08:21:25 +00004460 return 0;
4461}
4462
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004463uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004464Channel::EncodeAndSend()
4465{
4466 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4467 "Channel::EncodeAndSend()");
4468
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004469 assert(_audioFrame.num_channels_ <= 2);
4470 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004471 {
4472 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4473 "Channel::EncodeAndSend() invalid audio frame");
4474 return -1;
4475 }
4476
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004477 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004478
4479 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4480
4481 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004482 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004483 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004484 {
4485 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4486 "Channel::EncodeAndSend() ACM encoding failed");
4487 return -1;
4488 }
4489
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004490 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004491
4492 // --- Encode if complete frame is ready
4493
4494 // This call will trigger AudioPacketizationCallback::SendData if encoding
4495 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004496 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004497}
4498
4499int Channel::RegisterExternalMediaProcessing(
4500 ProcessingTypes type,
4501 VoEMediaProcess& processObject)
4502{
4503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4504 "Channel::RegisterExternalMediaProcessing()");
4505
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004506 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004507
4508 if (kPlaybackPerChannel == type)
4509 {
4510 if (_outputExternalMediaCallbackPtr)
4511 {
4512 _engineStatisticsPtr->SetLastError(
4513 VE_INVALID_OPERATION, kTraceError,
4514 "Channel::RegisterExternalMediaProcessing() "
4515 "output external media already enabled");
4516 return -1;
4517 }
4518 _outputExternalMediaCallbackPtr = &processObject;
4519 _outputExternalMedia = true;
4520 }
4521 else if (kRecordingPerChannel == type)
4522 {
4523 if (_inputExternalMediaCallbackPtr)
4524 {
4525 _engineStatisticsPtr->SetLastError(
4526 VE_INVALID_OPERATION, kTraceError,
4527 "Channel::RegisterExternalMediaProcessing() "
4528 "output external media already enabled");
4529 return -1;
4530 }
4531 _inputExternalMediaCallbackPtr = &processObject;
4532 _inputExternalMedia = true;
4533 }
4534 return 0;
4535}
4536
4537int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4538{
4539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4540 "Channel::DeRegisterExternalMediaProcessing()");
4541
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004542 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004543
4544 if (kPlaybackPerChannel == type)
4545 {
4546 if (!_outputExternalMediaCallbackPtr)
4547 {
4548 _engineStatisticsPtr->SetLastError(
4549 VE_INVALID_OPERATION, kTraceWarning,
4550 "Channel::DeRegisterExternalMediaProcessing() "
4551 "output external media already disabled");
4552 return 0;
4553 }
4554 _outputExternalMedia = false;
4555 _outputExternalMediaCallbackPtr = NULL;
4556 }
4557 else if (kRecordingPerChannel == type)
4558 {
4559 if (!_inputExternalMediaCallbackPtr)
4560 {
4561 _engineStatisticsPtr->SetLastError(
4562 VE_INVALID_OPERATION, kTraceWarning,
4563 "Channel::DeRegisterExternalMediaProcessing() "
4564 "input external media already disabled");
4565 return 0;
4566 }
4567 _inputExternalMedia = false;
4568 _inputExternalMediaCallbackPtr = NULL;
4569 }
4570
4571 return 0;
4572}
4573
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004574int Channel::SetExternalMixing(bool enabled) {
4575 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4576 "Channel::SetExternalMixing(enabled=%d)", enabled);
4577
4578 if (_playing)
4579 {
4580 _engineStatisticsPtr->SetLastError(
4581 VE_INVALID_OPERATION, kTraceError,
4582 "Channel::SetExternalMixing() "
4583 "external mixing cannot be changed while playing.");
4584 return -1;
4585 }
4586
4587 _externalMixing = enabled;
4588
4589 return 0;
4590}
4591
niklase@google.com470e71d2011-07-07 08:21:25 +00004592int
4593Channel::ResetRTCPStatistics()
4594{
4595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4596 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004597 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004598 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004599 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004600}
4601
4602int
4603Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4604{
4605 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4606 "Channel::GetRoundTripTimeSummary()");
4607 // Override default module outputs for the case when RTCP is disabled.
4608 // This is done to ensure that we are backward compatible with the
4609 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004610 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004611 {
4612 delaysMs.min = -1;
4613 delaysMs.max = -1;
4614 delaysMs.average = -1;
4615 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4616 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4617 " valid RTT measurements cannot be retrieved");
4618 return 0;
4619 }
4620
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004621 uint32_t remoteSSRC;
4622 uint16_t RTT;
4623 uint16_t avgRTT;
4624 uint16_t maxRTT;
4625 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004626 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004627 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004628 if (remoteSSRC == 0)
4629 {
4630 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4631 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4632 " since no RTP packet has been received yet");
4633 }
4634
4635 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4636 // channel and SSRC. The SSRC is required to parse out the correct source
4637 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004638 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004639 {
4640 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4641 "GetRoundTripTimeSummary unable to retrieve RTT values"
4642 " from the RTCP layer");
4643 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4644 }
4645 else
4646 {
4647 delaysMs.min = minRTT;
4648 delaysMs.max = maxRTT;
4649 delaysMs.average = avgRTT;
4650 }
4651 return 0;
4652}
4653
4654int
4655Channel::GetNetworkStatistics(NetworkStatistics& stats)
4656{
4657 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4658 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004659 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004660 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004661 if (return_value >= 0) {
4662 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4663 }
4664 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004665}
4666
wu@webrtc.org24301a62013-12-13 19:17:43 +00004667void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4668 audio_coding_->GetDecodingCallStatistics(stats);
4669}
4670
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004671bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4672 int* playout_buffer_delay_ms) const {
4673 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004675 "Channel::GetDelayEstimate() no valid estimate.");
4676 return false;
4677 }
4678 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4679 _recPacketDelayMs;
4680 *playout_buffer_delay_ms = playout_delay_ms_;
4681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4682 "Channel::GetDelayEstimate()");
4683 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004684}
4685
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004686int Channel::SetInitialPlayoutDelay(int delay_ms)
4687{
4688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4689 "Channel::SetInitialPlayoutDelay()");
4690 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4691 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4692 {
4693 _engineStatisticsPtr->SetLastError(
4694 VE_INVALID_ARGUMENT, kTraceError,
4695 "SetInitialPlayoutDelay() invalid min delay");
4696 return -1;
4697 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004698 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004699 {
4700 _engineStatisticsPtr->SetLastError(
4701 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4702 "SetInitialPlayoutDelay() failed to set min playout delay");
4703 return -1;
4704 }
4705 return 0;
4706}
4707
4708
niklase@google.com470e71d2011-07-07 08:21:25 +00004709int
4710Channel::SetMinimumPlayoutDelay(int delayMs)
4711{
4712 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4713 "Channel::SetMinimumPlayoutDelay()");
4714 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4715 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4716 {
4717 _engineStatisticsPtr->SetLastError(
4718 VE_INVALID_ARGUMENT, kTraceError,
4719 "SetMinimumPlayoutDelay() invalid min delay");
4720 return -1;
4721 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004722 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004723 {
4724 _engineStatisticsPtr->SetLastError(
4725 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4726 "SetMinimumPlayoutDelay() failed to set min playout delay");
4727 return -1;
4728 }
4729 return 0;
4730}
4731
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004732void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4733 uint32_t playout_timestamp = 0;
4734
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004735 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004736 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4737 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4738 " timestamp from the ACM");
4739 _engineStatisticsPtr->SetLastError(
4740 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4741 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4742 return;
4743 }
4744
4745 uint16_t delay_ms = 0;
4746 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4747 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4748 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4749 " delay from the ADM");
4750 _engineStatisticsPtr->SetLastError(
4751 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4752 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4753 return;
4754 }
4755
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004756 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004757 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004758 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004759 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4760 playout_frequency = 8000;
4761 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4762 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004763 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004764 }
4765
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004766 jitter_buffer_playout_timestamp_ = playout_timestamp;
4767
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004768 // Remove the playout delay.
4769 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4770
4771 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4772 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4773 playout_timestamp);
4774
4775 if (rtcp) {
4776 playout_timestamp_rtcp_ = playout_timestamp;
4777 } else {
4778 playout_timestamp_rtp_ = playout_timestamp;
4779 }
4780 playout_delay_ms_ = delay_ms;
4781}
4782
4783int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4784 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4785 "Channel::GetPlayoutTimestamp()");
4786 if (playout_timestamp_rtp_ == 0) {
4787 _engineStatisticsPtr->SetLastError(
4788 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4789 "GetPlayoutTimestamp() failed to retrieve timestamp");
4790 return -1;
4791 }
4792 timestamp = playout_timestamp_rtp_;
4793 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4794 VoEId(_instanceId,_channelId),
4795 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4796 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004797}
4798
4799int
4800Channel::SetInitTimestamp(unsigned int timestamp)
4801{
4802 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4803 "Channel::SetInitTimestamp()");
4804 if (_sending)
4805 {
4806 _engineStatisticsPtr->SetLastError(
4807 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4808 return -1;
4809 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004810 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004811 {
4812 _engineStatisticsPtr->SetLastError(
4813 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4814 "SetInitTimestamp() failed to set timestamp");
4815 return -1;
4816 }
4817 return 0;
4818}
4819
4820int
4821Channel::SetInitSequenceNumber(short sequenceNumber)
4822{
4823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4824 "Channel::SetInitSequenceNumber()");
4825 if (_sending)
4826 {
4827 _engineStatisticsPtr->SetLastError(
4828 VE_SENDING, kTraceError,
4829 "SetInitSequenceNumber() already sending");
4830 return -1;
4831 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004832 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004833 {
4834 _engineStatisticsPtr->SetLastError(
4835 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4836 "SetInitSequenceNumber() failed to set sequence number");
4837 return -1;
4838 }
4839 return 0;
4840}
4841
4842int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004843Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004844{
4845 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4846 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004847 *rtpRtcpModule = _rtpRtcpModule.get();
4848 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004849 return 0;
4850}
4851
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004852// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4853// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004854int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004855Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004856{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004857 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004858 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004859
4860 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004861 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004862
4863 if (_inputFilePlayerPtr == NULL)
4864 {
4865 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4866 VoEId(_instanceId, _channelId),
4867 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4868 " doesnt exist");
4869 return -1;
4870 }
4871
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004872 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004873 fileSamples,
4874 mixingFrequency) == -1)
4875 {
4876 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4877 VoEId(_instanceId, _channelId),
4878 "Channel::MixOrReplaceAudioWithFile() file mixing "
4879 "failed");
4880 return -1;
4881 }
4882 if (fileSamples == 0)
4883 {
4884 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4885 VoEId(_instanceId, _channelId),
4886 "Channel::MixOrReplaceAudioWithFile() file is ended");
4887 return 0;
4888 }
4889 }
4890
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004891 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004892
4893 if (_mixFileWithMicrophone)
4894 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004895 // Currently file stream is always mono.
4896 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004897 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004898 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004899 fileBuffer.get(),
4900 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004901 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004902 }
4903 else
4904 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004905 // Replace ACM audio with file.
4906 // Currently file stream is always mono.
4907 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004908 _audioFrame.UpdateFrame(_channelId,
4909 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004910 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004911 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004912 mixingFrequency,
4913 AudioFrame::kNormalSpeech,
4914 AudioFrame::kVadUnknown,
4915 1);
4916
4917 }
4918 return 0;
4919}
4920
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004921int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004922Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004923 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004924{
4925 assert(mixingFrequency <= 32000);
4926
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004927 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004928 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004929
4930 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004931 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004932
4933 if (_outputFilePlayerPtr == NULL)
4934 {
4935 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4936 VoEId(_instanceId, _channelId),
4937 "Channel::MixAudioWithFile() file mixing failed");
4938 return -1;
4939 }
4940
4941 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004942 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004943 fileSamples,
4944 mixingFrequency) == -1)
4945 {
4946 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4947 VoEId(_instanceId, _channelId),
4948 "Channel::MixAudioWithFile() file mixing failed");
4949 return -1;
4950 }
4951 }
4952
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004953 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004954 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004955 // Currently file stream is always mono.
4956 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004957 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004958 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004959 fileBuffer.get(),
4960 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004961 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004962 }
4963 else
4964 {
4965 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004966 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004967 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004968 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004969 return -1;
4970 }
4971
4972 return 0;
4973}
4974
4975int
4976Channel::InsertInbandDtmfTone()
4977{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004978 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004979 if (_inbandDtmfQueue.PendingDtmf() &&
4980 !_inbandDtmfGenerator.IsAddingTone() &&
4981 _inbandDtmfGenerator.DelaySinceLastTone() >
4982 kMinTelephoneEventSeparationMs)
4983 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004984 int8_t eventCode(0);
4985 uint16_t lengthMs(0);
4986 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004987
4988 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4989 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4990 if (_playInbandDtmfEvent)
4991 {
4992 // Add tone to output mixer using a reduced length to minimize
4993 // risk of echo.
4994 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4995 attenuationDb);
4996 }
4997 }
4998
4999 if (_inbandDtmfGenerator.IsAddingTone())
5000 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005001 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005002 _inbandDtmfGenerator.GetSampleRate(frequency);
5003
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005004 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005005 {
5006 // Update sample rate of Dtmf tone since the mixing frequency
5007 // has changed.
5008 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005009 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005010 // Reset the tone to be added taking the new sample rate into
5011 // account.
5012 _inbandDtmfGenerator.ResetTone();
5013 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005014
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005015 int16_t toneBuffer[320];
5016 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005017 // Get 10ms tone segment and set time since last tone to zero
5018 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5019 {
5020 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5021 VoEId(_instanceId, _channelId),
5022 "Channel::EncodeAndSend() inserting Dtmf failed");
5023 return -1;
5024 }
5025
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005026 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005027 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005028 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005029 sample++)
5030 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005031 for (int channel = 0;
5032 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005033 channel++)
5034 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005035 const int index = sample * _audioFrame.num_channels_ + channel;
5036 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005037 }
5038 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005039
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005040 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005041 } else
5042 {
5043 // Add 10ms to "delay-since-last-tone" counter
5044 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5045 }
5046 return 0;
5047}
5048
niklase@google.com470e71d2011-07-07 08:21:25 +00005049void
5050Channel::ResetDeadOrAliveCounters()
5051{
5052 _countDeadDetections = 0;
5053 _countAliveDetections = 0;
5054}
5055
5056void
5057Channel::UpdateDeadOrAliveCounters(bool alive)
5058{
5059 if (alive)
5060 _countAliveDetections++;
5061 else
5062 _countDeadDetections++;
5063}
5064
5065int
5066Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5067{
niklase@google.com470e71d2011-07-07 08:21:25 +00005068 return 0;
5069}
5070
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005071int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005072Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5073{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00005074 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005075 if (_transportPtr == NULL)
5076 {
5077 return -1;
5078 }
5079 if (!RTCP)
5080 {
5081 return _transportPtr->SendPacket(_channelId, data, len);
5082 }
5083 else
5084 {
5085 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5086 }
5087}
5088
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005089// Called for incoming RTP packets after successful RTP header parsing.
5090void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5091 uint16_t sequence_number) {
5092 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5093 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5094 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005095
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005096 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005097 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005098
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005099 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005100 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005101 return;
5102 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005103
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005104 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005105 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005106
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005107 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5108 // Even though the actual sampling rate for G.722 audio is
5109 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5110 // 8,000 Hz because that value was erroneously assigned in
5111 // RFC 1890 and must remain unchanged for backward compatibility.
5112 rtp_receive_frequency = 8000;
5113 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5114 // We are resampling Opus internally to 32,000 Hz until all our
5115 // DSP routines can operate at 48,000 Hz, but the RTP clock
5116 // rate for the Opus payload format is standardized to 48,000 Hz,
5117 // because that is the maximum supported decoding sampling rate.
5118 rtp_receive_frequency = 48000;
5119 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005120
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00005121 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
5122 // every incoming packet.
5123 uint32_t timestamp_diff_ms = (rtp_timestamp -
5124 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005125
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005126 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5127 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005128
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005129 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005130
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005131 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5132 timestamp_diff_ms = 0;
5133 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005134
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005135 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005136
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005137 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5138 _recPacketDelayMs = packet_delay_ms;
5139 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005140
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005141 if (_average_jitter_buffer_delay_us == 0) {
5142 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5143 return;
5144 }
5145
5146 // Filter average delay value using exponential filter (alpha is
5147 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5148 // risk of rounding error) and compensate for it in GetDelayEstimate()
5149 // later.
5150 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5151 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005152}
5153
5154void
5155Channel::RegisterReceiveCodecsToRTPModule()
5156{
5157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5158 "Channel::RegisterReceiveCodecsToRTPModule()");
5159
5160
5161 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005162 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005163
5164 for (int idx = 0; idx < nSupportedCodecs; idx++)
5165 {
5166 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005167 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005168 (rtp_receiver_->RegisterReceivePayload(
5169 codec.plname,
5170 codec.pltype,
5171 codec.plfreq,
5172 codec.channels,
5173 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005174 {
5175 WEBRTC_TRACE(
5176 kTraceWarning,
5177 kTraceVoice,
5178 VoEId(_instanceId, _channelId),
5179 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5180 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5181 codec.plname, codec.pltype, codec.plfreq,
5182 codec.channels, codec.rate);
5183 }
5184 else
5185 {
5186 WEBRTC_TRACE(
5187 kTraceInfo,
5188 kTraceVoice,
5189 VoEId(_instanceId, _channelId),
5190 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005191 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005192 "receiver",
5193 codec.plname, codec.pltype, codec.plfreq,
5194 codec.channels, codec.rate);
5195 }
5196 }
5197}
5198
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005199int Channel::SetSecondarySendCodec(const CodecInst& codec,
5200 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005201 // Sanity check for payload type.
5202 if (red_payload_type < 0 || red_payload_type > 127) {
5203 _engineStatisticsPtr->SetLastError(
5204 VE_PLTYPE_ERROR, kTraceError,
5205 "SetRedPayloadType() invalid RED payload type");
5206 return -1;
5207 }
5208
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005209 if (SetRedPayloadType(red_payload_type) < 0) {
5210 _engineStatisticsPtr->SetLastError(
5211 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5212 "SetSecondarySendCodec() Failed to register RED ACM");
5213 return -1;
5214 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005215 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005216 _engineStatisticsPtr->SetLastError(
5217 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5218 "SetSecondarySendCodec() Failed to register secondary send codec in "
5219 "ACM");
5220 return -1;
5221 }
5222
5223 return 0;
5224}
5225
5226void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005227 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005228}
5229
5230int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005231 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005232 _engineStatisticsPtr->SetLastError(
5233 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5234 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5235 return -1;
5236 }
5237 return 0;
5238}
5239
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005240// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005241int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005242 CodecInst codec;
5243 bool found_red = false;
5244
5245 // Get default RED settings from the ACM database
5246 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5247 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005248 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005249 if (!STR_CASE_CMP(codec.plname, "RED")) {
5250 found_red = true;
5251 break;
5252 }
5253 }
5254
5255 if (!found_red) {
5256 _engineStatisticsPtr->SetLastError(
5257 VE_CODEC_ERROR, kTraceError,
5258 "SetRedPayloadType() RED is not supported");
5259 return -1;
5260 }
5261
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005262 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005263 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005264 _engineStatisticsPtr->SetLastError(
5265 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5266 "SetRedPayloadType() RED registration in ACM module failed");
5267 return -1;
5268 }
5269
5270 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5271 _engineStatisticsPtr->SetLastError(
5272 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5273 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5274 return -1;
5275 }
5276 return 0;
5277}
5278
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005279} // namespace voe
5280} // namespace webrtc