blob: 41728c74ad7cea04097ee5d45448fc6aa104d3da [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.orgead8a5b2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
wu@webrtc.org81f8df92014-06-05 20:34:08 +000013#include "webrtc/base/timeutils.h"
minyue@webrtc.org4489c512013-09-12 17:03:00 +000014#include "webrtc/common.h"
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +000015#include "webrtc/modules/audio_device/include/audio_device.h"
16#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orga5db8e32014-03-20 12:04:09 +000017#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +000018#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
19#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
21#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +000022#include "webrtc/modules/utility/interface/audio_frame_operations.h"
23#include "webrtc/modules/utility/interface/process_thread.h"
24#include "webrtc/modules/utility/interface/rtp_dump.h"
25#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
26#include "webrtc/system_wrappers/interface/logging.h"
27#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +000028#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +000029#include "webrtc/voice_engine/include/voe_base.h"
30#include "webrtc/voice_engine/include/voe_external_media.h"
31#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
32#include "webrtc/voice_engine/output_mixer.h"
33#include "webrtc/voice_engine/statistics.h"
34#include "webrtc/voice_engine/transmit_mixer.h"
35#include "webrtc/voice_engine/utility.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000036
37#if defined(_WIN32)
38#include <Qos.h>
39#endif
40
andrew@webrtc.orgd898c012012-11-14 19:07:54 +000041namespace webrtc {
42namespace voe {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000043
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +000044// Extend the default RTCP statistics struct with max_jitter, defined as the
45// maximum jitter value seen in an RTCP report block.
46struct ChannelStatistics : public RtcpStatistics {
47 ChannelStatistics() : rtcp(), max_jitter(0) {}
48
49 RtcpStatistics rtcp;
50 uint32_t max_jitter;
51};
52
53// Statistics callback, called at each generation of a new RTCP report block.
54class StatisticsProxy : public RtcpStatisticsCallback {
55 public:
56 StatisticsProxy(uint32_t ssrc)
57 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
58 ssrc_(ssrc) {}
59 virtual ~StatisticsProxy() {}
60
61 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
62 uint32_t ssrc) OVERRIDE {
63 if (ssrc != ssrc_)
64 return;
65
66 CriticalSectionScoped cs(stats_lock_.get());
67 stats_.rtcp = statistics;
68 if (statistics.jitter > stats_.max_jitter) {
69 stats_.max_jitter = statistics.jitter;
70 }
71 }
72
73 void ResetStatistics() {
74 CriticalSectionScoped cs(stats_lock_.get());
75 stats_ = ChannelStatistics();
76 }
77
78 ChannelStatistics GetStats() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 return stats_;
81 }
82
83 private:
84 // StatisticsUpdated calls are triggered from threads in the RTP module,
85 // while GetStats calls can be triggered from the public voice engine API,
86 // hence synchronization is needed.
87 scoped_ptr<CriticalSectionWrapper> stats_lock_;
88 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +000092class VoEBitrateObserver : public BitrateObserver {
93 public:
94 explicit VoEBitrateObserver(Channel* owner)
95 : owner_(owner) {}
96 virtual ~VoEBitrateObserver() {}
97
98 // Implements BitrateObserver.
99 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
100 const uint8_t fraction_lost,
101 const uint32_t rtt) OVERRIDE {
102 // |fraction_lost| has a scale of 0 - 255.
103 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
104 }
105
106 private:
107 Channel* owner_;
108};
109
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000110int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000111Channel::SendData(FrameType frameType,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000112 uint8_t payloadType,
113 uint32_t timeStamp,
114 const uint8_t* payloadData,
115 uint16_t payloadSize,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000116 const RTPFragmentationHeader* fragmentation)
117{
118 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
119 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
120 " payloadSize=%u, fragmentation=0x%x)",
121 frameType, payloadType, timeStamp, payloadSize, fragmentation);
122
123 if (_includeAudioLevelIndication)
124 {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000125 // Store current audio level in the RTP/RTCP module.
126 // The level will be used in combination with voice-activity state
127 // (frameType) to add an RTP header extension
andrew@webrtc.org3cd0f7c2014-05-05 18:22:21 +0000128 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000129 }
130
131 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
132 // packetization.
133 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
134 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
135 payloadType,
136 timeStamp,
137 // Leaving the time when this frame was
138 // received from the capture device as
139 // undefined for voice for now.
140 -1,
141 payloadData,
142 payloadSize,
143 fragmentation) == -1)
144 {
145 _engineStatisticsPtr->SetLastError(
146 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
147 "Channel::SendData() failed to send data to RTP/RTCP module");
148 return -1;
149 }
150
151 _lastLocalTimeStamp = timeStamp;
152 _lastPayloadType = payloadType;
153
154 return 0;
155}
156
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000157int32_t
158Channel::InFrameType(int16_t frameType)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000159{
160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
161 "Channel::InFrameType(frameType=%d)", frameType);
162
163 CriticalSectionScoped cs(&_callbackCritSect);
164 // 1 indicates speech
165 _sendFrameType = (frameType == 1) ? 1 : 0;
166 return 0;
167}
168
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000169int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000170Channel::OnRxVadDetected(int vadDecision)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000171{
172 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
173 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
174
175 CriticalSectionScoped cs(&_callbackCritSect);
176 if (_rxVadObserverPtr)
177 {
178 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
179 }
180
181 return 0;
182}
183
184int
185Channel::SendPacket(int channel, const void *data, int len)
186{
187 channel = VoEChannelId(channel);
188 assert(channel == _channelId);
189
190 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
191 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
192
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000193 CriticalSectionScoped cs(&_callbackCritSect);
194
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000195 if (_transportPtr == NULL)
196 {
197 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
198 "Channel::SendPacket() failed to send RTP packet due to"
199 " invalid transport object");
200 return -1;
201 }
202
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000203 uint8_t* bufferToSendPtr = (uint8_t*)data;
204 int32_t bufferLength = len;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000205
206 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000207 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000208 {
209 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
210 VoEId(_instanceId,_channelId),
211 "Channel::SendPacket() RTP dump to output file failed");
212 }
213
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000214 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
215 bufferLength);
216 if (n < 0) {
217 std::string transport_name =
218 _externalTransport ? "external transport" : "WebRtc sockets";
219 WEBRTC_TRACE(kTraceError, kTraceVoice,
220 VoEId(_instanceId,_channelId),
221 "Channel::SendPacket() RTP transmission using %s failed",
222 transport_name.c_str());
223 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000224 }
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000225 return n;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000226}
227
228int
229Channel::SendRTCPPacket(int channel, const void *data, int len)
230{
231 channel = VoEChannelId(channel);
232 assert(channel == _channelId);
233
234 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
235 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
236
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000237 CriticalSectionScoped cs(&_callbackCritSect);
238 if (_transportPtr == NULL)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000239 {
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000240 WEBRTC_TRACE(kTraceError, kTraceVoice,
241 VoEId(_instanceId,_channelId),
242 "Channel::SendRTCPPacket() failed to send RTCP packet"
243 " due to invalid transport object");
244 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000245 }
246
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000247 uint8_t* bufferToSendPtr = (uint8_t*)data;
248 int32_t bufferLength = len;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000249
250 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000251 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000252 {
253 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254 VoEId(_instanceId,_channelId),
255 "Channel::SendPacket() RTCP dump to output file failed");
256 }
257
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000258 int n = _transportPtr->SendRTCPPacket(channel,
259 bufferToSendPtr,
260 bufferLength);
261 if (n < 0) {
262 std::string transport_name =
263 _externalTransport ? "external transport" : "WebRtc sockets";
264 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
265 VoEId(_instanceId,_channelId),
266 "Channel::SendRTCPPacket() transmission using %s failed",
267 transport_name.c_str());
268 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000269 }
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000270 return n;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000271}
272
273void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000274Channel::OnPlayTelephoneEvent(int32_t id,
275 uint8_t event,
276 uint16_t lengthMs,
277 uint8_t volume)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000278{
279 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
280 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
281 " volume=%u)", id, event, lengthMs, volume);
282
283 if (!_playOutbandDtmfEvent || (event > 15))
284 {
285 // Ignore callback since feedback is disabled or event is not a
286 // Dtmf tone event.
287 return;
288 }
289
290 assert(_outputMixerPtr != NULL);
291
292 // Start playing out the Dtmf tone (if playout is enabled).
293 // Reduce length of tone with 80ms to the reduce risk of echo.
294 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
295}
296
297void
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000298Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000299{
300 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
301 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000302 id, ssrc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000303
dwkang@webrtc.orgc766a742013-08-29 07:34:12 +0000304 // Update ssrc so that NTP for AV sync can be updated.
305 _rtpRtcpModule->SetRemoteSSRC(ssrc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000306}
307
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000308void Channel::OnIncomingCSRCChanged(int32_t id,
309 uint32_t CSRC,
310 bool added)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000311{
312 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
313 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
314 id, CSRC, added);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000315}
316
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000317void Channel::ResetStatistics(uint32_t ssrc) {
318 StreamStatistician* statistician =
319 rtp_receive_statistics_->GetStatistician(ssrc);
320 if (statistician) {
321 statistician->ResetStatistics();
322 }
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000323 statistics_proxy_->ResetStatistics();
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000324}
325
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000326void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000327Channel::OnApplicationDataReceived(int32_t id,
328 uint8_t subType,
329 uint32_t name,
330 uint16_t length,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000331 const uint8_t* data)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000332{
333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
334 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
335 " name=%u, length=%u)",
336 id, subType, name, length);
337
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000338 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000339 assert(channel == _channelId);
340
341 if (_rtcpObserver)
342 {
343 CriticalSectionScoped cs(&_callbackCritSect);
344
345 if (_rtcpObserverPtr)
346 {
347 _rtcpObserverPtr->OnApplicationDataReceived(channel,
348 subType,
349 name,
350 data,
351 length);
352 }
353 }
354}
355
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000356int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000357Channel::OnInitializeDecoder(
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000358 int32_t id,
359 int8_t payloadType,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000360 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000361 int frequency,
362 uint8_t channels,
363 uint32_t rate)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
367 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
368 id, payloadType, payloadName, frequency, channels, rate);
369
370 assert(VoEChannelId(id) == _channelId);
371
372 CodecInst receiveCodec = {0};
373 CodecInst dummyCodec = {0};
374
375 receiveCodec.pltype = payloadType;
376 receiveCodec.plfreq = frequency;
377 receiveCodec.channels = channels;
378 receiveCodec.rate = rate;
379 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgd4682362013-01-22 04:44:30 +0000380
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000381 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000382 receiveCodec.pacsize = dummyCodec.pacsize;
383
384 // Register the new codec to the ACM
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000385 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000386 {
387 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
388 VoEId(_instanceId, _channelId),
389 "Channel::OnInitializeDecoder() invalid codec ("
390 "pt=%d, name=%s) received - 1", payloadType, payloadName);
391 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
392 return -1;
393 }
394
395 return 0;
396}
397
398void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000399Channel::OnPacketTimeout(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000400{
401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
402 "Channel::OnPacketTimeout(id=%d)", id);
403
404 CriticalSectionScoped cs(_callbackCritSectPtr);
405 if (_voiceEngineObserverPtr)
406 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000407 if (channel_state_.Get().receiving || _externalTransport)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000408 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000409 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000410 assert(channel == _channelId);
411 // Ensure that next OnReceivedPacket() callback will trigger
412 // a VE_PACKET_RECEIPT_RESTARTED callback.
413 _rtpPacketTimedOut = true;
414 // Deliver callback to the observer
415 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
416 VoEId(_instanceId,_channelId),
417 "Channel::OnPacketTimeout() => "
418 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
419 _voiceEngineObserverPtr->CallbackOnError(channel,
420 VE_RECEIVE_PACKET_TIMEOUT);
421 }
422 }
423}
424
425void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000426Channel::OnReceivedPacket(int32_t id,
427 RtpRtcpPacketType packetType)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000428{
429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
430 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
431 id, packetType);
432
433 assert(VoEChannelId(id) == _channelId);
434
435 // Notify only for the case when we have restarted an RTP session.
436 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
437 {
438 CriticalSectionScoped cs(_callbackCritSectPtr);
439 if (_voiceEngineObserverPtr)
440 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000441 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000442 assert(channel == _channelId);
443 // Reset timeout mechanism
444 _rtpPacketTimedOut = false;
445 // Deliver callback to the observer
446 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
447 VoEId(_instanceId,_channelId),
448 "Channel::OnPacketTimeout() =>"
449 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
450 _voiceEngineObserverPtr->CallbackOnError(
451 channel,
452 VE_PACKET_RECEIPT_RESTARTED);
453 }
454 }
455}
456
457void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000458Channel::OnPeriodicDeadOrAlive(int32_t id,
459 RTPAliveType alive)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000460{
461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
462 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
463
henrika@webrtc.org1d25eac2013-04-05 14:34:57 +0000464 {
465 CriticalSectionScoped cs(&_callbackCritSect);
466 if (!_connectionObserver)
467 return;
468 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000469
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000470 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000471 assert(channel == _channelId);
472
473 // Use Alive as default to limit risk of false Dead detections
474 bool isAlive(true);
475
476 // Always mark the connection as Dead when the module reports kRtpDead
477 if (kRtpDead == alive)
478 {
479 isAlive = false;
480 }
481
482 // It is possible that the connection is alive even if no RTP packet has
483 // been received for a long time since the other side might use VAD/DTX
484 // and a low SID-packet update rate.
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000485 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000486 {
487 // Detect Alive for all NetEQ states except for the case when we are
488 // in PLC_CNG state.
489 // PLC_CNG <=> background noise only due to long expand or error.
490 // Note that, the case where the other side stops sending during CNG
491 // state will be detected as Alive. Dead is is not set until after
492 // missing RTCP packets for at least twelve seconds (handled
493 // internally by the RTP/RTCP module).
494 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
495 }
496
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000497 // Send callback to the registered observer
498 if (_connectionObserver)
499 {
500 CriticalSectionScoped cs(&_callbackCritSect);
501 if (_connectionObserverPtr)
502 {
503 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
504 }
505 }
506}
507
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000508int32_t
509Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000510 uint16_t payloadSize,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000511 const WebRtcRTPHeader* rtpHeader)
512{
513 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
514 "Channel::OnReceivedPayloadData(payloadSize=%d,"
515 " payloadType=%u, audioChannel=%u)",
516 payloadSize,
517 rtpHeader->header.payloadType,
518 rtpHeader->type.Audio.channel);
519
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000520 if (!channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000521 {
522 // Avoid inserting into NetEQ when we are not playing. Count the
523 // packet as discarded.
524 WEBRTC_TRACE(kTraceStream, kTraceVoice,
525 VoEId(_instanceId, _channelId),
526 "received packet is discarded since playing is not"
527 " activated");
528 _numberOfDiscardedPackets++;
529 return 0;
530 }
531
532 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000533 if (audio_coding_->IncomingPacket(payloadData,
534 payloadSize,
535 *rtpHeader) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000536 {
537 _engineStatisticsPtr->SetLastError(
538 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
539 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
540 return -1;
541 }
542
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +0000543 // Update the packet delay.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000544 UpdatePacketDelay(rtpHeader->header.timestamp,
545 rtpHeader->header.sequenceNumber);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +0000546
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000547 uint16_t round_trip_time = 0;
548 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
549 NULL, NULL, NULL);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +0000550
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000551 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000552 round_trip_time);
553 if (!nack_list.empty()) {
554 // Can't use nack_list.data() since it's not supported by all
555 // compilers.
556 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +0000557 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000558 return 0;
559}
560
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +0000561bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
562 int rtp_packet_length) {
563 RTPHeader header;
564 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
565 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
566 "IncomingPacket invalid RTP header");
567 return false;
568 }
569 header.payload_type_frequency =
570 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
571 if (header.payload_type_frequency < 0)
572 return false;
573 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
574}
575
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000576int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000577{
578 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
579 "Channel::GetAudioFrame(id=%d)", id);
580
581 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000582 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
583 &audioFrame) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000584 {
585 WEBRTC_TRACE(kTraceError, kTraceVoice,
586 VoEId(_instanceId,_channelId),
587 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
588 // In all likelihood, the audio in this frame is garbage. We return an
589 // error so that the audio mixer module doesn't add it to the mix. As
590 // a result, it won't be played out and the actions skipped here are
591 // irrelevant.
592 return -1;
593 }
594
595 if (_RxVadDetection)
596 {
597 UpdateRxVadDetection(audioFrame);
598 }
599
600 // Convert module ID to internal VoE channel ID
601 audioFrame.id_ = VoEChannelId(audioFrame.id_);
602 // Store speech type for dead-or-alive detection
603 _outputSpeechType = audioFrame.speech_type_;
604
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000605 ChannelState::State state = channel_state_.Get();
606
607 if (state.rx_apm_is_enabled) {
andrew@webrtc.orge95dc252014-01-07 17:45:09 +0000608 int err = rx_audioproc_->ProcessStream(&audioFrame);
609 if (err) {
610 LOG(LS_ERROR) << "ProcessStream() error: " << err;
611 assert(false);
612 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000613 }
614
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000615 float output_gain = 1.0f;
616 float left_pan = 1.0f;
617 float right_pan = 1.0f;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000618 {
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000619 CriticalSectionScoped cs(&volume_settings_critsect_);
620 output_gain = _outputGain;
621 left_pan = _panLeft;
622 right_pan= _panRight;
623 }
624
625 // Output volume scaling
626 if (output_gain < 0.99f || output_gain > 1.01f)
627 {
628 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000629 }
630
631 // Scale left and/or right channel(s) if stereo and master balance is
632 // active
633
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000634 if (left_pan != 1.0f || right_pan != 1.0f)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000635 {
636 if (audioFrame.num_channels_ == 1)
637 {
638 // Emulate stereo mode since panning is active.
639 // The mono signal is copied to both left and right channels here.
640 AudioFrameOperations::MonoToStereo(&audioFrame);
641 }
642 // For true stereo mode (when we are receiving a stereo signal), no
643 // action is needed.
644
645 // Do the panning operation (the audio frame contains stereo at this
646 // stage)
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000647 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000648 }
649
650 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000651 if (state.output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000652 {
653 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
654 }
655
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000656 // External media
657 if (_outputExternalMedia)
658 {
659 CriticalSectionScoped cs(&_callbackCritSect);
660 const bool isStereo = (audioFrame.num_channels_ == 2);
661 if (_outputExternalMediaCallbackPtr)
662 {
663 _outputExternalMediaCallbackPtr->Process(
664 _channelId,
665 kPlaybackPerChannel,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000666 (int16_t*)audioFrame.data_,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000667 audioFrame.samples_per_channel_,
668 audioFrame.sample_rate_hz_,
669 isStereo);
670 }
671 }
672
673 // Record playout if enabled
674 {
675 CriticalSectionScoped cs(&_fileCritSect);
676
677 if (_outputFileRecording && _outputFileRecorderPtr)
678 {
679 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
680 }
681 }
682
683 // Measure audio level (0-9)
684 _outputAudioLevel.ComputeLevel(audioFrame);
685
wu@webrtc.org81f8df92014-06-05 20:34:08 +0000686 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
687 // The first frame with a valid rtp timestamp.
wu@webrtc.org22f69bd2014-05-19 17:39:11 +0000688 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org81f8df92014-06-05 20:34:08 +0000689 }
690
691 if (capture_start_rtp_time_stamp_ >= 0) {
692 // audioFrame.timestamp_ should be valid from now on.
693
694 // Compute elapsed time.
695 int64_t unwrap_timestamp =
696 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
697 audioFrame.elapsed_time_ms_ =
698 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
699 (GetPlayoutFrequency() / 1000);
700
stefan@webrtc.org237d0792014-09-02 18:58:24 +0000701 {
wu@webrtc.org22f69bd2014-05-19 17:39:11 +0000702 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org237d0792014-09-02 18:58:24 +0000703 // Compute ntp time.
704 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
705 audioFrame.timestamp_);
706 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
707 if (audioFrame.ntp_time_ms_ > 0) {
708 // Compute |capture_start_ntp_time_ms_| so that
709 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
710 capture_start_ntp_time_ms_ =
711 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
712 }
wu@webrtc.org22f69bd2014-05-19 17:39:11 +0000713 }
714 }
715
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000716 return 0;
717}
718
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000719int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000720Channel::NeededFrequency(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000721{
722 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
723 "Channel::NeededFrequency(id=%d)", id);
724
725 int highestNeeded = 0;
726
727 // Determine highest needed receive frequency
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000728 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000729
730 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000731 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000732 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000733 highestNeeded = audio_coding_->PlayoutFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000734 }
735 else
736 {
737 highestNeeded = receiveFrequency;
738 }
739
740 // Special case, if we're playing a file on the playout side
741 // we take that frequency into consideration as well
742 // This is not needed on sending side, since the codec will
743 // limit the spectrum anyway.
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000744 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000745 {
746 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000747 if (_outputFilePlayerPtr)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000748 {
749 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
750 {
751 highestNeeded=_outputFilePlayerPtr->Frequency();
752 }
753 }
754 }
755
756 return(highestNeeded);
757}
758
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000759int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000760Channel::CreateChannel(Channel*& channel,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000761 int32_t channelId,
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000762 uint32_t instanceId,
763 const Config& config)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000764{
765 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
766 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
767 channelId, instanceId);
768
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000769 channel = new Channel(channelId, instanceId, config);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000770 if (channel == NULL)
771 {
772 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
773 VoEId(instanceId,channelId),
774 "Channel::CreateChannel() unable to allocate memory for"
775 " channel");
776 return -1;
777 }
778 return 0;
779}
780
781void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000782Channel::PlayNotification(int32_t id, uint32_t durationMs)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000783{
784 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
785 "Channel::PlayNotification(id=%d, durationMs=%d)",
786 id, durationMs);
787
788 // Not implement yet
789}
790
791void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000792Channel::RecordNotification(int32_t id, uint32_t durationMs)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000793{
794 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
795 "Channel::RecordNotification(id=%d, durationMs=%d)",
796 id, durationMs);
797
798 // Not implement yet
799}
800
801void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000802Channel::PlayFileEnded(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000803{
804 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
805 "Channel::PlayFileEnded(id=%d)", id);
806
807 if (id == _inputFilePlayerId)
808 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000809 channel_state_.SetInputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000810 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
811 VoEId(_instanceId,_channelId),
812 "Channel::PlayFileEnded() => input file player module is"
813 " shutdown");
814 }
815 else if (id == _outputFilePlayerId)
816 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000817 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000818 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
819 VoEId(_instanceId,_channelId),
820 "Channel::PlayFileEnded() => output file player module is"
821 " shutdown");
822 }
823}
824
825void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000826Channel::RecordFileEnded(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000827{
828 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
829 "Channel::RecordFileEnded(id=%d)", id);
830
831 assert(id == _outputFileRecorderId);
832
833 CriticalSectionScoped cs(&_fileCritSect);
834
835 _outputFileRecording = false;
836 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
837 VoEId(_instanceId,_channelId),
838 "Channel::RecordFileEnded() => output file recorder module is"
839 " shutdown");
840}
841
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000842Channel::Channel(int32_t channelId,
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000843 uint32_t instanceId,
844 const Config& config) :
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000845 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
846 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000847 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000848 _instanceId(instanceId),
849 _channelId(channelId),
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000850 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000851 rtp_payload_registry_(
andresp@webrtc.org99681312014-04-08 11:06:12 +0000852 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000853 rtp_receive_statistics_(ReceiveStatistics::Create(
854 Clock::GetRealTimeClock())),
855 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
856 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
857 this, this, rtp_payload_registry_.get())),
858 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org6ce37202014-04-22 19:04:34 +0000859 audio_coding_(AudioCodingModule::Create(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000860 VoEModuleId(instanceId, channelId))),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000861 _rtpDumpIn(*RtpDump::CreateRtpDump()),
862 _rtpDumpOut(*RtpDump::CreateRtpDump()),
863 _outputAudioLevel(),
864 _externalTransport(false),
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000865 _audioLevel_dBov(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000866 _inputFilePlayerPtr(NULL),
867 _outputFilePlayerPtr(NULL),
868 _outputFileRecorderPtr(NULL),
869 // Avoid conflict with other channels by adding 1024 - 1026,
870 // won't use as much as 1024 channels.
871 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
872 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
873 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000874 _outputFileRecording(false),
875 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
876 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000877 _outputExternalMedia(false),
878 _inputExternalMediaCallbackPtr(NULL),
879 _outputExternalMediaCallbackPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000880 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
881 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org237d0792014-09-02 18:58:24 +0000882 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +0000883 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +0000884 playout_timestamp_rtp_(0),
885 playout_timestamp_rtcp_(0),
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000886 playout_delay_ms_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000887 _numberOfDiscardedPackets(0),
xians@webrtc.org5ce87232013-07-31 16:30:19 +0000888 send_sequence_number_(0),
wu@webrtc.org22f69bd2014-05-19 17:39:11 +0000889 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org81f8df92014-06-05 20:34:08 +0000890 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
891 capture_start_rtp_time_stamp_(-1),
wu@webrtc.org22f69bd2014-05-19 17:39:11 +0000892 capture_start_ntp_time_ms_(-1),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000893 _engineStatisticsPtr(NULL),
894 _outputMixerPtr(NULL),
895 _transmitMixerPtr(NULL),
896 _moduleProcessThreadPtr(NULL),
897 _audioDeviceModulePtr(NULL),
898 _voiceEngineObserverPtr(NULL),
899 _callbackCritSectPtr(NULL),
900 _transportPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000901 _rxVadObserverPtr(NULL),
902 _oldVadDecision(-1),
903 _sendFrameType(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000904 _rtcpObserverPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000905 _externalPlayout(false),
roosa@google.comb9e3afc2012-12-12 23:00:29 +0000906 _externalMixing(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000907 _mixFileWithMicrophone(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000908 _rtcpObserver(false),
909 _mute(false),
910 _panLeft(1.0f),
911 _panRight(1.0f),
912 _outputGain(1.0f),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000913 _playOutbandDtmfEvent(false),
914 _playInbandDtmfEvent(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000915 _lastLocalTimeStamp(0),
916 _lastPayloadType(0),
917 _includeAudioLevelIndication(false),
918 _rtpPacketTimedOut(false),
919 _rtpPacketTimeOutIsEnabled(false),
920 _rtpTimeOutSeconds(0),
921 _connectionObserver(false),
922 _connectionObserverPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000923 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +0000924 vie_network_(NULL),
925 video_channel_(-1),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +0000926 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orgd5577342013-05-22 20:39:43 +0000927 least_required_delay_ms_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000928 _previousTimestamp(0),
929 _recPacketDelayMs(20),
930 _RxVadDetection(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000931 _rxAgcIsEnabled(false),
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +0000932 _rxNsIsEnabled(false),
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +0000933 restored_packet_in_use_(false),
934 bitrate_controller_(
935 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
936 true)),
937 rtcp_bandwidth_observer_(
938 bitrate_controller_->CreateRtcpBandwidthObserver()),
minyue@webrtc.org31b38da2014-07-16 21:28:26 +0000939 send_bitrate_observer_(new VoEBitrateObserver(this)),
940 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000941{
942 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
943 "Channel::Channel() - ctor");
944 _inbandDtmfQueue.ResetDtmf();
945 _inbandDtmfGenerator.Init();
946 _outputAudioLevel.Clear();
947
948 RtpRtcp::Configuration configuration;
949 configuration.id = VoEModuleId(instanceId, channelId);
950 configuration.audio = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000951 configuration.outgoing_transport = this;
952 configuration.rtcp_feedback = this;
953 configuration.audio_messages = this;
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000954 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +0000955 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000956
957 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000958
959 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
960 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
961 statistics_proxy_.get());
aluebs@webrtc.org1a07e422014-04-16 11:58:18 +0000962
963 Config audioproc_config;
964 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
965 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000966}
967
968Channel::~Channel()
969{
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000970 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000971 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
972 "Channel::~Channel() - dtor");
973
974 if (_outputExternalMedia)
975 {
976 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
977 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000978 if (channel_state_.Get().input_external_media)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000979 {
980 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
981 }
982 StopSend();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000983 StopPlayout();
984
985 {
986 CriticalSectionScoped cs(&_fileCritSect);
987 if (_inputFilePlayerPtr)
988 {
989 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
990 _inputFilePlayerPtr->StopPlayingFile();
991 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
992 _inputFilePlayerPtr = NULL;
993 }
994 if (_outputFilePlayerPtr)
995 {
996 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
997 _outputFilePlayerPtr->StopPlayingFile();
998 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
999 _outputFilePlayerPtr = NULL;
1000 }
1001 if (_outputFileRecorderPtr)
1002 {
1003 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1004 _outputFileRecorderPtr->StopRecording();
1005 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1006 _outputFileRecorderPtr = NULL;
1007 }
1008 }
1009
1010 // The order to safely shutdown modules in a channel is:
1011 // 1. De-register callbacks in modules
1012 // 2. De-register modules in process thread
1013 // 3. Destroy modules
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001014 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001015 {
1016 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1017 VoEId(_instanceId,_channelId),
1018 "~Channel() failed to de-register transport callback"
1019 " (Audio coding module)");
1020 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001021 if (audio_coding_->RegisterVADCallback(NULL) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001022 {
1023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "~Channel() failed to de-register VAD callback"
1026 " (Audio coding module)");
1027 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001028 // De-register modules in process thread
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001029 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
1030 {
1031 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1032 VoEId(_instanceId,_channelId),
1033 "~Channel() failed to deregister RTP/RTCP module");
1034 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001035 // End of modules shutdown
1036
1037 // Delete other objects
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001038 if (vie_network_) {
1039 vie_network_->Release();
1040 vie_network_ = NULL;
1041 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001042 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1043 RtpDump::DestroyRtpDump(&_rtpDumpOut);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001044 delete &_callbackCritSect;
1045 delete &_fileCritSect;
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00001046 delete &volume_settings_critsect_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001047}
1048
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001049int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001050Channel::Init()
1051{
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1053 "Channel::Init()");
1054
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001055 channel_state_.Reset();
1056
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001057 // --- Initial sanity
1058
1059 if ((_engineStatisticsPtr == NULL) ||
1060 (_moduleProcessThreadPtr == NULL))
1061 {
1062 WEBRTC_TRACE(kTraceError, kTraceVoice,
1063 VoEId(_instanceId,_channelId),
1064 "Channel::Init() must call SetEngineInformation() first");
1065 return -1;
1066 }
1067
1068 // --- Add modules to process thread (for periodic schedulation)
1069
1070 const bool processThreadFail =
1071 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001072 false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001073 if (processThreadFail)
1074 {
1075 _engineStatisticsPtr->SetLastError(
1076 VE_CANNOT_INIT_CHANNEL, kTraceError,
1077 "Channel::Init() modules not registered");
1078 return -1;
1079 }
1080 // --- ACM initialization
1081
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001082 if ((audio_coding_->InitializeReceiver() == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001083#ifdef WEBRTC_CODEC_AVT
1084 // out-of-band Dtmf tones are played out by default
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001085 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001086#endif
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001087 (audio_coding_->InitializeSender() == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001088 {
1089 _engineStatisticsPtr->SetLastError(
1090 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1091 "Channel::Init() unable to initialize the ACM - 1");
1092 return -1;
1093 }
1094
1095 // --- RTP/RTCP module initialization
1096
1097 // Ensure that RTCP is enabled by default for the created channel.
1098 // Note that, the module will keep generating RTCP until it is explicitly
1099 // disabled by the user.
1100 // After StopListen (when no sockets exists), RTCP packets will no longer
1101 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001102 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1103 // RTCP is enabled by default.
1104 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1108 "Channel::Init() RTP/RTCP module not initialized");
1109 return -1;
1110 }
1111
1112 // --- Register all permanent callbacks
1113 const bool fail =
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001114 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1115 (audio_coding_->RegisterVADCallback(this) == -1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001116
1117 if (fail)
1118 {
1119 _engineStatisticsPtr->SetLastError(
1120 VE_CANNOT_INIT_CHANNEL, kTraceError,
1121 "Channel::Init() callbacks not registered");
1122 return -1;
1123 }
1124
1125 // --- Register all supported codecs to the receiving side of the
1126 // RTP/RTCP module
1127
1128 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001129 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001130
1131 for (int idx = 0; idx < nSupportedCodecs; idx++)
1132 {
1133 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001134 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001135 (rtp_receiver_->RegisterReceivePayload(
1136 codec.plname,
1137 codec.pltype,
1138 codec.plfreq,
1139 codec.channels,
1140 (codec.rate < 0) ? 0 : codec.rate) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001141 {
1142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1143 VoEId(_instanceId,_channelId),
1144 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1145 "to RTP/RTCP receiver",
1146 codec.plname, codec.pltype, codec.plfreq,
1147 codec.channels, codec.rate);
1148 }
1149 else
1150 {
1151 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1152 VoEId(_instanceId,_channelId),
1153 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1154 "the RTP/RTCP receiver",
1155 codec.plname, codec.pltype, codec.plfreq,
1156 codec.channels, codec.rate);
1157 }
1158
1159 // Ensure that PCMU is used as default codec on the sending side
1160 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
1161 {
1162 SetSendCodec(codec);
1163 }
1164
1165 // Register default PT for outband 'telephone-event'
1166 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1167 {
1168 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001169 (audio_coding_->RegisterReceiveCodec(codec) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001170 {
1171 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1172 VoEId(_instanceId,_channelId),
1173 "Channel::Init() failed to register outband "
1174 "'telephone-event' (%d/%d) correctly",
1175 codec.pltype, codec.plfreq);
1176 }
1177 }
1178
1179 if (!STR_CASE_CMP(codec.plname, "CN"))
1180 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001181 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1182 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001183 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
1184 {
1185 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1186 VoEId(_instanceId,_channelId),
1187 "Channel::Init() failed to register CN (%d/%d) "
1188 "correctly - 1",
1189 codec.pltype, codec.plfreq);
1190 }
1191 }
1192#ifdef WEBRTC_CODEC_RED
1193 // Register RED to the receiving side of the ACM.
1194 // We will not receive an OnInitializeDecoder() callback for RED.
1195 if (!STR_CASE_CMP(codec.plname, "RED"))
1196 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001197 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001198 {
1199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() failed to register RED (%d/%d) "
1202 "correctly",
1203 codec.pltype, codec.plfreq);
1204 }
1205 }
1206#endif
1207 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001208
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00001209 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1210 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1211 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001212 }
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00001213 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1214 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1215 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001216 }
1217
1218 return 0;
1219}
1220
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001221int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001222Channel::SetEngineInformation(Statistics& engineStatistics,
1223 OutputMixer& outputMixer,
1224 voe::TransmitMixer& transmitMixer,
1225 ProcessThread& moduleProcessThread,
1226 AudioDeviceModule& audioDeviceModule,
1227 VoiceEngineObserver* voiceEngineObserver,
1228 CriticalSectionWrapper* callbackCritSect)
1229{
1230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1231 "Channel::SetEngineInformation()");
1232 _engineStatisticsPtr = &engineStatistics;
1233 _outputMixerPtr = &outputMixer;
1234 _transmitMixerPtr = &transmitMixer,
1235 _moduleProcessThreadPtr = &moduleProcessThread;
1236 _audioDeviceModulePtr = &audioDeviceModule;
1237 _voiceEngineObserverPtr = voiceEngineObserver;
1238 _callbackCritSectPtr = callbackCritSect;
1239 return 0;
1240}
1241
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001242int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001243Channel::UpdateLocalTimeStamp()
1244{
1245
1246 _timeStamp += _audioFrame.samples_per_channel_;
1247 return 0;
1248}
1249
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001250int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001251Channel::StartPlayout()
1252{
1253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1254 "Channel::StartPlayout()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001255 if (channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001256 {
1257 return 0;
1258 }
roosa@google.comb9e3afc2012-12-12 23:00:29 +00001259
1260 if (!_externalMixing) {
1261 // Add participant as candidates for mixing.
1262 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1263 {
1264 _engineStatisticsPtr->SetLastError(
1265 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1266 "StartPlayout() failed to add participant to mixer");
1267 return -1;
1268 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001269 }
1270
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001271 channel_state_.SetPlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001272 if (RegisterFilePlayingToMixer() != 0)
1273 return -1;
1274
1275 return 0;
1276}
1277
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001278int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001279Channel::StopPlayout()
1280{
1281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1282 "Channel::StopPlayout()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001283 if (!channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001284 {
1285 return 0;
1286 }
roosa@google.comb9e3afc2012-12-12 23:00:29 +00001287
1288 if (!_externalMixing) {
1289 // Remove participant as candidates for mixing
1290 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1291 {
1292 _engineStatisticsPtr->SetLastError(
1293 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1294 "StopPlayout() failed to remove participant from mixer");
1295 return -1;
1296 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001297 }
1298
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001299 channel_state_.SetPlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001300 _outputAudioLevel.Clear();
1301
1302 return 0;
1303}
1304
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001305int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001306Channel::StartSend()
1307{
1308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1309 "Channel::StartSend()");
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001310 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001311 // This needs to be done before |sending| is set to true.
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001312 if (send_sequence_number_)
1313 SetInitSequenceNumber(send_sequence_number_);
1314
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001315 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001316 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001317 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001318 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001319 channel_state_.SetSending(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001320
1321 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
1322 {
1323 _engineStatisticsPtr->SetLastError(
1324 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1325 "StartSend() RTP/RTCP failed to start sending");
1326 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001327 channel_state_.SetSending(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001328 return -1;
1329 }
1330
1331 return 0;
1332}
1333
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001334int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001335Channel::StopSend()
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::StopSend()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001339 if (!channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001340 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001341 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001342 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001343 channel_state_.SetSending(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001344
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001345 // Store the sequence number to be able to pick up the same sequence for
1346 // the next StartSend(). This is needed for restarting device, otherwise
1347 // it might cause libSRTP to complain about packets being replayed.
1348 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1349 // CL is landed. See issue
1350 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1351 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1352
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001353 // Reset sending SSRC and sequence number and triggers direct transmission
1354 // of RTCP BYE
1355 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1356 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
1357 {
1358 _engineStatisticsPtr->SetLastError(
1359 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1360 "StartSend() RTP/RTCP failed to stop sending");
1361 }
1362
1363 return 0;
1364}
1365
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001366int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001367Channel::StartReceiving()
1368{
1369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1370 "Channel::StartReceiving()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001371 if (channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001372 {
1373 return 0;
1374 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001375 channel_state_.SetReceiving(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001376 _numberOfDiscardedPackets = 0;
1377 return 0;
1378}
1379
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001380int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001381Channel::StopReceiving()
1382{
1383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1384 "Channel::StopReceiving()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001385 if (!channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001386 {
1387 return 0;
1388 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001389
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001390 channel_state_.SetReceiving(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001391 return 0;
1392}
1393
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001394int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001395Channel::SetNetEQPlayoutMode(NetEqModes mode)
1396{
1397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1398 "Channel::SetNetEQPlayoutMode()");
1399 AudioPlayoutMode playoutMode(voice);
1400 switch (mode)
1401 {
1402 case kNetEqDefault:
1403 playoutMode = voice;
1404 break;
1405 case kNetEqStreaming:
1406 playoutMode = streaming;
1407 break;
1408 case kNetEqFax:
1409 playoutMode = fax;
1410 break;
roosa@google.com90d333e2012-12-12 21:59:14 +00001411 case kNetEqOff:
1412 playoutMode = off;
1413 break;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001414 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001415 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001416 {
1417 _engineStatisticsPtr->SetLastError(
1418 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1419 "SetNetEQPlayoutMode() failed to set playout mode");
1420 return -1;
1421 }
1422 return 0;
1423}
1424
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001425int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001426Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1427{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001428 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001429 switch (playoutMode)
1430 {
1431 case voice:
1432 mode = kNetEqDefault;
1433 break;
1434 case streaming:
1435 mode = kNetEqStreaming;
1436 break;
1437 case fax:
1438 mode = kNetEqFax;
1439 break;
roosa@google.com90d333e2012-12-12 21:59:14 +00001440 case off:
1441 mode = kNetEqOff;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001442 }
1443 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1444 VoEId(_instanceId,_channelId),
1445 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1446 return 0;
1447}
1448
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001449int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001450Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1451{
1452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1453 "Channel::RegisterVoiceEngineObserver()");
1454 CriticalSectionScoped cs(&_callbackCritSect);
1455
1456 if (_voiceEngineObserverPtr)
1457 {
1458 _engineStatisticsPtr->SetLastError(
1459 VE_INVALID_OPERATION, kTraceError,
1460 "RegisterVoiceEngineObserver() observer already enabled");
1461 return -1;
1462 }
1463 _voiceEngineObserverPtr = &observer;
1464 return 0;
1465}
1466
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001467int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001468Channel::DeRegisterVoiceEngineObserver()
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::DeRegisterVoiceEngineObserver()");
1472 CriticalSectionScoped cs(&_callbackCritSect);
1473
1474 if (!_voiceEngineObserverPtr)
1475 {
1476 _engineStatisticsPtr->SetLastError(
1477 VE_INVALID_OPERATION, kTraceWarning,
1478 "DeRegisterVoiceEngineObserver() observer already disabled");
1479 return 0;
1480 }
1481 _voiceEngineObserverPtr = NULL;
1482 return 0;
1483}
1484
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001485int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001486Channel::GetSendCodec(CodecInst& codec)
1487{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001488 return (audio_coding_->SendCodec(&codec));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001489}
1490
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001491int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001492Channel::GetRecCodec(CodecInst& codec)
1493{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001494 return (audio_coding_->ReceiveCodec(&codec));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001495}
1496
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001497int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001498Channel::SetSendCodec(const CodecInst& codec)
1499{
1500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1501 "Channel::SetSendCodec()");
1502
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001503 if (audio_coding_->RegisterSendCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001504 {
1505 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1506 "SetSendCodec() failed to register codec to ACM");
1507 return -1;
1508 }
1509
1510 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1511 {
1512 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1513 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1514 {
1515 WEBRTC_TRACE(
1516 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1517 "SetSendCodec() failed to register codec to"
1518 " RTP/RTCP module");
1519 return -1;
1520 }
1521 }
1522
1523 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
1524 {
1525 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "SetSendCodec() failed to set audio packet size");
1527 return -1;
1528 }
1529
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00001530 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1531 codec.rate, 0, 0);
1532
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001533 return 0;
1534}
1535
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00001536void
1537Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1538 const uint8_t fraction_lost, // 0 - 255.
1539 const uint32_t rtt) {
1540 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1541 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1542 bitrate_bps, fraction_lost, rtt);
minyue@webrtc.org31b38da2014-07-16 21:28:26 +00001543 // |fraction_lost| from BitrateObserver is short time observation of packet
1544 // loss rate from past. We use network predictor to make a more reasonable
1545 // loss rate estimation.
1546 network_predictor_->UpdatePacketLossRate(fraction_lost);
1547 uint8_t loss_rate = network_predictor_->GetLossRate();
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00001548 // Normalizes rate to 0 - 100.
minyue@webrtc.org31b38da2014-07-16 21:28:26 +00001549 if (audio_coding_->SetPacketLossRate(100 * loss_rate / 255) != 0) {
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00001550 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1551 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1552 assert(false); // This should not happen.
1553 }
1554}
1555
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001556int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001557Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1558{
1559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1560 "Channel::SetVADStatus(mode=%d)", mode);
1561 // To disable VAD, DTX must be disabled too
1562 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001563 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001564 {
1565 _engineStatisticsPtr->SetLastError(
1566 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1567 "SetVADStatus() failed to set VAD");
1568 return -1;
1569 }
1570 return 0;
1571}
1572
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001573int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001574Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1575{
1576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1577 "Channel::GetVADStatus");
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001578 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001579 {
1580 _engineStatisticsPtr->SetLastError(
1581 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1582 "GetVADStatus() failed to get VAD status");
1583 return -1;
1584 }
1585 disabledDTX = !disabledDTX;
1586 return 0;
1587}
1588
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001589int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001590Channel::SetRecPayloadType(const CodecInst& codec)
1591{
1592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1593 "Channel::SetRecPayloadType()");
1594
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001595 if (channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001596 {
1597 _engineStatisticsPtr->SetLastError(
1598 VE_ALREADY_PLAYING, kTraceError,
1599 "SetRecPayloadType() unable to set PT while playing");
1600 return -1;
1601 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001602 if (channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001603 {
1604 _engineStatisticsPtr->SetLastError(
1605 VE_ALREADY_LISTENING, kTraceError,
1606 "SetRecPayloadType() unable to set PT while listening");
1607 return -1;
1608 }
1609
1610 if (codec.pltype == -1)
1611 {
1612 // De-register the selected codec (RTP/RTCP module and ACM)
1613
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001614 int8_t pltype(-1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001615 CodecInst rxCodec = codec;
1616
1617 // Get payload type for the given codec
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001618 rtp_payload_registry_->ReceivePayloadType(
1619 rxCodec.plname,
1620 rxCodec.plfreq,
1621 rxCodec.channels,
1622 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1623 &pltype);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001624 rxCodec.pltype = pltype;
1625
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001626 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001627 {
1628 _engineStatisticsPtr->SetLastError(
1629 VE_RTP_RTCP_MODULE_ERROR,
1630 kTraceError,
1631 "SetRecPayloadType() RTP/RTCP-module deregistration "
1632 "failed");
1633 return -1;
1634 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001635 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001636 {
1637 _engineStatisticsPtr->SetLastError(
1638 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1639 "SetRecPayloadType() ACM deregistration failed - 1");
1640 return -1;
1641 }
1642 return 0;
1643 }
1644
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001645 if (rtp_receiver_->RegisterReceivePayload(
1646 codec.plname,
1647 codec.pltype,
1648 codec.plfreq,
1649 codec.channels,
1650 (codec.rate < 0) ? 0 : codec.rate) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001651 {
1652 // First attempt to register failed => de-register and try again
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001653 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1654 if (rtp_receiver_->RegisterReceivePayload(
1655 codec.plname,
1656 codec.pltype,
1657 codec.plfreq,
1658 codec.channels,
1659 (codec.rate < 0) ? 0 : codec.rate) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001660 {
1661 _engineStatisticsPtr->SetLastError(
1662 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1663 "SetRecPayloadType() RTP/RTCP-module registration failed");
1664 return -1;
1665 }
1666 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001667 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001668 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001669 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1670 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674 "SetRecPayloadType() ACM registration failed - 1");
1675 return -1;
1676 }
1677 }
1678 return 0;
1679}
1680
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001681int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001682Channel::GetRecPayloadType(CodecInst& codec)
1683{
1684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::GetRecPayloadType()");
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001686 int8_t payloadType(-1);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001687 if (rtp_payload_registry_->ReceivePayloadType(
1688 codec.plname,
1689 codec.plfreq,
1690 codec.channels,
1691 (codec.rate < 0) ? 0 : codec.rate,
1692 &payloadType) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001693 {
1694 _engineStatisticsPtr->SetLastError(
1695 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1696 "GetRecPayloadType() failed to retrieve RX payload type");
1697 return -1;
1698 }
1699 codec.pltype = payloadType;
1700 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1701 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1702 return 0;
1703}
1704
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001705int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001706Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1707{
1708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1709 "Channel::SetSendCNPayloadType()");
1710
1711 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001712 int32_t samplingFreqHz(-1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001713 const int kMono = 1;
1714 if (frequency == kFreq32000Hz)
1715 samplingFreqHz = 32000;
1716 else if (frequency == kFreq16000Hz)
1717 samplingFreqHz = 16000;
1718
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001719 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001720 {
1721 _engineStatisticsPtr->SetLastError(
1722 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1723 "SetSendCNPayloadType() failed to retrieve default CN codec "
1724 "settings");
1725 return -1;
1726 }
1727
1728 // Modify the payload type (must be set to dynamic range)
1729 codec.pltype = type;
1730
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001731 if (audio_coding_->RegisterSendCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001732 {
1733 _engineStatisticsPtr->SetLastError(
1734 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1735 "SetSendCNPayloadType() failed to register CN to ACM");
1736 return -1;
1737 }
1738
1739 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1740 {
1741 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1742 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1743 {
1744 _engineStatisticsPtr->SetLastError(
1745 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1746 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1747 "module");
1748 return -1;
1749 }
1750 }
1751 return 0;
1752}
1753
minyue@webrtc.orgb0aac712014-09-03 12:28:06 +00001754int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org1bfd5402014-08-12 08:13:33 +00001755 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgb0aac712014-09-03 12:28:06 +00001756 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org1bfd5402014-08-12 08:13:33 +00001757
minyue@webrtc.orgb0aac712014-09-03 12:28:06 +00001758 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org1bfd5402014-08-12 08:13:33 +00001759 _engineStatisticsPtr->SetLastError(
1760 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgb0aac712014-09-03 12:28:06 +00001761 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org1bfd5402014-08-12 08:13:33 +00001762 return -1;
1763 }
1764 return 0;
1765}
1766
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001767int32_t Channel::RegisterExternalTransport(Transport& transport)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001768{
1769 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1770 "Channel::RegisterExternalTransport()");
1771
1772 CriticalSectionScoped cs(&_callbackCritSect);
1773
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001774 if (_externalTransport)
1775 {
1776 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1777 kTraceError,
1778 "RegisterExternalTransport() external transport already enabled");
1779 return -1;
1780 }
1781 _externalTransport = true;
1782 _transportPtr = &transport;
1783 return 0;
1784}
1785
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001786int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001787Channel::DeRegisterExternalTransport()
1788{
1789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1790 "Channel::DeRegisterExternalTransport()");
1791
1792 CriticalSectionScoped cs(&_callbackCritSect);
1793
1794 if (!_transportPtr)
1795 {
1796 _engineStatisticsPtr->SetLastError(
1797 VE_INVALID_OPERATION, kTraceWarning,
1798 "DeRegisterExternalTransport() external transport already "
1799 "disabled");
1800 return 0;
1801 }
1802 _externalTransport = false;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001803 _transportPtr = NULL;
1804 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1805 "DeRegisterExternalTransport() all transport is disabled");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001806 return 0;
1807}
1808
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001809int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1810 const PacketTime& packet_time) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001811 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1812 "Channel::ReceivedRTPPacket()");
1813
1814 // Store playout timestamp for the received RTP packet
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00001815 UpdatePlayoutTimestamp(false);
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001816
1817 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001818 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1819 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001820 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1821 VoEId(_instanceId,_channelId),
1822 "Channel::SendPacket() RTP dump to input file failed");
1823 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001824 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001825 RTPHeader header;
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001826 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1827 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1828 "Incoming packet: invalid RTP header");
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001829 return -1;
1830 }
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001831 header.payload_type_frequency =
1832 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001833 if (header.payload_type_frequency < 0)
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001834 return -1;
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001835 bool in_order = IsPacketInOrder(header);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001836 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001837 IsPacketRetransmitted(header, in_order));
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001838 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001839
1840 // Forward any packets to ViE bandwidth estimator, if enabled.
1841 {
1842 CriticalSectionScoped cs(&_callbackCritSect);
1843 if (vie_network_) {
1844 int64_t arrival_time_ms;
1845 if (packet_time.timestamp != -1) {
1846 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1847 } else {
1848 arrival_time_ms = TickTime::MillisecondTimestamp();
1849 }
1850 int payload_length = length - header.headerLength;
1851 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1852 payload_length, header);
1853 }
1854 }
1855
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001856 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001857}
1858
1859bool Channel::ReceivePacket(const uint8_t* packet,
1860 int packet_length,
1861 const RTPHeader& header,
1862 bool in_order) {
1863 if (rtp_payload_registry_->IsEncapsulated(header)) {
1864 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001865 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001866 const uint8_t* payload = packet + header.headerLength;
1867 int payload_length = packet_length - header.headerLength;
1868 assert(payload_length >= 0);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001869 PayloadUnion payload_specific;
1870 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001871 &payload_specific)) {
1872 return false;
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001873 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001874 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1875 payload_specific, in_order);
1876}
1877
1878bool Channel::HandleEncapsulation(const uint8_t* packet,
1879 int packet_length,
1880 const RTPHeader& header) {
1881 if (!rtp_payload_registry_->IsRtx(header))
1882 return false;
1883
1884 // Remove the RTX header and parse the original RTP header.
1885 if (packet_length < header.headerLength)
1886 return false;
1887 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1888 return false;
1889 if (restored_packet_in_use_) {
1890 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1891 "Multiple RTX headers detected, dropping packet");
1892 return false;
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001893 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001894 uint8_t* restored_packet_ptr = restored_packet_;
1895 if (!rtp_payload_registry_->RestoreOriginalPacket(
1896 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1897 header)) {
1898 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1899 "Incoming RTX packet: invalid RTP header");
1900 return false;
1901 }
1902 restored_packet_in_use_ = true;
1903 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1904 restored_packet_in_use_ = false;
1905 return ret;
1906}
1907
1908bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1909 StreamStatistician* statistician =
1910 rtp_receive_statistics_->GetStatistician(header.ssrc);
1911 if (!statistician)
1912 return false;
1913 return statistician->IsPacketInOrder(header.sequenceNumber);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001914}
1915
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001916bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1917 bool in_order) const {
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001918 // Retransmissions are handled separately if RTX is enabled.
1919 if (rtp_payload_registry_->RtxEnabled())
1920 return false;
1921 StreamStatistician* statistician =
1922 rtp_receive_statistics_->GetStatistician(header.ssrc);
1923 if (!statistician)
1924 return false;
1925 // Check if this is a retransmission.
1926 uint16_t min_rtt = 0;
1927 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001928 return !in_order &&
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001929 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001930}
1931
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001932int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001933 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1934 "Channel::ReceivedRTCPPacket()");
1935 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00001936 UpdatePlayoutTimestamp(true);
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001937
1938 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001939 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1940 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001941 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1942 VoEId(_instanceId,_channelId),
1943 "Channel::SendPacket() RTCP dump to input file failed");
1944 }
1945
1946 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001947 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1948 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001949 _engineStatisticsPtr->SetLastError(
1950 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1951 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1952 }
wu@webrtc.org881a32d2014-05-20 22:55:01 +00001953
stefan@webrtc.org237d0792014-09-02 18:58:24 +00001954 {
1955 CriticalSectionScoped lock(ts_stats_lock_.get());
1956 ntp_estimator_.UpdateRtcpTimestamp(rtp_receiver_->SSRC(),
1957 _rtpRtcpModule.get());
1958 }
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001959 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001960}
1961
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001962int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00001963 bool loop,
1964 FileFormats format,
1965 int startPosition,
1966 float volumeScaling,
1967 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001968 const CodecInst* codecInst)
1969{
1970 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1971 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1972 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1973 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1974 startPosition, stopPosition);
1975
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001976 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001977 {
1978 _engineStatisticsPtr->SetLastError(
1979 VE_ALREADY_PLAYING, kTraceError,
1980 "StartPlayingFileLocally() is already playing");
1981 return -1;
1982 }
1983
1984 {
1985 CriticalSectionScoped cs(&_fileCritSect);
1986
1987 if (_outputFilePlayerPtr)
1988 {
1989 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1990 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1991 _outputFilePlayerPtr = NULL;
1992 }
1993
1994 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1995 _outputFilePlayerId, (const FileFormats)format);
1996
1997 if (_outputFilePlayerPtr == NULL)
1998 {
1999 _engineStatisticsPtr->SetLastError(
2000 VE_INVALID_ARGUMENT, kTraceError,
2001 "StartPlayingFileLocally() filePlayer format is not correct");
2002 return -1;
2003 }
2004
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002005 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002006
2007 if (_outputFilePlayerPtr->StartPlayingFile(
2008 fileName,
2009 loop,
2010 startPosition,
2011 volumeScaling,
2012 notificationTime,
2013 stopPosition,
2014 (const CodecInst*)codecInst) != 0)
2015 {
2016 _engineStatisticsPtr->SetLastError(
2017 VE_BAD_FILE, kTraceError,
2018 "StartPlayingFile() failed to start file playout");
2019 _outputFilePlayerPtr->StopPlayingFile();
2020 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2021 _outputFilePlayerPtr = NULL;
2022 return -1;
2023 }
2024 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002025 channel_state_.SetOutputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002026 }
2027
2028 if (RegisterFilePlayingToMixer() != 0)
2029 return -1;
2030
2031 return 0;
2032}
2033
2034int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002035 FileFormats format,
2036 int startPosition,
2037 float volumeScaling,
2038 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002039 const CodecInst* codecInst)
2040{
2041 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2042 "Channel::StartPlayingFileLocally(format=%d,"
2043 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2044 format, volumeScaling, startPosition, stopPosition);
2045
2046 if(stream == NULL)
2047 {
2048 _engineStatisticsPtr->SetLastError(
2049 VE_BAD_FILE, kTraceError,
2050 "StartPlayingFileLocally() NULL as input stream");
2051 return -1;
2052 }
2053
2054
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002055 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_ALREADY_PLAYING, kTraceError,
2059 "StartPlayingFileLocally() is already playing");
2060 return -1;
2061 }
2062
2063 {
2064 CriticalSectionScoped cs(&_fileCritSect);
2065
2066 // Destroy the old instance
2067 if (_outputFilePlayerPtr)
2068 {
2069 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2070 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2071 _outputFilePlayerPtr = NULL;
2072 }
2073
2074 // Create the instance
2075 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2076 _outputFilePlayerId,
2077 (const FileFormats)format);
2078
2079 if (_outputFilePlayerPtr == NULL)
2080 {
2081 _engineStatisticsPtr->SetLastError(
2082 VE_INVALID_ARGUMENT, kTraceError,
2083 "StartPlayingFileLocally() filePlayer format isnot correct");
2084 return -1;
2085 }
2086
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002087 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002088
2089 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2090 volumeScaling,
2091 notificationTime,
2092 stopPosition, codecInst) != 0)
2093 {
2094 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2095 "StartPlayingFile() failed to "
2096 "start file playout");
2097 _outputFilePlayerPtr->StopPlayingFile();
2098 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2099 _outputFilePlayerPtr = NULL;
2100 return -1;
2101 }
2102 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002103 channel_state_.SetOutputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002104 }
2105
2106 if (RegisterFilePlayingToMixer() != 0)
2107 return -1;
2108
2109 return 0;
2110}
2111
2112int Channel::StopPlayingFileLocally()
2113{
2114 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2115 "Channel::StopPlayingFileLocally()");
2116
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002117 if (!channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002118 {
2119 _engineStatisticsPtr->SetLastError(
2120 VE_INVALID_OPERATION, kTraceWarning,
2121 "StopPlayingFileLocally() isnot playing");
2122 return 0;
2123 }
2124
2125 {
2126 CriticalSectionScoped cs(&_fileCritSect);
2127
2128 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2129 {
2130 _engineStatisticsPtr->SetLastError(
2131 VE_STOP_RECORDING_FAILED, kTraceError,
2132 "StopPlayingFile() could not stop playing");
2133 return -1;
2134 }
2135 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2136 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2137 _outputFilePlayerPtr = NULL;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002138 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002139 }
2140 // _fileCritSect cannot be taken while calling
2141 // SetAnonymousMixibilityStatus. Refer to comments in
2142 // StartPlayingFileLocally(const char* ...) for more details.
2143 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2144 {
2145 _engineStatisticsPtr->SetLastError(
2146 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2147 "StopPlayingFile() failed to stop participant from playing as"
2148 "file in the mixer");
2149 return -1;
2150 }
2151
2152 return 0;
2153}
2154
2155int Channel::IsPlayingFileLocally() const
2156{
2157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2158 "Channel::IsPlayingFileLocally()");
2159
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002160 return channel_state_.Get().output_file_playing;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002161}
2162
2163int Channel::RegisterFilePlayingToMixer()
2164{
2165 // Return success for not registering for file playing to mixer if:
2166 // 1. playing file before playout is started on that channel.
2167 // 2. starting playout without file playing on that channel.
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002168 if (!channel_state_.Get().playing ||
2169 !channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002170 {
2171 return 0;
2172 }
2173
2174 // |_fileCritSect| cannot be taken while calling
2175 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2176 // frames can be pulled by the mixer. Since the frames are generated from
2177 // the file, _fileCritSect will be taken. This would result in a deadlock.
2178 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2179 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002180 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002181 CriticalSectionScoped cs(&_fileCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002182 _engineStatisticsPtr->SetLastError(
2183 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2184 "StartPlayingFile() failed to add participant as file to mixer");
2185 _outputFilePlayerPtr->StopPlayingFile();
2186 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2187 _outputFilePlayerPtr = NULL;
2188 return -1;
2189 }
2190
2191 return 0;
2192}
2193
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002194int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002195 bool loop,
2196 FileFormats format,
2197 int startPosition,
2198 float volumeScaling,
2199 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002200 const CodecInst* codecInst)
2201{
2202 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2203 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2204 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2205 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2206 startPosition, stopPosition);
2207
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002208 CriticalSectionScoped cs(&_fileCritSect);
2209
2210 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002211 {
2212 _engineStatisticsPtr->SetLastError(
2213 VE_ALREADY_PLAYING, kTraceWarning,
2214 "StartPlayingFileAsMicrophone() filePlayer is playing");
2215 return 0;
2216 }
2217
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002218 // Destroy the old instance
2219 if (_inputFilePlayerPtr)
2220 {
2221 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2222 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2223 _inputFilePlayerPtr = NULL;
2224 }
2225
2226 // Create the instance
2227 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2228 _inputFilePlayerId, (const FileFormats)format);
2229
2230 if (_inputFilePlayerPtr == NULL)
2231 {
2232 _engineStatisticsPtr->SetLastError(
2233 VE_INVALID_ARGUMENT, kTraceError,
2234 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2235 return -1;
2236 }
2237
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002238 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002239
2240 if (_inputFilePlayerPtr->StartPlayingFile(
2241 fileName,
2242 loop,
2243 startPosition,
2244 volumeScaling,
2245 notificationTime,
2246 stopPosition,
2247 (const CodecInst*)codecInst) != 0)
2248 {
2249 _engineStatisticsPtr->SetLastError(
2250 VE_BAD_FILE, kTraceError,
2251 "StartPlayingFile() failed to start file playout");
2252 _inputFilePlayerPtr->StopPlayingFile();
2253 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2254 _inputFilePlayerPtr = NULL;
2255 return -1;
2256 }
2257 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002258 channel_state_.SetInputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002259
2260 return 0;
2261}
2262
2263int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002264 FileFormats format,
2265 int startPosition,
2266 float volumeScaling,
2267 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002268 const CodecInst* codecInst)
2269{
2270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2271 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2272 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2273 format, volumeScaling, startPosition, stopPosition);
2274
2275 if(stream == NULL)
2276 {
2277 _engineStatisticsPtr->SetLastError(
2278 VE_BAD_FILE, kTraceError,
2279 "StartPlayingFileAsMicrophone NULL as input stream");
2280 return -1;
2281 }
2282
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002283 CriticalSectionScoped cs(&_fileCritSect);
2284
2285 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002286 {
2287 _engineStatisticsPtr->SetLastError(
2288 VE_ALREADY_PLAYING, kTraceWarning,
2289 "StartPlayingFileAsMicrophone() is playing");
2290 return 0;
2291 }
2292
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002293 // Destroy the old instance
2294 if (_inputFilePlayerPtr)
2295 {
2296 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2297 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2298 _inputFilePlayerPtr = NULL;
2299 }
2300
2301 // Create the instance
2302 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2303 _inputFilePlayerId, (const FileFormats)format);
2304
2305 if (_inputFilePlayerPtr == NULL)
2306 {
2307 _engineStatisticsPtr->SetLastError(
2308 VE_INVALID_ARGUMENT, kTraceError,
2309 "StartPlayingInputFile() filePlayer format isnot correct");
2310 return -1;
2311 }
2312
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002313 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002314
2315 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2316 volumeScaling, notificationTime,
2317 stopPosition, codecInst) != 0)
2318 {
2319 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2320 "StartPlayingFile() failed to start "
2321 "file playout");
2322 _inputFilePlayerPtr->StopPlayingFile();
2323 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2324 _inputFilePlayerPtr = NULL;
2325 return -1;
2326 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00002327
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002328 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002329 channel_state_.SetInputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002330
2331 return 0;
2332}
2333
2334int Channel::StopPlayingFileAsMicrophone()
2335{
2336 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2337 "Channel::StopPlayingFileAsMicrophone()");
2338
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002339 CriticalSectionScoped cs(&_fileCritSect);
2340
2341 if (!channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002342 {
2343 _engineStatisticsPtr->SetLastError(
2344 VE_INVALID_OPERATION, kTraceWarning,
2345 "StopPlayingFileAsMicrophone() isnot playing");
2346 return 0;
2347 }
2348
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002349 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2350 {
2351 _engineStatisticsPtr->SetLastError(
2352 VE_STOP_RECORDING_FAILED, kTraceError,
2353 "StopPlayingFile() could not stop playing");
2354 return -1;
2355 }
2356 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2357 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2358 _inputFilePlayerPtr = NULL;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002359 channel_state_.SetInputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002360
2361 return 0;
2362}
2363
2364int Channel::IsPlayingFileAsMicrophone() const
2365{
2366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2367 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002368 return channel_state_.Get().input_file_playing;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002369}
2370
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002371int Channel::StartRecordingPlayout(const char* fileName,
2372 const CodecInst* codecInst)
2373{
2374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2375 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2376
2377 if (_outputFileRecording)
2378 {
2379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2380 "StartRecordingPlayout() is already recording");
2381 return 0;
2382 }
2383
2384 FileFormats format;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002385 const uint32_t notificationTime(0); // Not supported in VoE
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002386 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2387
2388 if ((codecInst != NULL) &&
2389 ((codecInst->channels < 1) || (codecInst->channels > 2)))
2390 {
2391 _engineStatisticsPtr->SetLastError(
2392 VE_BAD_ARGUMENT, kTraceError,
2393 "StartRecordingPlayout() invalid compression");
2394 return(-1);
2395 }
2396 if(codecInst == NULL)
2397 {
2398 format = kFileFormatPcm16kHzFile;
2399 codecInst=&dummyCodec;
2400 }
2401 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2402 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2403 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2404 {
2405 format = kFileFormatWavFile;
2406 }
2407 else
2408 {
2409 format = kFileFormatCompressedFile;
2410 }
2411
2412 CriticalSectionScoped cs(&_fileCritSect);
2413
2414 // Destroy the old instance
2415 if (_outputFileRecorderPtr)
2416 {
2417 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2418 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2419 _outputFileRecorderPtr = NULL;
2420 }
2421
2422 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2423 _outputFileRecorderId, (const FileFormats)format);
2424 if (_outputFileRecorderPtr == NULL)
2425 {
2426 _engineStatisticsPtr->SetLastError(
2427 VE_INVALID_ARGUMENT, kTraceError,
2428 "StartRecordingPlayout() fileRecorder format isnot correct");
2429 return -1;
2430 }
2431
2432 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2433 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2434 {
2435 _engineStatisticsPtr->SetLastError(
2436 VE_BAD_FILE, kTraceError,
2437 "StartRecordingAudioFile() failed to start file recording");
2438 _outputFileRecorderPtr->StopRecording();
2439 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2440 _outputFileRecorderPtr = NULL;
2441 return -1;
2442 }
2443 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2444 _outputFileRecording = true;
2445
2446 return 0;
2447}
2448
2449int Channel::StartRecordingPlayout(OutStream* stream,
2450 const CodecInst* codecInst)
2451{
2452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2453 "Channel::StartRecordingPlayout()");
2454
2455 if (_outputFileRecording)
2456 {
2457 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2458 "StartRecordingPlayout() is already recording");
2459 return 0;
2460 }
2461
2462 FileFormats format;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002463 const uint32_t notificationTime(0); // Not supported in VoE
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002464 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2465
2466 if (codecInst != NULL && codecInst->channels != 1)
2467 {
2468 _engineStatisticsPtr->SetLastError(
2469 VE_BAD_ARGUMENT, kTraceError,
2470 "StartRecordingPlayout() invalid compression");
2471 return(-1);
2472 }
2473 if(codecInst == NULL)
2474 {
2475 format = kFileFormatPcm16kHzFile;
2476 codecInst=&dummyCodec;
2477 }
2478 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2479 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2480 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2481 {
2482 format = kFileFormatWavFile;
2483 }
2484 else
2485 {
2486 format = kFileFormatCompressedFile;
2487 }
2488
2489 CriticalSectionScoped cs(&_fileCritSect);
2490
2491 // Destroy the old instance
2492 if (_outputFileRecorderPtr)
2493 {
2494 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2495 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2496 _outputFileRecorderPtr = NULL;
2497 }
2498
2499 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2500 _outputFileRecorderId, (const FileFormats)format);
2501 if (_outputFileRecorderPtr == NULL)
2502 {
2503 _engineStatisticsPtr->SetLastError(
2504 VE_INVALID_ARGUMENT, kTraceError,
2505 "StartRecordingPlayout() fileRecorder format isnot correct");
2506 return -1;
2507 }
2508
2509 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2510 notificationTime) != 0)
2511 {
2512 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2513 "StartRecordingPlayout() failed to "
2514 "start file recording");
2515 _outputFileRecorderPtr->StopRecording();
2516 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2517 _outputFileRecorderPtr = NULL;
2518 return -1;
2519 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00002520
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002521 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2522 _outputFileRecording = true;
2523
2524 return 0;
2525}
2526
2527int Channel::StopRecordingPlayout()
2528{
2529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2530 "Channel::StopRecordingPlayout()");
2531
2532 if (!_outputFileRecording)
2533 {
2534 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2535 "StopRecordingPlayout() isnot recording");
2536 return -1;
2537 }
2538
2539
2540 CriticalSectionScoped cs(&_fileCritSect);
2541
2542 if (_outputFileRecorderPtr->StopRecording() != 0)
2543 {
2544 _engineStatisticsPtr->SetLastError(
2545 VE_STOP_RECORDING_FAILED, kTraceError,
2546 "StopRecording() could not stop recording");
2547 return(-1);
2548 }
2549 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2550 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2551 _outputFileRecorderPtr = NULL;
2552 _outputFileRecording = false;
2553
2554 return 0;
2555}
2556
2557void
2558Channel::SetMixWithMicStatus(bool mix)
2559{
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002560 CriticalSectionScoped cs(&_fileCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002561 _mixFileWithMicrophone=mix;
2562}
2563
2564int
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002565Channel::GetSpeechOutputLevel(uint32_t& level) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002566{
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002567 int8_t currentLevel = _outputAudioLevel.Level();
2568 level = static_cast<int32_t> (currentLevel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002569 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2570 VoEId(_instanceId,_channelId),
2571 "GetSpeechOutputLevel() => level=%u", level);
2572 return 0;
2573}
2574
2575int
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002576Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002577{
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002578 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2579 level = static_cast<int32_t> (currentLevel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002580 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2581 VoEId(_instanceId,_channelId),
2582 "GetSpeechOutputLevelFullRange() => level=%u", level);
2583 return 0;
2584}
2585
2586int
2587Channel::SetMute(bool enable)
2588{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002589 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2591 "Channel::SetMute(enable=%d)", enable);
2592 _mute = enable;
2593 return 0;
2594}
2595
2596bool
2597Channel::Mute() const
2598{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002599 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002600 return _mute;
2601}
2602
2603int
2604Channel::SetOutputVolumePan(float left, float right)
2605{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002606 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2608 "Channel::SetOutputVolumePan()");
2609 _panLeft = left;
2610 _panRight = right;
2611 return 0;
2612}
2613
2614int
2615Channel::GetOutputVolumePan(float& left, float& right) const
2616{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002617 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002618 left = _panLeft;
2619 right = _panRight;
2620 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2621 VoEId(_instanceId,_channelId),
2622 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2623 return 0;
2624}
2625
2626int
2627Channel::SetChannelOutputVolumeScaling(float scaling)
2628{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002629 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2631 "Channel::SetChannelOutputVolumeScaling()");
2632 _outputGain = scaling;
2633 return 0;
2634}
2635
2636int
2637Channel::GetChannelOutputVolumeScaling(float& scaling) const
2638{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002639 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002640 scaling = _outputGain;
2641 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2642 VoEId(_instanceId,_channelId),
2643 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2644 return 0;
2645}
2646
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002647int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00002648 int lengthMs, int attenuationDb,
2649 bool playDtmfEvent)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002650{
2651 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2652 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2653 playDtmfEvent);
2654
2655 _playOutbandDtmfEvent = playDtmfEvent;
2656
2657 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
2658 attenuationDb) != 0)
2659 {
2660 _engineStatisticsPtr->SetLastError(
2661 VE_SEND_DTMF_FAILED,
2662 kTraceWarning,
2663 "SendTelephoneEventOutband() failed to send event");
2664 return -1;
2665 }
2666 return 0;
2667}
2668
2669int Channel::SendTelephoneEventInband(unsigned char eventCode,
2670 int lengthMs,
2671 int attenuationDb,
2672 bool playDtmfEvent)
2673{
2674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2675 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2676 playDtmfEvent);
2677
2678 _playInbandDtmfEvent = playDtmfEvent;
2679 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2680
2681 return 0;
2682}
2683
2684int
2685Channel::SetDtmfPlayoutStatus(bool enable)
2686{
2687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2688 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00002689 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002690 {
2691 _engineStatisticsPtr->SetLastError(
2692 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2693 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2694 return -1;
2695 }
2696 return 0;
2697}
2698
2699bool
2700Channel::DtmfPlayoutStatus() const
2701{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00002702 return audio_coding_->DtmfPlayoutStatus();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002703}
2704
2705int
2706Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2707{
2708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2709 "Channel::SetSendTelephoneEventPayloadType()");
2710 if (type > 127)
2711 {
2712 _engineStatisticsPtr->SetLastError(
2713 VE_INVALID_ARGUMENT, kTraceError,
2714 "SetSendTelephoneEventPayloadType() invalid type");
2715 return -1;
2716 }
pbos@webrtc.org6a4acb92013-07-11 15:50:07 +00002717 CodecInst codec = {};
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002718 codec.plfreq = 8000;
2719 codec.pltype = type;
2720 memcpy(codec.plname, "telephone-event", 16);
2721 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
2722 {
henrika@webrtc.org570c4a52013-04-17 07:34:25 +00002723 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2724 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2725 _engineStatisticsPtr->SetLastError(
2726 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2727 "SetSendTelephoneEventPayloadType() failed to register send"
2728 "payload type");
2729 return -1;
2730 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002731 }
2732 _sendTelephoneEventPayloadType = type;
2733 return 0;
2734}
2735
2736int
2737Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2738{
2739 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2740 "Channel::GetSendTelephoneEventPayloadType()");
2741 type = _sendTelephoneEventPayloadType;
2742 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2743 VoEId(_instanceId,_channelId),
2744 "GetSendTelephoneEventPayloadType() => type=%u", type);
2745 return 0;
2746}
2747
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002748int
2749Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2750{
2751 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2752 "Channel::UpdateRxVadDetection()");
2753
2754 int vadDecision = 1;
2755
2756 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
2757
2758 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2759 {
2760 OnRxVadDetected(vadDecision);
2761 _oldVadDecision = vadDecision;
2762 }
2763
2764 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2765 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2766 vadDecision);
2767 return 0;
2768}
2769
2770int
2771Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2772{
2773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2774 "Channel::RegisterRxVadObserver()");
2775 CriticalSectionScoped cs(&_callbackCritSect);
2776
2777 if (_rxVadObserverPtr)
2778 {
2779 _engineStatisticsPtr->SetLastError(
2780 VE_INVALID_OPERATION, kTraceError,
2781 "RegisterRxVadObserver() observer already enabled");
2782 return -1;
2783 }
2784 _rxVadObserverPtr = &observer;
2785 _RxVadDetection = true;
2786 return 0;
2787}
2788
2789int
2790Channel::DeRegisterRxVadObserver()
2791{
2792 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2793 "Channel::DeRegisterRxVadObserver()");
2794 CriticalSectionScoped cs(&_callbackCritSect);
2795
2796 if (!_rxVadObserverPtr)
2797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_INVALID_OPERATION, kTraceWarning,
2800 "DeRegisterRxVadObserver() observer already disabled");
2801 return 0;
2802 }
2803 _rxVadObserverPtr = NULL;
2804 _RxVadDetection = false;
2805 return 0;
2806}
2807
2808int
2809Channel::VoiceActivityIndicator(int &activity)
2810{
2811 activity = _sendFrameType;
2812
2813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002814 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002815 return 0;
2816}
2817
2818#ifdef WEBRTC_VOICE_ENGINE_AGC
2819
2820int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002821Channel::SetRxAgcStatus(bool enable, AgcModes mode)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002822{
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2824 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2825 (int)enable, (int)mode);
2826
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002827 GainControl::Mode agcMode = kDefaultRxAgcMode;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002828 switch (mode)
2829 {
2830 case kAgcDefault:
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002831 break;
2832 case kAgcUnchanged:
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002833 agcMode = rx_audioproc_->gain_control()->mode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002834 break;
2835 case kAgcFixedDigital:
2836 agcMode = GainControl::kFixedDigital;
2837 break;
2838 case kAgcAdaptiveDigital:
2839 agcMode =GainControl::kAdaptiveDigital;
2840 break;
2841 default:
2842 _engineStatisticsPtr->SetLastError(
2843 VE_INVALID_ARGUMENT, kTraceError,
2844 "SetRxAgcStatus() invalid Agc mode");
2845 return -1;
2846 }
2847
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002848 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002849 {
2850 _engineStatisticsPtr->SetLastError(
2851 VE_APM_ERROR, kTraceError,
2852 "SetRxAgcStatus() failed to set Agc mode");
2853 return -1;
2854 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002855 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002856 {
2857 _engineStatisticsPtr->SetLastError(
2858 VE_APM_ERROR, kTraceError,
2859 "SetRxAgcStatus() failed to set Agc state");
2860 return -1;
2861 }
2862
2863 _rxAgcIsEnabled = enable;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002864 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002865
2866 return 0;
2867}
2868
2869int
2870Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2871{
2872 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2873 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2874
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002875 bool enable = rx_audioproc_->gain_control()->is_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002876 GainControl::Mode agcMode =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002877 rx_audioproc_->gain_control()->mode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002878
2879 enabled = enable;
2880
2881 switch (agcMode)
2882 {
2883 case GainControl::kFixedDigital:
2884 mode = kAgcFixedDigital;
2885 break;
2886 case GainControl::kAdaptiveDigital:
2887 mode = kAgcAdaptiveDigital;
2888 break;
2889 default:
2890 _engineStatisticsPtr->SetLastError(
2891 VE_APM_ERROR, kTraceError,
2892 "GetRxAgcStatus() invalid Agc mode");
2893 return -1;
2894 }
2895
2896 return 0;
2897}
2898
2899int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002900Channel::SetRxAgcConfig(AgcConfig config)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002901{
2902 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2903 "Channel::SetRxAgcConfig()");
2904
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002905 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002906 config.targetLeveldBOv) != 0)
2907 {
2908 _engineStatisticsPtr->SetLastError(
2909 VE_APM_ERROR, kTraceError,
2910 "SetRxAgcConfig() failed to set target peak |level|"
2911 "(or envelope) of the Agc");
2912 return -1;
2913 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002914 if (rx_audioproc_->gain_control()->set_compression_gain_db(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002915 config.digitalCompressionGaindB) != 0)
2916 {
2917 _engineStatisticsPtr->SetLastError(
2918 VE_APM_ERROR, kTraceError,
2919 "SetRxAgcConfig() failed to set the range in |gain| the"
2920 " digital compression stage may apply");
2921 return -1;
2922 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002923 if (rx_audioproc_->gain_control()->enable_limiter(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002924 config.limiterEnable) != 0)
2925 {
2926 _engineStatisticsPtr->SetLastError(
2927 VE_APM_ERROR, kTraceError,
2928 "SetRxAgcConfig() failed to set hard limiter to the signal");
2929 return -1;
2930 }
2931
2932 return 0;
2933}
2934
2935int
2936Channel::GetRxAgcConfig(AgcConfig& config)
2937{
2938 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2939 "Channel::GetRxAgcConfig(config=%?)");
2940
2941 config.targetLeveldBOv =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002942 rx_audioproc_->gain_control()->target_level_dbfs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002943 config.digitalCompressionGaindB =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002944 rx_audioproc_->gain_control()->compression_gain_db();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002945 config.limiterEnable =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002946 rx_audioproc_->gain_control()->is_limiter_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002947
2948 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2949 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2950 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2951 " limiterEnable=%d",
2952 config.targetLeveldBOv,
2953 config.digitalCompressionGaindB,
2954 config.limiterEnable);
2955
2956 return 0;
2957}
2958
2959#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2960
2961#ifdef WEBRTC_VOICE_ENGINE_NR
2962
2963int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002964Channel::SetRxNsStatus(bool enable, NsModes mode)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002965{
2966 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2967 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2968 (int)enable, (int)mode);
2969
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002970 NoiseSuppression::Level nsLevel = kDefaultNsMode;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002971 switch (mode)
2972 {
2973
2974 case kNsDefault:
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002975 break;
2976 case kNsUnchanged:
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002977 nsLevel = rx_audioproc_->noise_suppression()->level();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002978 break;
2979 case kNsConference:
2980 nsLevel = NoiseSuppression::kHigh;
2981 break;
2982 case kNsLowSuppression:
2983 nsLevel = NoiseSuppression::kLow;
2984 break;
2985 case kNsModerateSuppression:
2986 nsLevel = NoiseSuppression::kModerate;
2987 break;
2988 case kNsHighSuppression:
2989 nsLevel = NoiseSuppression::kHigh;
2990 break;
2991 case kNsVeryHighSuppression:
2992 nsLevel = NoiseSuppression::kVeryHigh;
2993 break;
2994 }
2995
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002996 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002997 != 0)
2998 {
2999 _engineStatisticsPtr->SetLastError(
3000 VE_APM_ERROR, kTraceError,
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00003001 "SetRxNsStatus() failed to set NS level");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003002 return -1;
3003 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003004 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003005 {
3006 _engineStatisticsPtr->SetLastError(
3007 VE_APM_ERROR, kTraceError,
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00003008 "SetRxNsStatus() failed to set NS state");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003009 return -1;
3010 }
3011
3012 _rxNsIsEnabled = enable;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003013 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003014
3015 return 0;
3016}
3017
3018int
3019Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3020{
3021 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3022 "Channel::GetRxNsStatus(enable=?, mode=?)");
3023
3024 bool enable =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003025 rx_audioproc_->noise_suppression()->is_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003026 NoiseSuppression::Level ncLevel =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003027 rx_audioproc_->noise_suppression()->level();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003028
3029 enabled = enable;
3030
3031 switch (ncLevel)
3032 {
3033 case NoiseSuppression::kLow:
3034 mode = kNsLowSuppression;
3035 break;
3036 case NoiseSuppression::kModerate:
3037 mode = kNsModerateSuppression;
3038 break;
3039 case NoiseSuppression::kHigh:
3040 mode = kNsHighSuppression;
3041 break;
3042 case NoiseSuppression::kVeryHigh:
3043 mode = kNsVeryHighSuppression;
3044 break;
3045 }
3046
3047 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3048 VoEId(_instanceId,_channelId),
3049 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3050 return 0;
3051}
3052
3053#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3054
3055int
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003056Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3057{
3058 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3059 "Channel::RegisterRTCPObserver()");
3060 CriticalSectionScoped cs(&_callbackCritSect);
3061
3062 if (_rtcpObserverPtr)
3063 {
3064 _engineStatisticsPtr->SetLastError(
3065 VE_INVALID_OPERATION, kTraceError,
3066 "RegisterRTCPObserver() observer already enabled");
3067 return -1;
3068 }
3069
3070 _rtcpObserverPtr = &observer;
3071 _rtcpObserver = true;
3072
3073 return 0;
3074}
3075
3076int
3077Channel::DeRegisterRTCPObserver()
3078{
3079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3080 "Channel::DeRegisterRTCPObserver()");
3081 CriticalSectionScoped cs(&_callbackCritSect);
3082
3083 if (!_rtcpObserverPtr)
3084 {
3085 _engineStatisticsPtr->SetLastError(
3086 VE_INVALID_OPERATION, kTraceWarning,
3087 "DeRegisterRTCPObserver() observer already disabled");
3088 return 0;
3089 }
3090
3091 _rtcpObserver = false;
3092 _rtcpObserverPtr = NULL;
3093
3094 return 0;
3095}
3096
3097int
3098Channel::SetLocalSSRC(unsigned int ssrc)
3099{
3100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3101 "Channel::SetLocalSSRC()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003102 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003103 {
3104 _engineStatisticsPtr->SetLastError(
3105 VE_ALREADY_SENDING, kTraceError,
3106 "SetLocalSSRC() already sending");
3107 return -1;
3108 }
stefan@webrtc.org903e7462014-06-05 08:25:29 +00003109 _rtpRtcpModule->SetSSRC(ssrc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003110 return 0;
3111}
3112
3113int
3114Channel::GetLocalSSRC(unsigned int& ssrc)
3115{
3116 ssrc = _rtpRtcpModule->SSRC();
3117 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3118 VoEId(_instanceId,_channelId),
3119 "GetLocalSSRC() => ssrc=%lu", ssrc);
3120 return 0;
3121}
3122
3123int
3124Channel::GetRemoteSSRC(unsigned int& ssrc)
3125{
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003126 ssrc = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003127 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3128 VoEId(_instanceId,_channelId),
3129 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3130 return 0;
3131}
3132
wu@webrtc.org9a823222014-03-06 23:49:08 +00003133int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003134 _includeAudioLevelIndication = enable;
wu@webrtc.org9a823222014-03-06 23:49:08 +00003135 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003136}
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003137
wu@webrtc.org47e54ba2014-04-24 20:33:08 +00003138int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3139 unsigned char id) {
3140 rtp_header_parser_->DeregisterRtpHeaderExtension(
3141 kRtpExtensionAudioLevel);
3142 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3143 kRtpExtensionAudioLevel, id)) {
3144 return -1;
3145 }
3146 return 0;
3147}
3148
wu@webrtc.org9a823222014-03-06 23:49:08 +00003149int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3150 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3151}
3152
3153int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3154 rtp_header_parser_->DeregisterRtpHeaderExtension(
3155 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00003156 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3157 kRtpExtensionAbsoluteSendTime, id)) {
3158 return -1;
wu@webrtc.org9a823222014-03-06 23:49:08 +00003159 }
3160 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003161}
3162
3163int
3164Channel::SetRTCPStatus(bool enable)
3165{
3166 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3167 "Channel::SetRTCPStatus()");
3168 if (_rtpRtcpModule->SetRTCPStatus(enable ?
3169 kRtcpCompound : kRtcpOff) != 0)
3170 {
3171 _engineStatisticsPtr->SetLastError(
3172 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3173 "SetRTCPStatus() failed to set RTCP status");
3174 return -1;
3175 }
3176 return 0;
3177}
3178
3179int
3180Channel::GetRTCPStatus(bool& enabled)
3181{
3182 RTCPMethod method = _rtpRtcpModule->RTCP();
3183 enabled = (method != kRtcpOff);
3184 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3185 VoEId(_instanceId,_channelId),
3186 "GetRTCPStatus() => enabled=%d", enabled);
3187 return 0;
3188}
3189
3190int
3191Channel::SetRTCP_CNAME(const char cName[256])
3192{
3193 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3194 "Channel::SetRTCP_CNAME()");
3195 if (_rtpRtcpModule->SetCNAME(cName) != 0)
3196 {
3197 _engineStatisticsPtr->SetLastError(
3198 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3199 "SetRTCP_CNAME() failed to set RTCP CNAME");
3200 return -1;
3201 }
3202 return 0;
3203}
3204
3205int
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003206Channel::GetRemoteRTCP_CNAME(char cName[256])
3207{
3208 if (cName == NULL)
3209 {
3210 _engineStatisticsPtr->SetLastError(
3211 VE_INVALID_ARGUMENT, kTraceError,
3212 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3213 return -1;
3214 }
3215 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003216 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003217 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
3218 {
3219 _engineStatisticsPtr->SetLastError(
3220 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3221 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3222 return -1;
3223 }
3224 strcpy(cName, cname);
3225 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3226 VoEId(_instanceId, _channelId),
3227 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3228 return 0;
3229}
3230
3231int
3232Channel::GetRemoteRTCPData(
3233 unsigned int& NTPHigh,
3234 unsigned int& NTPLow,
3235 unsigned int& timestamp,
3236 unsigned int& playoutTimestamp,
3237 unsigned int* jitter,
3238 unsigned short* fractionLost)
3239{
3240 // --- Information from sender info in received Sender Reports
3241
3242 RTCPSenderInfo senderInfo;
3243 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
3244 {
3245 _engineStatisticsPtr->SetLastError(
3246 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3247 "GetRemoteRTCPData() failed to retrieve sender info for remote "
3248 "side");
3249 return -1;
3250 }
3251
3252 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3253 // and octet count)
3254 NTPHigh = senderInfo.NTPseconds;
3255 NTPLow = senderInfo.NTPfraction;
3256 timestamp = senderInfo.RTPtimeStamp;
3257
3258 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3259 VoEId(_instanceId, _channelId),
3260 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3261 "timestamp=%lu",
3262 NTPHigh, NTPLow, timestamp);
3263
3264 // --- Locally derived information
3265
3266 // This value is updated on each incoming RTCP packet (0 when no packet
3267 // has been received)
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003268 playoutTimestamp = playout_timestamp_rtcp_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003269
3270 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3271 VoEId(_instanceId, _channelId),
3272 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003273 playout_timestamp_rtcp_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003274
3275 if (NULL != jitter || NULL != fractionLost)
3276 {
3277 // Get all RTCP receiver report blocks that have been received on this
3278 // channel. If we receive RTP packets from a remote source we know the
3279 // remote SSRC and use the report block from him.
3280 // Otherwise use the first report block.
3281 std::vector<RTCPReportBlock> remote_stats;
3282 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
3283 remote_stats.empty()) {
3284 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3285 VoEId(_instanceId, _channelId),
3286 "GetRemoteRTCPData() failed to measure statistics due"
3287 " to lack of received RTP and/or RTCP packets");
3288 return -1;
3289 }
3290
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003291 uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003292 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3293 for (; it != remote_stats.end(); ++it) {
3294 if (it->remoteSSRC == remoteSSRC)
3295 break;
3296 }
3297
3298 if (it == remote_stats.end()) {
3299 // If we have not received any RTCP packets from this SSRC it probably
3300 // means that we have not received any RTP packets.
3301 // Use the first received report block instead.
3302 it = remote_stats.begin();
3303 remoteSSRC = it->remoteSSRC;
3304 }
3305
3306 if (jitter) {
3307 *jitter = it->jitter;
3308 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3309 VoEId(_instanceId, _channelId),
3310 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3311 }
3312
3313 if (fractionLost) {
3314 *fractionLost = it->fractionLost;
3315 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3316 VoEId(_instanceId, _channelId),
3317 "GetRemoteRTCPData() => fractionLost = %lu",
3318 *fractionLost);
3319 }
3320 }
3321 return 0;
3322}
3323
3324int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00003325Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003326 unsigned int name,
3327 const char* data,
3328 unsigned short dataLengthInBytes)
3329{
3330 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3331 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003332 if (!channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003333 {
3334 _engineStatisticsPtr->SetLastError(
3335 VE_NOT_SENDING, kTraceError,
3336 "SendApplicationDefinedRTCPPacket() not sending");
3337 return -1;
3338 }
3339 if (NULL == data)
3340 {
3341 _engineStatisticsPtr->SetLastError(
3342 VE_INVALID_ARGUMENT, kTraceError,
3343 "SendApplicationDefinedRTCPPacket() invalid data value");
3344 return -1;
3345 }
3346 if (dataLengthInBytes % 4 != 0)
3347 {
3348 _engineStatisticsPtr->SetLastError(
3349 VE_INVALID_ARGUMENT, kTraceError,
3350 "SendApplicationDefinedRTCPPacket() invalid length value");
3351 return -1;
3352 }
3353 RTCPMethod status = _rtpRtcpModule->RTCP();
3354 if (status == kRtcpOff)
3355 {
3356 _engineStatisticsPtr->SetLastError(
3357 VE_RTCP_ERROR, kTraceError,
3358 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3359 return -1;
3360 }
3361
3362 // Create and schedule the RTCP APP packet for transmission
3363 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
3364 subType,
3365 name,
3366 (const unsigned char*) data,
3367 dataLengthInBytes) != 0)
3368 {
3369 _engineStatisticsPtr->SetLastError(
3370 VE_SEND_ERROR, kTraceError,
3371 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3372 return -1;
3373 }
3374 return 0;
3375}
3376
3377int
3378Channel::GetRTPStatistics(
3379 unsigned int& averageJitterMs,
3380 unsigned int& maxJitterMs,
3381 unsigned int& discardedPackets)
3382{
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003383 // The jitter statistics is updated for each received RTP packet and is
3384 // based on received packets.
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003385 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3386 // If RTCP is off, there is no timed thread in the RTCP module regularly
3387 // generating new stats, trigger the update manually here instead.
3388 StreamStatistician* statistician =
3389 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3390 if (statistician) {
3391 // Don't use returned statistics, use data from proxy instead so that
3392 // max jitter can be fetched atomically.
3393 RtcpStatistics s;
3394 statistician->GetStatistics(&s, true);
3395 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003396 }
3397
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003398 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003399 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003400 if (playoutFrequency > 0) {
3401 // Scale RTP statistics given the current playout frequency
3402 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3403 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003404 }
3405
3406 discardedPackets = _numberOfDiscardedPackets;
3407
3408 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3409 VoEId(_instanceId, _channelId),
3410 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
3411 " discardedPackets = %lu)",
3412 averageJitterMs, maxJitterMs, discardedPackets);
3413 return 0;
3414}
3415
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003416int Channel::GetRemoteRTCPReportBlocks(
3417 std::vector<ReportBlock>* report_blocks) {
3418 if (report_blocks == NULL) {
3419 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3420 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3421 return -1;
3422 }
3423
3424 // Get the report blocks from the latest received RTCP Sender or Receiver
3425 // Report. Each element in the vector contains the sender's SSRC and a
3426 // report block according to RFC 3550.
3427 std::vector<RTCPReportBlock> rtcp_report_blocks;
3428 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3429 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3430 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3431 return -1;
3432 }
3433
3434 if (rtcp_report_blocks.empty())
3435 return 0;
3436
3437 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3438 for (; it != rtcp_report_blocks.end(); ++it) {
3439 ReportBlock report_block;
3440 report_block.sender_SSRC = it->remoteSSRC;
3441 report_block.source_SSRC = it->sourceSSRC;
3442 report_block.fraction_lost = it->fractionLost;
3443 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3444 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3445 report_block.interarrival_jitter = it->jitter;
3446 report_block.last_SR_timestamp = it->lastSR;
3447 report_block.delay_since_last_SR = it->delaySinceLastSR;
3448 report_blocks->push_back(report_block);
3449 }
3450 return 0;
3451}
3452
3453int
3454Channel::GetRTPStatistics(CallStatistics& stats)
3455{
wu@webrtc.org22f69bd2014-05-19 17:39:11 +00003456 // --- RtcpStatistics
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003457
3458 // The jitter statistics is updated for each received RTP packet and is
3459 // based on received packets.
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003460 RtcpStatistics statistics;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00003461 StreamStatistician* statistician =
3462 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3463 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003464 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3465 _engineStatisticsPtr->SetLastError(
3466 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3467 "GetRTPStatistics() failed to read RTP statistics from the "
3468 "RTP/RTCP module");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003469 }
3470
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003471 stats.fractionLost = statistics.fraction_lost;
3472 stats.cumulativeLost = statistics.cumulative_lost;
3473 stats.extendedMax = statistics.extended_max_sequence_number;
3474 stats.jitterSamples = statistics.jitter;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003475
3476 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3477 VoEId(_instanceId, _channelId),
3478 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
3479 " extendedMax=%lu, jitterSamples=%li)",
3480 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3481 stats.jitterSamples);
3482
wu@webrtc.org22f69bd2014-05-19 17:39:11 +00003483 // --- RTT
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003484
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003485 uint16_t RTT(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003486 RTCPMethod method = _rtpRtcpModule->RTCP();
3487 if (method == kRtcpOff)
3488 {
3489 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3490 VoEId(_instanceId, _channelId),
3491 "GetRTPStatistics() RTCP is disabled => valid RTT "
3492 "measurements cannot be retrieved");
3493 } else
3494 {
3495 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003496 uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003497 if (remoteSSRC > 0)
3498 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003499 uint16_t avgRTT(0);
3500 uint16_t maxRTT(0);
3501 uint16_t minRTT(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003502
3503 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
3504 != 0)
3505 {
3506 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3507 VoEId(_instanceId, _channelId),
3508 "GetRTPStatistics() failed to retrieve RTT from "
3509 "the RTP/RTCP module");
3510 }
3511 } else
3512 {
3513 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3514 VoEId(_instanceId, _channelId),
3515 "GetRTPStatistics() failed to measure RTT since no "
3516 "RTP packets have been received yet");
3517 }
3518 }
3519
3520 stats.rttMs = static_cast<int> (RTT);
3521
3522 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3523 VoEId(_instanceId, _channelId),
3524 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3525
wu@webrtc.org22f69bd2014-05-19 17:39:11 +00003526 // --- Data counters
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003527
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003528 uint32_t bytesSent(0);
3529 uint32_t packetsSent(0);
3530 uint32_t bytesReceived(0);
3531 uint32_t packetsReceived(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003532
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00003533 if (statistician) {
3534 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3535 }
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003536
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003537 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003538 &packetsSent) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003539 {
3540 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3541 VoEId(_instanceId, _channelId),
3542 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
3543 " output will not be complete");
3544 }
3545
3546 stats.bytesSent = bytesSent;
3547 stats.packetsSent = packetsSent;
3548 stats.bytesReceived = bytesReceived;
3549 stats.packetsReceived = packetsReceived;
3550
3551 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3552 VoEId(_instanceId, _channelId),
3553 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
3554 " bytesReceived=%d, packetsReceived=%d)",
3555 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3556 stats.packetsReceived);
3557
wu@webrtc.org22f69bd2014-05-19 17:39:11 +00003558 // --- Timestamps
3559 {
3560 CriticalSectionScoped lock(ts_stats_lock_.get());
3561 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3562 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003563 return 0;
3564}
3565
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003566int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003568 "Channel::SetREDStatus()");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003569
turaj@webrtc.org040f8002013-01-31 18:20:17 +00003570 if (enable) {
3571 if (redPayloadtype < 0 || redPayloadtype > 127) {
3572 _engineStatisticsPtr->SetLastError(
3573 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003574 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org040f8002013-01-31 18:20:17 +00003575 return -1;
3576 }
3577
3578 if (SetRedPayloadType(redPayloadtype) < 0) {
3579 _engineStatisticsPtr->SetLastError(
3580 VE_CODEC_ERROR, kTraceError,
3581 "SetSecondarySendCodec() Failed to register RED ACM");
3582 return -1;
3583 }
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003584 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003585
minyue@webrtc.org91c0a252014-05-23 15:16:51 +00003586 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003587 _engineStatisticsPtr->SetLastError(
3588 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.org91c0a252014-05-23 15:16:51 +00003589 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003590 return -1;
3591 }
3592 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003593}
3594
3595int
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003596Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003597{
minyue@webrtc.org91c0a252014-05-23 15:16:51 +00003598 enabled = audio_coding_->REDStatus();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003599 if (enabled)
3600 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003601 int8_t payloadType(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003602 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
3603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003606 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003607 "module");
3608 return -1;
3609 }
3610 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3611 VoEId(_instanceId, _channelId),
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003612 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003613 enabled, redPayloadtype);
3614 return 0;
3615 }
3616 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3617 VoEId(_instanceId, _channelId),
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003618 "GetREDStatus() => enabled=%d", enabled);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003619 return 0;
3620}
3621
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00003622int Channel::SetCodecFECStatus(bool enable) {
3623 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3624 "Channel::SetCodecFECStatus()");
3625
3626 if (audio_coding_->SetCodecFEC(enable) != 0) {
3627 _engineStatisticsPtr->SetLastError(
3628 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3629 "SetCodecFECStatus() failed to set FEC state");
3630 return -1;
3631 }
3632 return 0;
3633}
3634
3635bool Channel::GetCodecFECStatus() {
3636 bool enabled = audio_coding_->CodecFEC();
3637 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3638 VoEId(_instanceId, _channelId),
3639 "GetCodecFECStatus() => enabled=%d", enabled);
3640 return enabled;
3641}
3642
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003643void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3644 // None of these functions can fail.
3645 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00003646 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3647 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003648 if (enable)
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003649 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003650 else
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003651 audio_coding_->DisableNack();
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003652}
3653
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003654// Called when we are missing one or more packets.
3655int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003656 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3657}
3658
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003659int
3660Channel::StartRTPDump(const char fileNameUTF8[1024],
3661 RTPDirections direction)
3662{
3663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3664 "Channel::StartRTPDump()");
3665 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3666 {
3667 _engineStatisticsPtr->SetLastError(
3668 VE_INVALID_ARGUMENT, kTraceError,
3669 "StartRTPDump() invalid RTP direction");
3670 return -1;
3671 }
3672 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3673 &_rtpDumpIn : &_rtpDumpOut;
3674 if (rtpDumpPtr == NULL)
3675 {
3676 assert(false);
3677 return -1;
3678 }
3679 if (rtpDumpPtr->IsActive())
3680 {
3681 rtpDumpPtr->Stop();
3682 }
3683 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3684 {
3685 _engineStatisticsPtr->SetLastError(
3686 VE_BAD_FILE, kTraceError,
3687 "StartRTPDump() failed to create file");
3688 return -1;
3689 }
3690 return 0;
3691}
3692
3693int
3694Channel::StopRTPDump(RTPDirections direction)
3695{
3696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3697 "Channel::StopRTPDump()");
3698 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3699 {
3700 _engineStatisticsPtr->SetLastError(
3701 VE_INVALID_ARGUMENT, kTraceError,
3702 "StopRTPDump() invalid RTP direction");
3703 return -1;
3704 }
3705 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3706 &_rtpDumpIn : &_rtpDumpOut;
3707 if (rtpDumpPtr == NULL)
3708 {
3709 assert(false);
3710 return -1;
3711 }
3712 if (!rtpDumpPtr->IsActive())
3713 {
3714 return 0;
3715 }
3716 return rtpDumpPtr->Stop();
3717}
3718
3719bool
3720Channel::RTPDumpIsActive(RTPDirections direction)
3721{
3722 if ((direction != kRtpIncoming) &&
3723 (direction != kRtpOutgoing))
3724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_INVALID_ARGUMENT, kTraceError,
3727 "RTPDumpIsActive() invalid RTP direction");
3728 return false;
3729 }
3730 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3731 &_rtpDumpIn : &_rtpDumpOut;
3732 return rtpDumpPtr->IsActive();
3733}
3734
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00003735void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3736 int video_channel) {
3737 CriticalSectionScoped cs(&_callbackCritSect);
3738 if (vie_network_) {
3739 vie_network_->Release();
3740 vie_network_ = NULL;
3741 }
3742 video_channel_ = -1;
3743
3744 if (vie_network != NULL && video_channel != -1) {
3745 vie_network_ = vie_network;
3746 video_channel_ = video_channel;
3747 }
3748}
3749
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003750uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003751Channel::Demultiplex(const AudioFrame& audioFrame)
3752{
3753 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3754 "Channel::Demultiplex()");
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00003755 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003756 _audioFrame.id_ = _channelId;
3757 return 0;
3758}
3759
xians@webrtc.org44f12392013-07-31 16:23:37 +00003760void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00003761 int sample_rate,
xians@webrtc.org44f12392013-07-31 16:23:37 +00003762 int number_of_frames,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00003763 int number_of_channels) {
xians@webrtc.org44f12392013-07-31 16:23:37 +00003764 CodecInst codec;
3765 GetSendCodec(codec);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003766
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00003767 if (!mono_recording_audio_.get()) {
3768 // Temporary space for DownConvertToCodecFormat.
3769 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003770 }
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00003771 DownConvertToCodecFormat(audio_data,
3772 number_of_frames,
3773 number_of_channels,
3774 sample_rate,
3775 codec.channels,
3776 codec.plfreq,
3777 mono_recording_audio_.get(),
3778 &input_resampler_,
3779 &_audioFrame);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003780}
3781
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003782uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003783Channel::PrepareEncodeAndSend(int mixingFrequency)
3784{
3785 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3786 "Channel::PrepareEncodeAndSend()");
3787
3788 if (_audioFrame.samples_per_channel_ == 0)
3789 {
3790 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3791 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.org9fbd3ec2014-07-11 19:09:59 +00003792 return 0xFFFFFFFF;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003793 }
3794
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003795 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003796 {
3797 MixOrReplaceAudioWithFile(mixingFrequency);
3798 }
3799
andrew@webrtc.org7d20dda2014-05-14 19:00:59 +00003800 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3801 if (is_muted) {
3802 AudioFrameOperations::Mute(_audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003803 }
3804
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003805 if (channel_state_.Get().input_external_media)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003806 {
3807 CriticalSectionScoped cs(&_callbackCritSect);
3808 const bool isStereo = (_audioFrame.num_channels_ == 2);
3809 if (_inputExternalMediaCallbackPtr)
3810 {
3811 _inputExternalMediaCallbackPtr->Process(
3812 _channelId,
3813 kRecordingPerChannel,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003814 (int16_t*)_audioFrame.data_,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003815 _audioFrame.samples_per_channel_,
3816 _audioFrame.sample_rate_hz_,
3817 isStereo);
3818 }
3819 }
3820
3821 InsertInbandDtmfTone();
3822
andrew@webrtc.orge95dc252014-01-07 17:45:09 +00003823 if (_includeAudioLevelIndication) {
andrew@webrtc.org3cd0f7c2014-05-05 18:22:21 +00003824 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org7d20dda2014-05-14 19:00:59 +00003825 if (is_muted) {
3826 rms_level_.ProcessMuted(length);
3827 } else {
3828 rms_level_.Process(_audioFrame.data_, length);
3829 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003830 }
3831
3832 return 0;
3833}
3834
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003835uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003836Channel::EncodeAndSend()
3837{
3838 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3839 "Channel::EncodeAndSend()");
3840
3841 assert(_audioFrame.num_channels_ <= 2);
3842 if (_audioFrame.samples_per_channel_ == 0)
3843 {
3844 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3845 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.org9fbd3ec2014-07-11 19:09:59 +00003846 return 0xFFFFFFFF;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003847 }
3848
3849 _audioFrame.id_ = _channelId;
3850
3851 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3852
3853 // The ACM resamples internally.
3854 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003855 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003856 {
3857 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3858 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.org9fbd3ec2014-07-11 19:09:59 +00003859 return 0xFFFFFFFF;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003860 }
3861
3862 _timeStamp += _audioFrame.samples_per_channel_;
3863
3864 // --- Encode if complete frame is ready
3865
3866 // This call will trigger AudioPacketizationCallback::SendData if encoding
3867 // is done and payload is ready for packetization and transmission.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003868 return audio_coding_->Process();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003869}
3870
3871int Channel::RegisterExternalMediaProcessing(
3872 ProcessingTypes type,
3873 VoEMediaProcess& processObject)
3874{
3875 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3876 "Channel::RegisterExternalMediaProcessing()");
3877
3878 CriticalSectionScoped cs(&_callbackCritSect);
3879
3880 if (kPlaybackPerChannel == type)
3881 {
3882 if (_outputExternalMediaCallbackPtr)
3883 {
3884 _engineStatisticsPtr->SetLastError(
3885 VE_INVALID_OPERATION, kTraceError,
3886 "Channel::RegisterExternalMediaProcessing() "
3887 "output external media already enabled");
3888 return -1;
3889 }
3890 _outputExternalMediaCallbackPtr = &processObject;
3891 _outputExternalMedia = true;
3892 }
3893 else if (kRecordingPerChannel == type)
3894 {
3895 if (_inputExternalMediaCallbackPtr)
3896 {
3897 _engineStatisticsPtr->SetLastError(
3898 VE_INVALID_OPERATION, kTraceError,
3899 "Channel::RegisterExternalMediaProcessing() "
3900 "output external media already enabled");
3901 return -1;
3902 }
3903 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003904 channel_state_.SetInputExternalMedia(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003905 }
3906 return 0;
3907}
3908
3909int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3910{
3911 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3912 "Channel::DeRegisterExternalMediaProcessing()");
3913
3914 CriticalSectionScoped cs(&_callbackCritSect);
3915
3916 if (kPlaybackPerChannel == type)
3917 {
3918 if (!_outputExternalMediaCallbackPtr)
3919 {
3920 _engineStatisticsPtr->SetLastError(
3921 VE_INVALID_OPERATION, kTraceWarning,
3922 "Channel::DeRegisterExternalMediaProcessing() "
3923 "output external media already disabled");
3924 return 0;
3925 }
3926 _outputExternalMedia = false;
3927 _outputExternalMediaCallbackPtr = NULL;
3928 }
3929 else if (kRecordingPerChannel == type)
3930 {
3931 if (!_inputExternalMediaCallbackPtr)
3932 {
3933 _engineStatisticsPtr->SetLastError(
3934 VE_INVALID_OPERATION, kTraceWarning,
3935 "Channel::DeRegisterExternalMediaProcessing() "
3936 "input external media already disabled");
3937 return 0;
3938 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003939 channel_state_.SetInputExternalMedia(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003940 _inputExternalMediaCallbackPtr = NULL;
3941 }
3942
3943 return 0;
3944}
3945
roosa@google.comb9e3afc2012-12-12 23:00:29 +00003946int Channel::SetExternalMixing(bool enabled) {
3947 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3948 "Channel::SetExternalMixing(enabled=%d)", enabled);
3949
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003950 if (channel_state_.Get().playing)
roosa@google.comb9e3afc2012-12-12 23:00:29 +00003951 {
3952 _engineStatisticsPtr->SetLastError(
3953 VE_INVALID_OPERATION, kTraceError,
3954 "Channel::SetExternalMixing() "
3955 "external mixing cannot be changed while playing.");
3956 return -1;
3957 }
3958
3959 _externalMixing = enabled;
3960
3961 return 0;
3962}
3963
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003964int
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003965Channel::GetNetworkStatistics(NetworkStatistics& stats)
3966{
3967 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3968 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.orge9bb4e52013-02-21 10:27:48 +00003969 ACMNetworkStatistics acm_stats;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003970 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.orge9bb4e52013-02-21 10:27:48 +00003971 if (return_value >= 0) {
3972 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3973 }
3974 return return_value;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003975}
3976
wu@webrtc.org79d6daf2013-12-13 19:17:43 +00003977void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3978 audio_coding_->GetDecodingCallStatistics(stats);
3979}
3980
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003981bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3982 int* playout_buffer_delay_ms) const {
3983 if (_average_jitter_buffer_delay_us == 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003984 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003985 "Channel::GetDelayEstimate() no valid estimate.");
3986 return false;
3987 }
3988 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3989 _recPacketDelayMs;
3990 *playout_buffer_delay_ms = playout_delay_ms_;
3991 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3992 "Channel::GetDelayEstimate()");
3993 return true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003994}
3995
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +00003996int Channel::SetInitialPlayoutDelay(int delay_ms)
3997{
3998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3999 "Channel::SetInitialPlayoutDelay()");
4000 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4001 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4002 {
4003 _engineStatisticsPtr->SetLastError(
4004 VE_INVALID_ARGUMENT, kTraceError,
4005 "SetInitialPlayoutDelay() invalid min delay");
4006 return -1;
4007 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004008 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +00004009 {
4010 _engineStatisticsPtr->SetLastError(
4011 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4012 "SetInitialPlayoutDelay() failed to set min playout delay");
4013 return -1;
4014 }
4015 return 0;
4016}
4017
4018
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004019int
4020Channel::SetMinimumPlayoutDelay(int delayMs)
4021{
4022 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4023 "Channel::SetMinimumPlayoutDelay()");
4024 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4025 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4026 {
4027 _engineStatisticsPtr->SetLastError(
4028 VE_INVALID_ARGUMENT, kTraceError,
4029 "SetMinimumPlayoutDelay() invalid min delay");
4030 return -1;
4031 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004032 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004033 {
4034 _engineStatisticsPtr->SetLastError(
4035 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4036 "SetMinimumPlayoutDelay() failed to set min playout delay");
4037 return -1;
4038 }
4039 return 0;
4040}
4041
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004042void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4043 uint32_t playout_timestamp = 0;
4044
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004045 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.orgca4bc682014-07-25 17:50:10 +00004046 // This can happen if this channel has not been received any RTP packet. In
4047 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004048 return;
4049 }
4050
4051 uint16_t delay_ms = 0;
4052 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4053 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4054 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4055 " delay from the ADM");
4056 _engineStatisticsPtr->SetLastError(
4057 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4058 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4059 return;
4060 }
4061
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +00004062 jitter_buffer_playout_timestamp_ = playout_timestamp;
4063
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004064 // Remove the playout delay.
wu@webrtc.org81f8df92014-06-05 20:34:08 +00004065 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004066
4067 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4068 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4069 playout_timestamp);
4070
4071 if (rtcp) {
4072 playout_timestamp_rtcp_ = playout_timestamp;
4073 } else {
4074 playout_timestamp_rtp_ = playout_timestamp;
4075 }
4076 playout_delay_ms_ = delay_ms;
4077}
4078
4079int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4081 "Channel::GetPlayoutTimestamp()");
4082 if (playout_timestamp_rtp_ == 0) {
4083 _engineStatisticsPtr->SetLastError(
4084 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4085 "GetPlayoutTimestamp() failed to retrieve timestamp");
4086 return -1;
4087 }
4088 timestamp = playout_timestamp_rtp_;
4089 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4090 VoEId(_instanceId,_channelId),
4091 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4092 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004093}
4094
4095int
4096Channel::SetInitTimestamp(unsigned int timestamp)
4097{
4098 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4099 "Channel::SetInitTimestamp()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004100 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004101 {
4102 _engineStatisticsPtr->SetLastError(
4103 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4104 return -1;
4105 }
4106 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
4107 {
4108 _engineStatisticsPtr->SetLastError(
4109 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4110 "SetInitTimestamp() failed to set timestamp");
4111 return -1;
4112 }
4113 return 0;
4114}
4115
4116int
4117Channel::SetInitSequenceNumber(short sequenceNumber)
4118{
4119 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4120 "Channel::SetInitSequenceNumber()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004121 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004122 {
4123 _engineStatisticsPtr->SetLastError(
4124 VE_SENDING, kTraceError,
4125 "SetInitSequenceNumber() already sending");
4126 return -1;
4127 }
4128 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
4129 {
4130 _engineStatisticsPtr->SetLastError(
4131 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4132 "SetInitSequenceNumber() failed to set sequence number");
4133 return -1;
4134 }
4135 return 0;
4136}
4137
4138int
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004139Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004140{
4141 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4142 "Channel::GetRtpRtcp()");
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004143 *rtpRtcpModule = _rtpRtcpModule.get();
4144 *rtp_receiver = rtp_receiver_.get();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004145 return 0;
4146}
4147
4148// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4149// a shared helper.
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004150int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00004151Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004152{
andrew@webrtc.orgba476162014-04-25 23:10:28 +00004153 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004154 int fileSamples(0);
4155
4156 {
4157 CriticalSectionScoped cs(&_fileCritSect);
4158
4159 if (_inputFilePlayerPtr == NULL)
4160 {
4161 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4162 VoEId(_instanceId, _channelId),
4163 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4164 " doesnt exist");
4165 return -1;
4166 }
4167
4168 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4169 fileSamples,
4170 mixingFrequency) == -1)
4171 {
4172 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4173 VoEId(_instanceId, _channelId),
4174 "Channel::MixOrReplaceAudioWithFile() file mixing "
4175 "failed");
4176 return -1;
4177 }
4178 if (fileSamples == 0)
4179 {
4180 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4181 VoEId(_instanceId, _channelId),
4182 "Channel::MixOrReplaceAudioWithFile() file is ended");
4183 return 0;
4184 }
4185 }
4186
4187 assert(_audioFrame.samples_per_channel_ == fileSamples);
4188
4189 if (_mixFileWithMicrophone)
4190 {
4191 // Currently file stream is always mono.
4192 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00004193 MixWithSat(_audioFrame.data_,
4194 _audioFrame.num_channels_,
4195 fileBuffer.get(),
4196 1,
4197 fileSamples);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004198 }
4199 else
4200 {
4201 // Replace ACM audio with file.
4202 // Currently file stream is always mono.
4203 // TODO(xians): Change the code when FilePlayer supports real stereo.
4204 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.org9fbd3ec2014-07-11 19:09:59 +00004205 0xFFFFFFFF,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004206 fileBuffer.get(),
4207 fileSamples,
4208 mixingFrequency,
4209 AudioFrame::kNormalSpeech,
4210 AudioFrame::kVadUnknown,
4211 1);
4212
4213 }
4214 return 0;
4215}
4216
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004217int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004218Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00004219 int mixingFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004220{
minyue@webrtc.orgb9ca3e22014-08-06 10:05:19 +00004221 assert(mixingFrequency <= 48000);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004222
minyue@webrtc.orgb9ca3e22014-08-06 10:05:19 +00004223 scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004224 int fileSamples(0);
4225
4226 {
4227 CriticalSectionScoped cs(&_fileCritSect);
4228
4229 if (_outputFilePlayerPtr == NULL)
4230 {
4231 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4232 VoEId(_instanceId, _channelId),
4233 "Channel::MixAudioWithFile() file mixing failed");
4234 return -1;
4235 }
4236
4237 // We should get the frequency we ask for.
4238 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4239 fileSamples,
4240 mixingFrequency) == -1)
4241 {
4242 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4243 VoEId(_instanceId, _channelId),
4244 "Channel::MixAudioWithFile() file mixing failed");
4245 return -1;
4246 }
4247 }
4248
4249 if (audioFrame.samples_per_channel_ == fileSamples)
4250 {
4251 // Currently file stream is always mono.
4252 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00004253 MixWithSat(audioFrame.data_,
4254 audioFrame.num_channels_,
4255 fileBuffer.get(),
4256 1,
4257 fileSamples);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004258 }
4259 else
4260 {
4261 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4262 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
4263 "fileSamples(%d)",
4264 audioFrame.samples_per_channel_, fileSamples);
4265 return -1;
4266 }
4267
4268 return 0;
4269}
4270
4271int
4272Channel::InsertInbandDtmfTone()
4273{
4274 // Check if we should start a new tone.
4275 if (_inbandDtmfQueue.PendingDtmf() &&
4276 !_inbandDtmfGenerator.IsAddingTone() &&
4277 _inbandDtmfGenerator.DelaySinceLastTone() >
4278 kMinTelephoneEventSeparationMs)
4279 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004280 int8_t eventCode(0);
4281 uint16_t lengthMs(0);
4282 uint8_t attenuationDb(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004283
4284 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4285 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4286 if (_playInbandDtmfEvent)
4287 {
4288 // Add tone to output mixer using a reduced length to minimize
4289 // risk of echo.
4290 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4291 attenuationDb);
4292 }
4293 }
4294
4295 if (_inbandDtmfGenerator.IsAddingTone())
4296 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004297 uint16_t frequency(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004298 _inbandDtmfGenerator.GetSampleRate(frequency);
4299
4300 if (frequency != _audioFrame.sample_rate_hz_)
4301 {
4302 // Update sample rate of Dtmf tone since the mixing frequency
4303 // has changed.
4304 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004305 (uint16_t) (_audioFrame.sample_rate_hz_));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004306 // Reset the tone to be added taking the new sample rate into
4307 // account.
4308 _inbandDtmfGenerator.ResetTone();
4309 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004310
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004311 int16_t toneBuffer[320];
4312 uint16_t toneSamples(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004313 // Get 10ms tone segment and set time since last tone to zero
4314 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4315 {
4316 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4317 VoEId(_instanceId, _channelId),
4318 "Channel::EncodeAndSend() inserting Dtmf failed");
4319 return -1;
4320 }
4321
4322 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004323 for (int sample = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004324 sample < _audioFrame.samples_per_channel_;
4325 sample++)
4326 {
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004327 for (int channel = 0;
4328 channel < _audioFrame.num_channels_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004329 channel++)
4330 {
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004331 const int index = sample * _audioFrame.num_channels_ + channel;
4332 _audioFrame.data_[index] = toneBuffer[sample];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004333 }
4334 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004335
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004336 assert(_audioFrame.samples_per_channel_ == toneSamples);
4337 } else
4338 {
4339 // Add 10ms to "delay-since-last-tone" counter
4340 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4341 }
4342 return 0;
4343}
4344
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004345int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004346Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4347{
wu@webrtc.orgb27e6702013-10-18 21:10:51 +00004348 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004349 if (_transportPtr == NULL)
4350 {
4351 return -1;
4352 }
4353 if (!RTCP)
4354 {
4355 return _transportPtr->SendPacket(_channelId, data, len);
4356 }
4357 else
4358 {
4359 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4360 }
4361}
4362
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004363// Called for incoming RTP packets after successful RTP header parsing.
4364void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4365 uint16_t sequence_number) {
4366 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4367 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4368 rtp_timestamp, sequence_number);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004369
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004370 // Get frequency of last received payload
wu@webrtc.org81f8df92014-06-05 20:34:08 +00004371 int rtp_receive_frequency = GetPlayoutFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004372
turaj@webrtc.orgd5577342013-05-22 20:39:43 +00004373 // Update the least required delay.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004374 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orgd5577342013-05-22 20:39:43 +00004375
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +00004376 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4377 // every incoming packet.
4378 uint32_t timestamp_diff_ms = (rtp_timestamp -
4379 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orga5db8e32014-03-20 12:04:09 +00004380 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4381 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4382 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4383 // timestamp, the resulting difference is negative, but is set to zero.
4384 // This can happen when a network glitch causes a packet to arrive late,
4385 // and during long comfort noise periods with clock drift.
4386 timestamp_diff_ms = 0;
4387 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004388
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004389 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4390 (rtp_receive_frequency / 1000);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004391
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004392 _previousTimestamp = rtp_timestamp;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004393
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004394 if (timestamp_diff_ms == 0) return;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004395
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004396 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4397 _recPacketDelayMs = packet_delay_ms;
4398 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004399
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004400 if (_average_jitter_buffer_delay_us == 0) {
4401 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4402 return;
4403 }
4404
4405 // Filter average delay value using exponential filter (alpha is
4406 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4407 // risk of rounding error) and compensate for it in GetDelayEstimate()
4408 // later.
4409 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4410 1000 * timestamp_diff_ms + 500) / 8;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004411}
4412
4413void
4414Channel::RegisterReceiveCodecsToRTPModule()
4415{
4416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4417 "Channel::RegisterReceiveCodecsToRTPModule()");
4418
4419
4420 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004421 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004422
4423 for (int idx = 0; idx < nSupportedCodecs; idx++)
4424 {
4425 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004426 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004427 (rtp_receiver_->RegisterReceivePayload(
4428 codec.plname,
4429 codec.pltype,
4430 codec.plfreq,
4431 codec.channels,
4432 (codec.rate < 0) ? 0 : codec.rate) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004433 {
4434 WEBRTC_TRACE(
4435 kTraceWarning,
4436 kTraceVoice,
4437 VoEId(_instanceId, _channelId),
4438 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4439 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4440 codec.plname, codec.pltype, codec.plfreq,
4441 codec.channels, codec.rate);
4442 }
4443 else
4444 {
4445 WEBRTC_TRACE(
4446 kTraceInfo,
4447 kTraceVoice,
4448 VoEId(_instanceId, _channelId),
4449 "Channel::RegisterReceiveCodecsToRTPModule() %s "
4450 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
4451 "receiver",
4452 codec.plname, codec.pltype, codec.plfreq,
4453 codec.channels, codec.rate);
4454 }
4455 }
4456}
4457
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004458int Channel::SetSecondarySendCodec(const CodecInst& codec,
4459 int red_payload_type) {
turaj@webrtc.org040f8002013-01-31 18:20:17 +00004460 // Sanity check for payload type.
4461 if (red_payload_type < 0 || red_payload_type > 127) {
4462 _engineStatisticsPtr->SetLastError(
4463 VE_PLTYPE_ERROR, kTraceError,
4464 "SetRedPayloadType() invalid RED payload type");
4465 return -1;
4466 }
4467
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004468 if (SetRedPayloadType(red_payload_type) < 0) {
4469 _engineStatisticsPtr->SetLastError(
4470 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4471 "SetSecondarySendCodec() Failed to register RED ACM");
4472 return -1;
4473 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004474 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004475 _engineStatisticsPtr->SetLastError(
4476 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4477 "SetSecondarySendCodec() Failed to register secondary send codec in "
4478 "ACM");
4479 return -1;
4480 }
4481
4482 return 0;
4483}
4484
4485void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004486 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004487}
4488
4489int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004490 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004491 _engineStatisticsPtr->SetLastError(
4492 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4493 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4494 return -1;
4495 }
4496 return 0;
4497}
4498
turaj@webrtc.org040f8002013-01-31 18:20:17 +00004499// Assuming this method is called with valid payload type.
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004500int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004501 CodecInst codec;
4502 bool found_red = false;
4503
4504 // Get default RED settings from the ACM database
4505 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4506 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004507 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004508 if (!STR_CASE_CMP(codec.plname, "RED")) {
4509 found_red = true;
4510 break;
4511 }
4512 }
4513
4514 if (!found_red) {
4515 _engineStatisticsPtr->SetLastError(
4516 VE_CODEC_ERROR, kTraceError,
4517 "SetRedPayloadType() RED is not supported");
4518 return -1;
4519 }
4520
turaj@webrtc.org2344ebe2013-01-31 18:34:19 +00004521 codec.pltype = red_payload_type;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004522 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004523 _engineStatisticsPtr->SetLastError(
4524 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4525 "SetRedPayloadType() RED registration in ACM module failed");
4526 return -1;
4527 }
4528
4529 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4530 _engineStatisticsPtr->SetLastError(
4531 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4532 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4533 return -1;
4534 }
4535 return 0;
4536}
4537
wu@webrtc.org9a823222014-03-06 23:49:08 +00004538int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4539 unsigned char id) {
4540 int error = 0;
4541 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4542 if (enable) {
4543 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4544 }
4545 return error;
4546}
minyue@webrtc.orgdd671de2014-05-28 09:52:06 +00004547
wu@webrtc.org81f8df92014-06-05 20:34:08 +00004548int32_t Channel::GetPlayoutFrequency() {
4549 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4550 CodecInst current_recive_codec;
4551 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4552 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4553 // Even though the actual sampling rate for G.722 audio is
4554 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4555 // 8,000 Hz because that value was erroneously assigned in
4556 // RFC 1890 and must remain unchanged for backward compatibility.
4557 playout_frequency = 8000;
4558 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4559 // We are resampling Opus internally to 32,000 Hz until all our
4560 // DSP routines can operate at 48,000 Hz, but the RTP clock
4561 // rate for the Opus payload format is standardized to 48,000 Hz,
4562 // because that is the maximum supported decoding sampling rate.
4563 playout_frequency = 48000;
4564 }
4565 }
4566 return playout_frequency;
4567}
4568
pbos@webrtc.org3b89e102013-07-03 15:12:26 +00004569} // namespace voe
4570} // namespace webrtc