blob: 91167c0cf11a634dacfe8a2e91fb3feb19e9b786 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000013#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000014#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000015#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000016#include "webrtc/modules/audio_device/include/audio_device.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000018#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000019#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
21#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
22#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000023#include "webrtc/modules/utility/interface/audio_frame_operations.h"
24#include "webrtc/modules/utility/interface/process_thread.h"
25#include "webrtc/modules/utility/interface/rtp_dump.h"
26#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/logging.h"
28#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000029#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000030#include "webrtc/voice_engine/include/voe_base.h"
31#include "webrtc/voice_engine/include/voe_external_media.h"
32#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
33#include "webrtc/voice_engine/output_mixer.h"
34#include "webrtc/voice_engine/statistics.h"
35#include "webrtc/voice_engine/transmit_mixer.h"
36#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000037
38#if defined(_WIN32)
39#include <Qos.h>
40#endif
41
andrew@webrtc.org50419b02012-11-14 19:07:54 +000042namespace webrtc {
43namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000044
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000045// Extend the default RTCP statistics struct with max_jitter, defined as the
46// maximum jitter value seen in an RTCP report block.
47struct ChannelStatistics : public RtcpStatistics {
48 ChannelStatistics() : rtcp(), max_jitter(0) {}
49
50 RtcpStatistics rtcp;
51 uint32_t max_jitter;
52};
53
54// Statistics callback, called at each generation of a new RTCP report block.
55class StatisticsProxy : public RtcpStatisticsCallback {
56 public:
57 StatisticsProxy(uint32_t ssrc)
58 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
59 ssrc_(ssrc) {}
60 virtual ~StatisticsProxy() {}
61
62 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
63 uint32_t ssrc) OVERRIDE {
64 if (ssrc != ssrc_)
65 return;
66
67 CriticalSectionScoped cs(stats_lock_.get());
68 stats_.rtcp = statistics;
69 if (statistics.jitter > stats_.max_jitter) {
70 stats_.max_jitter = statistics.jitter;
71 }
72 }
73
74 void ResetStatistics() {
75 CriticalSectionScoped cs(stats_lock_.get());
76 stats_ = ChannelStatistics();
77 }
78
79 ChannelStatistics GetStats() {
80 CriticalSectionScoped cs(stats_lock_.get());
81 return stats_;
82 }
83
84 private:
85 // StatisticsUpdated calls are triggered from threads in the RTP module,
86 // while GetStats calls can be triggered from the public voice engine API,
87 // hence synchronization is needed.
88 scoped_ptr<CriticalSectionWrapper> stats_lock_;
89 const uint32_t ssrc_;
90 ChannelStatistics stats_;
91};
92
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000093class VoEBitrateObserver : public BitrateObserver {
94 public:
95 explicit VoEBitrateObserver(Channel* owner)
96 : owner_(owner) {}
97 virtual ~VoEBitrateObserver() {}
98
99 // Implements BitrateObserver.
100 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
101 const uint8_t fraction_lost,
102 const uint32_t rtt) OVERRIDE {
103 // |fraction_lost| has a scale of 0 - 255.
104 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
105 }
106
107 private:
108 Channel* owner_;
109};
110
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000111int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000112Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000113 uint8_t payloadType,
114 uint32_t timeStamp,
115 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000116 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 const RTPFragmentationHeader* fragmentation)
118{
119 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
120 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000121 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
122 frameType, payloadType, timeStamp,
123 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000124
125 if (_includeAudioLevelIndication)
126 {
127 // Store current audio level in the RTP/RTCP module.
128 // The level will be used in combination with voice-activity state
129 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000130 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 }
132
133 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
134 // packetization.
135 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000136 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 payloadType,
138 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000139 // Leaving the time when this frame was
140 // received from the capture device as
141 // undefined for voice for now.
142 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 payloadData,
144 payloadSize,
145 fragmentation) == -1)
146 {
147 _engineStatisticsPtr->SetLastError(
148 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
149 "Channel::SendData() failed to send data to RTP/RTCP module");
150 return -1;
151 }
152
153 _lastLocalTimeStamp = timeStamp;
154 _lastPayloadType = payloadType;
155
156 return 0;
157}
158
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000159int32_t
160Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000161{
162 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
163 "Channel::InFrameType(frameType=%d)", frameType);
164
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000165 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 // 1 indicates speech
167 _sendFrameType = (frameType == 1) ? 1 : 0;
168 return 0;
169}
170
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000171int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000172Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000173{
174 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
175 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
176
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000177 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 if (_rxVadObserverPtr)
179 {
180 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
181 }
182
183 return 0;
184}
185
186int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000187Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000188{
189 channel = VoEChannelId(channel);
190 assert(channel == _channelId);
191
192 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000193 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
194 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000195
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000196 CriticalSectionScoped cs(&_callbackCritSect);
197
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 if (_transportPtr == NULL)
199 {
200 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
201 "Channel::SendPacket() failed to send RTP packet due to"
202 " invalid transport object");
203 return -1;
204 }
205
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000206 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000207 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208
209 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000210 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 {
212 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
213 VoEId(_instanceId,_channelId),
214 "Channel::SendPacket() RTP dump to output file failed");
215 }
216
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000217 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
218 bufferLength);
219 if (n < 0) {
220 std::string transport_name =
221 _externalTransport ? "external transport" : "WebRtc sockets";
222 WEBRTC_TRACE(kTraceError, kTraceVoice,
223 VoEId(_instanceId,_channelId),
224 "Channel::SendPacket() RTP transmission using %s failed",
225 transport_name.c_str());
226 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000228 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000229}
230
231int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000232Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000233{
234 channel = VoEChannelId(channel);
235 assert(channel == _channelId);
236
237 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000238 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
239 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000240
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000241 CriticalSectionScoped cs(&_callbackCritSect);
242 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000243 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000244 WEBRTC_TRACE(kTraceError, kTraceVoice,
245 VoEId(_instanceId,_channelId),
246 "Channel::SendRTCPPacket() failed to send RTCP packet"
247 " due to invalid transport object");
248 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249 }
250
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000252 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
254 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000255 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
257 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
258 VoEId(_instanceId,_channelId),
259 "Channel::SendPacket() RTCP dump to output file failed");
260 }
261
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000262 int n = _transportPtr->SendRTCPPacket(channel,
263 bufferToSendPtr,
264 bufferLength);
265 if (n < 0) {
266 std::string transport_name =
267 _externalTransport ? "external transport" : "WebRtc sockets";
268 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
269 VoEId(_instanceId,_channelId),
270 "Channel::SendRTCPPacket() transmission using %s failed",
271 transport_name.c_str());
272 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000274 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275}
276
277void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000278Channel::OnPlayTelephoneEvent(int32_t id,
279 uint8_t event,
280 uint16_t lengthMs,
281 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000282{
283 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
284 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000285 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000286
287 if (!_playOutbandDtmfEvent || (event > 15))
288 {
289 // Ignore callback since feedback is disabled or event is not a
290 // Dtmf tone event.
291 return;
292 }
293
294 assert(_outputMixerPtr != NULL);
295
296 // Start playing out the Dtmf tone (if playout is enabled).
297 // Reduce length of tone with 80ms to the reduce risk of echo.
298 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
299}
300
301void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000302Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000303{
304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
305 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000306 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000308 // Update ssrc so that NTP for AV sync can be updated.
309 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310}
311
pbos@webrtc.org92135212013-05-14 08:31:39 +0000312void Channel::OnIncomingCSRCChanged(int32_t id,
313 uint32_t CSRC,
314 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000315{
316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
317 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
318 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000319}
320
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000321void Channel::ResetStatistics(uint32_t ssrc) {
322 StreamStatistician* statistician =
323 rtp_receive_statistics_->GetStatistician(ssrc);
324 if (statistician) {
325 statistician->ResetStatistics();
326 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000327 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000328}
329
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000330int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000331Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000332 int32_t id,
333 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000334 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000335 int frequency,
336 uint8_t channels,
337 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000338{
339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
340 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
341 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
342 id, payloadType, payloadName, frequency, channels, rate);
343
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000344 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000346 CodecInst receiveCodec = {0};
347 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000348
349 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000350 receiveCodec.plfreq = frequency;
351 receiveCodec.channels = channels;
352 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000353 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000354
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000355 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 receiveCodec.pacsize = dummyCodec.pacsize;
357
358 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000359 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000360 {
361 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000362 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 "Channel::OnInitializeDecoder() invalid codec ("
364 "pt=%d, name=%s) received - 1", payloadType, payloadName);
365 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
366 return -1;
367 }
368
369 return 0;
370}
371
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000372int32_t
373Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000374 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000375 const WebRtcRTPHeader* rtpHeader)
376{
377 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000378 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 " payloadType=%u, audioChannel=%u)",
380 payloadSize,
381 rtpHeader->header.payloadType,
382 rtpHeader->type.Audio.channel);
383
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000384 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 {
386 // Avoid inserting into NetEQ when we are not playing. Count the
387 // packet as discarded.
388 WEBRTC_TRACE(kTraceStream, kTraceVoice,
389 VoEId(_instanceId, _channelId),
390 "received packet is discarded since playing is not"
391 " activated");
392 _numberOfDiscardedPackets++;
393 return 0;
394 }
395
396 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000397 if (audio_coding_->IncomingPacket(payloadData,
398 payloadSize,
399 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000400 {
401 _engineStatisticsPtr->SetLastError(
402 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
403 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
404 return -1;
405 }
406
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000407 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 UpdatePacketDelay(rtpHeader->header.timestamp,
409 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000410
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000411 uint16_t round_trip_time = 0;
412 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
413 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000414
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000415 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000416 round_trip_time);
417 if (!nack_list.empty()) {
418 // Can't use nack_list.data() since it's not supported by all
419 // compilers.
420 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000421 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 return 0;
423}
424
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000425bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000426 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000427 RTPHeader header;
428 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
429 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
430 "IncomingPacket invalid RTP header");
431 return false;
432 }
433 header.payload_type_frequency =
434 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
435 if (header.payload_type_frequency < 0)
436 return false;
437 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
438}
439
pbos@webrtc.org92135212013-05-14 08:31:39 +0000440int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000441{
442 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
443 "Channel::GetAudioFrame(id=%d)", id);
444
445 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000446 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
447 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 {
449 WEBRTC_TRACE(kTraceError, kTraceVoice,
450 VoEId(_instanceId,_channelId),
451 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000452 // In all likelihood, the audio in this frame is garbage. We return an
453 // error so that the audio mixer module doesn't add it to the mix. As
454 // a result, it won't be played out and the actions skipped here are
455 // irrelevant.
456 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 }
458
459 if (_RxVadDetection)
460 {
461 UpdateRxVadDetection(audioFrame);
462 }
463
464 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000465 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000466 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000467 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000468
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000469 ChannelState::State state = channel_state_.Get();
470
471 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000472 int err = rx_audioproc_->ProcessStream(&audioFrame);
473 if (err) {
474 LOG(LS_ERROR) << "ProcessStream() error: " << err;
475 assert(false);
476 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 }
478
wu@webrtc.org63420662013-10-17 18:28:55 +0000479 float output_gain = 1.0f;
480 float left_pan = 1.0f;
481 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000483 CriticalSectionScoped cs(&volume_settings_critsect_);
484 output_gain = _outputGain;
485 left_pan = _panLeft;
486 right_pan= _panRight;
487 }
488
489 // Output volume scaling
490 if (output_gain < 0.99f || output_gain > 1.01f)
491 {
492 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 }
494
495 // Scale left and/or right channel(s) if stereo and master balance is
496 // active
497
wu@webrtc.org63420662013-10-17 18:28:55 +0000498 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000500 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 {
502 // Emulate stereo mode since panning is active.
503 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000504 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 }
506 // For true stereo mode (when we are receiving a stereo signal), no
507 // action is needed.
508
509 // Do the panning operation (the audio frame contains stereo at this
510 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000511 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 }
513
514 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000515 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000517 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 }
519
niklase@google.com470e71d2011-07-07 08:21:25 +0000520 // External media
521 if (_outputExternalMedia)
522 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000523 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000524 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 if (_outputExternalMediaCallbackPtr)
526 {
527 _outputExternalMediaCallbackPtr->Process(
528 _channelId,
529 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000530 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000531 audioFrame.samples_per_channel_,
532 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 isStereo);
534 }
535 }
536
537 // Record playout if enabled
538 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000539 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000540
541 if (_outputFileRecording && _outputFileRecorderPtr)
542 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000543 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 }
545 }
546
547 // Measure audio level (0-9)
548 _outputAudioLevel.ComputeLevel(audioFrame);
549
wu@webrtc.org94454b72014-06-05 20:34:08 +0000550 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
551 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000552 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000553 }
554
555 if (capture_start_rtp_time_stamp_ >= 0) {
556 // audioFrame.timestamp_ should be valid from now on.
557
558 // Compute elapsed time.
559 int64_t unwrap_timestamp =
560 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
561 audioFrame.elapsed_time_ms_ =
562 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
563 (GetPlayoutFrequency() / 1000);
564
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000565 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000566 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000567 // Compute ntp time.
568 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
569 audioFrame.timestamp_);
570 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
571 if (audioFrame.ntp_time_ms_ > 0) {
572 // Compute |capture_start_ntp_time_ms_| so that
573 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
574 capture_start_ntp_time_ms_ =
575 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
576 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000577 }
578 }
579
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 return 0;
581}
582
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000583int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000584Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000585{
586 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
587 "Channel::NeededFrequency(id=%d)", id);
588
589 int highestNeeded = 0;
590
591 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000592 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
594 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000595 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000597 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 }
599 else
600 {
601 highestNeeded = receiveFrequency;
602 }
603
604 // Special case, if we're playing a file on the playout side
605 // we take that frequency into consideration as well
606 // This is not needed on sending side, since the codec will
607 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000608 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000610 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000611 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 {
613 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
614 {
615 highestNeeded=_outputFilePlayerPtr->Frequency();
616 }
617 }
618 }
619
620 return(highestNeeded);
621}
622
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000623int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000624Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000625 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000626 uint32_t instanceId,
627 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000628{
629 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
630 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
631 channelId, instanceId);
632
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000633 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 if (channel == NULL)
635 {
636 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
637 VoEId(instanceId,channelId),
638 "Channel::CreateChannel() unable to allocate memory for"
639 " channel");
640 return -1;
641 }
642 return 0;
643}
644
645void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000646Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647{
648 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
649 "Channel::PlayNotification(id=%d, durationMs=%d)",
650 id, durationMs);
651
652 // Not implement yet
653}
654
655void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000656Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000657{
658 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
659 "Channel::RecordNotification(id=%d, durationMs=%d)",
660 id, durationMs);
661
662 // Not implement yet
663}
664
665void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000666Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000667{
668 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
669 "Channel::PlayFileEnded(id=%d)", id);
670
671 if (id == _inputFilePlayerId)
672 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000673 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000674 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
675 VoEId(_instanceId,_channelId),
676 "Channel::PlayFileEnded() => input file player module is"
677 " shutdown");
678 }
679 else if (id == _outputFilePlayerId)
680 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000681 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
683 VoEId(_instanceId,_channelId),
684 "Channel::PlayFileEnded() => output file player module is"
685 " shutdown");
686 }
687}
688
689void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000690Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000691{
692 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
693 "Channel::RecordFileEnded(id=%d)", id);
694
695 assert(id == _outputFileRecorderId);
696
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000697 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000698
699 _outputFileRecording = false;
700 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
701 VoEId(_instanceId,_channelId),
702 "Channel::RecordFileEnded() => output file recorder module is"
703 " shutdown");
704}
705
pbos@webrtc.org92135212013-05-14 08:31:39 +0000706Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000707 uint32_t instanceId,
708 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
710 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000711 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000713 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000714 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000715 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000716 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000717 rtp_receive_statistics_(ReceiveStatistics::Create(
718 Clock::GetRealTimeClock())),
719 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
720 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
721 this, this, rtp_payload_registry_.get())),
722 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000723 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000724 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 _rtpDumpIn(*RtpDump::CreateRtpDump()),
726 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000729 _inputFilePlayerPtr(NULL),
730 _outputFilePlayerPtr(NULL),
731 _outputFileRecorderPtr(NULL),
732 // Avoid conflict with other channels by adding 1024 - 1026,
733 // won't use as much as 1024 channels.
734 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
735 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
736 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000738 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
739 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000740 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 _inputExternalMediaCallbackPtr(NULL),
742 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000743 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
744 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000745 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000746 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000747 playout_timestamp_rtp_(0),
748 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000749 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000750 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000751 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000752 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000753 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
754 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000755 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000756 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000757 _outputMixerPtr(NULL),
758 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000759 _moduleProcessThreadPtr(NULL),
760 _audioDeviceModulePtr(NULL),
761 _voiceEngineObserverPtr(NULL),
762 _callbackCritSectPtr(NULL),
763 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000764 _rxVadObserverPtr(NULL),
765 _oldVadDecision(-1),
766 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000767 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000768 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 _mute(false),
770 _panLeft(1.0f),
771 _panRight(1.0f),
772 _outputGain(1.0f),
773 _playOutbandDtmfEvent(false),
774 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 _lastLocalTimeStamp(0),
776 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000779 vie_network_(NULL),
780 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000781 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000782 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 _previousTimestamp(0),
784 _recPacketDelayMs(20),
785 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000786 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000787 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000788 restored_packet_in_use_(false),
789 bitrate_controller_(
790 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
791 true)),
792 rtcp_bandwidth_observer_(
793 bitrate_controller_->CreateRtcpBandwidthObserver()),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000794 send_bitrate_observer_(new VoEBitrateObserver(this)),
795 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000796{
797 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
798 "Channel::Channel() - ctor");
799 _inbandDtmfQueue.ResetDtmf();
800 _inbandDtmfGenerator.Init();
801 _outputAudioLevel.Clear();
802
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000803 RtpRtcp::Configuration configuration;
804 configuration.id = VoEModuleId(instanceId, channelId);
805 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000806 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000807 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000808 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000809 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000810
811 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000812
813 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
814 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
815 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000816
817 Config audioproc_config;
818 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
819 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000820}
821
822Channel::~Channel()
823{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000824 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
826 "Channel::~Channel() - dtor");
827
828 if (_outputExternalMedia)
829 {
830 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
831 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000832 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 {
834 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
835 }
836 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000837 StopPlayout();
838
839 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000840 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 if (_inputFilePlayerPtr)
842 {
843 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
844 _inputFilePlayerPtr->StopPlayingFile();
845 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
846 _inputFilePlayerPtr = NULL;
847 }
848 if (_outputFilePlayerPtr)
849 {
850 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
851 _outputFilePlayerPtr->StopPlayingFile();
852 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
853 _outputFilePlayerPtr = NULL;
854 }
855 if (_outputFileRecorderPtr)
856 {
857 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
858 _outputFileRecorderPtr->StopRecording();
859 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
860 _outputFileRecorderPtr = NULL;
861 }
862 }
863
864 // The order to safely shutdown modules in a channel is:
865 // 1. De-register callbacks in modules
866 // 2. De-register modules in process thread
867 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000868 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000869 {
870 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
871 VoEId(_instanceId,_channelId),
872 "~Channel() failed to de-register transport callback"
873 " (Audio coding module)");
874 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000875 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 {
877 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
878 VoEId(_instanceId,_channelId),
879 "~Channel() failed to de-register VAD callback"
880 " (Audio coding module)");
881 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000882 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000883 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 {
885 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
886 VoEId(_instanceId,_channelId),
887 "~Channel() failed to deregister RTP/RTCP module");
888 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 // End of modules shutdown
890
891 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000892 if (vie_network_) {
893 vie_network_->Release();
894 vie_network_ = NULL;
895 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 RtpDump::DestroyRtpDump(&_rtpDumpIn);
897 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000900 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000901}
902
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000903int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000904Channel::Init()
905{
906 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
907 "Channel::Init()");
908
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000909 channel_state_.Reset();
910
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 // --- Initial sanity
912
913 if ((_engineStatisticsPtr == NULL) ||
914 (_moduleProcessThreadPtr == NULL))
915 {
916 WEBRTC_TRACE(kTraceError, kTraceVoice,
917 VoEId(_instanceId,_channelId),
918 "Channel::Init() must call SetEngineInformation() first");
919 return -1;
920 }
921
922 // --- Add modules to process thread (for periodic schedulation)
923
924 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000925 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 if (processThreadFail)
928 {
929 _engineStatisticsPtr->SetLastError(
930 VE_CANNOT_INIT_CHANNEL, kTraceError,
931 "Channel::Init() modules not registered");
932 return -1;
933 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000934 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000935
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000936 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000937#ifdef WEBRTC_CODEC_AVT
938 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000939 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000940#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000941 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 {
943 _engineStatisticsPtr->SetLastError(
944 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
945 "Channel::Init() unable to initialize the ACM - 1");
946 return -1;
947 }
948
949 // --- RTP/RTCP module initialization
950
951 // Ensure that RTCP is enabled by default for the created channel.
952 // Note that, the module will keep generating RTCP until it is explicitly
953 // disabled by the user.
954 // After StopListen (when no sockets exists), RTCP packets will no longer
955 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000956 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
957 // RTCP is enabled by default.
958 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 {
960 _engineStatisticsPtr->SetLastError(
961 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
962 "Channel::Init() RTP/RTCP module not initialized");
963 return -1;
964 }
965
966 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000967 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000968 (audio_coding_->RegisterTransportCallback(this) == -1) ||
969 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000970
971 if (fail)
972 {
973 _engineStatisticsPtr->SetLastError(
974 VE_CANNOT_INIT_CHANNEL, kTraceError,
975 "Channel::Init() callbacks not registered");
976 return -1;
977 }
978
979 // --- Register all supported codecs to the receiving side of the
980 // RTP/RTCP module
981
982 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000983 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000984
985 for (int idx = 0; idx < nSupportedCodecs; idx++)
986 {
987 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000988 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000989 (rtp_receiver_->RegisterReceivePayload(
990 codec.plname,
991 codec.pltype,
992 codec.plfreq,
993 codec.channels,
994 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000995 {
996 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
997 VoEId(_instanceId,_channelId),
998 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
999 "to RTP/RTCP receiver",
1000 codec.plname, codec.pltype, codec.plfreq,
1001 codec.channels, codec.rate);
1002 }
1003 else
1004 {
1005 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1006 VoEId(_instanceId,_channelId),
1007 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1008 "the RTP/RTCP receiver",
1009 codec.plname, codec.pltype, codec.plfreq,
1010 codec.channels, codec.rate);
1011 }
1012
1013 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001014 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
1016 SetSendCodec(codec);
1017 }
1018
1019 // Register default PT for outband 'telephone-event'
1020 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1021 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001022 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001023 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001024 {
1025 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1026 VoEId(_instanceId,_channelId),
1027 "Channel::Init() failed to register outband "
1028 "'telephone-event' (%d/%d) correctly",
1029 codec.pltype, codec.plfreq);
1030 }
1031 }
1032
1033 if (!STR_CASE_CMP(codec.plname, "CN"))
1034 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001035 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1036 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001037 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 {
1039 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1040 VoEId(_instanceId,_channelId),
1041 "Channel::Init() failed to register CN (%d/%d) "
1042 "correctly - 1",
1043 codec.pltype, codec.plfreq);
1044 }
1045 }
1046#ifdef WEBRTC_CODEC_RED
1047 // Register RED to the receiving side of the ACM.
1048 // We will not receive an OnInitializeDecoder() callback for RED.
1049 if (!STR_CASE_CMP(codec.plname, "RED"))
1050 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001051 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 {
1053 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1054 VoEId(_instanceId,_channelId),
1055 "Channel::Init() failed to register RED (%d/%d) "
1056 "correctly",
1057 codec.pltype, codec.plfreq);
1058 }
1059 }
1060#endif
1061 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001062
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001063 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1064 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1065 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001067 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1068 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1069 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 }
1071
1072 return 0;
1073}
1074
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001075int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001076Channel::SetEngineInformation(Statistics& engineStatistics,
1077 OutputMixer& outputMixer,
1078 voe::TransmitMixer& transmitMixer,
1079 ProcessThread& moduleProcessThread,
1080 AudioDeviceModule& audioDeviceModule,
1081 VoiceEngineObserver* voiceEngineObserver,
1082 CriticalSectionWrapper* callbackCritSect)
1083{
1084 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1085 "Channel::SetEngineInformation()");
1086 _engineStatisticsPtr = &engineStatistics;
1087 _outputMixerPtr = &outputMixer;
1088 _transmitMixerPtr = &transmitMixer,
1089 _moduleProcessThreadPtr = &moduleProcessThread;
1090 _audioDeviceModulePtr = &audioDeviceModule;
1091 _voiceEngineObserverPtr = voiceEngineObserver;
1092 _callbackCritSectPtr = callbackCritSect;
1093 return 0;
1094}
1095
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001096int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001097Channel::UpdateLocalTimeStamp()
1098{
1099
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001100 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001101 return 0;
1102}
1103
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001104int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001105Channel::StartPlayout()
1106{
1107 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1108 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001109 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001110 {
1111 return 0;
1112 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001113
1114 if (!_externalMixing) {
1115 // Add participant as candidates for mixing.
1116 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1117 {
1118 _engineStatisticsPtr->SetLastError(
1119 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1120 "StartPlayout() failed to add participant to mixer");
1121 return -1;
1122 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 }
1124
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001125 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001126 if (RegisterFilePlayingToMixer() != 0)
1127 return -1;
1128
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 return 0;
1130}
1131
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001132int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001133Channel::StopPlayout()
1134{
1135 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1136 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001137 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 {
1139 return 0;
1140 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001141
1142 if (!_externalMixing) {
1143 // Remove participant as candidates for mixing
1144 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1145 {
1146 _engineStatisticsPtr->SetLastError(
1147 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1148 "StopPlayout() failed to remove participant from mixer");
1149 return -1;
1150 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001151 }
1152
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001153 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 _outputAudioLevel.Clear();
1155
1156 return 0;
1157}
1158
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001159int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001160Channel::StartSend()
1161{
1162 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1163 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001164 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001165 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001166 if (send_sequence_number_)
1167 SetInitSequenceNumber(send_sequence_number_);
1168
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001169 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001171 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001173 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001174
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001175 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 {
1177 _engineStatisticsPtr->SetLastError(
1178 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1179 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001180 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001181 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 return -1;
1183 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001184
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 return 0;
1186}
1187
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001188int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001189Channel::StopSend()
1190{
1191 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1192 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001193 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001195 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001196 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001197 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001198
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001199 // Store the sequence number to be able to pick up the same sequence for
1200 // the next StartSend(). This is needed for restarting device, otherwise
1201 // it might cause libSRTP to complain about packets being replayed.
1202 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1203 // CL is landed. See issue
1204 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1205 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1206
niklase@google.com470e71d2011-07-07 08:21:25 +00001207 // Reset sending SSRC and sequence number and triggers direct transmission
1208 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001209 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1210 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 {
1212 _engineStatisticsPtr->SetLastError(
1213 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1214 "StartSend() RTP/RTCP failed to stop sending");
1215 }
1216
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 return 0;
1218}
1219
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001220int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001221Channel::StartReceiving()
1222{
1223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1224 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001225 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 {
1227 return 0;
1228 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001229 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 _numberOfDiscardedPackets = 0;
1231 return 0;
1232}
1233
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001234int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001235Channel::StopReceiving()
1236{
1237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1238 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001239 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 {
1241 return 0;
1242 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001243
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001244 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001245 return 0;
1246}
1247
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001248int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001249Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1250{
1251 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1252 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001253 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001254
1255 if (_voiceEngineObserverPtr)
1256 {
1257 _engineStatisticsPtr->SetLastError(
1258 VE_INVALID_OPERATION, kTraceError,
1259 "RegisterVoiceEngineObserver() observer already enabled");
1260 return -1;
1261 }
1262 _voiceEngineObserverPtr = &observer;
1263 return 0;
1264}
1265
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001266int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001267Channel::DeRegisterVoiceEngineObserver()
1268{
1269 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1270 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001271 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001272
1273 if (!_voiceEngineObserverPtr)
1274 {
1275 _engineStatisticsPtr->SetLastError(
1276 VE_INVALID_OPERATION, kTraceWarning,
1277 "DeRegisterVoiceEngineObserver() observer already disabled");
1278 return 0;
1279 }
1280 _voiceEngineObserverPtr = NULL;
1281 return 0;
1282}
1283
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001284int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001285Channel::GetSendCodec(CodecInst& codec)
1286{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001287 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001288}
1289
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001290int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001291Channel::GetRecCodec(CodecInst& codec)
1292{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001293 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001294}
1295
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001296int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001297Channel::SetSendCodec(const CodecInst& codec)
1298{
1299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1300 "Channel::SetSendCodec()");
1301
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001302 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001303 {
1304 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1305 "SetSendCodec() failed to register codec to ACM");
1306 return -1;
1307 }
1308
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001309 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001310 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001311 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1312 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001313 {
1314 WEBRTC_TRACE(
1315 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1316 "SetSendCodec() failed to register codec to"
1317 " RTP/RTCP module");
1318 return -1;
1319 }
1320 }
1321
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001322 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001323 {
1324 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1325 "SetSendCodec() failed to set audio packet size");
1326 return -1;
1327 }
1328
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001329 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1330 codec.rate, 0, 0);
1331
niklase@google.com470e71d2011-07-07 08:21:25 +00001332 return 0;
1333}
1334
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001335void
1336Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1337 const uint8_t fraction_lost, // 0 - 255.
1338 const uint32_t rtt) {
1339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1341 bitrate_bps, fraction_lost, rtt);
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001342 // |fraction_lost| from BitrateObserver is short time observation of packet
1343 // loss rate from past. We use network predictor to make a more reasonable
1344 // loss rate estimation.
1345 network_predictor_->UpdatePacketLossRate(fraction_lost);
1346 uint8_t loss_rate = network_predictor_->GetLossRate();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001347 // Normalizes rate to 0 - 100.
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001348 if (audio_coding_->SetPacketLossRate(100 * loss_rate / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001349 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1350 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1351 assert(false); // This should not happen.
1352 }
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::SetVADStatus(mode=%d)", mode);
1360 // To disable VAD, DTX must be disabled too
1361 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001362 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 {
1364 _engineStatisticsPtr->SetLastError(
1365 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1366 "SetVADStatus() failed to set VAD");
1367 return -1;
1368 }
1369 return 0;
1370}
1371
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001372int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001373Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1374{
1375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1376 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001377 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 {
1379 _engineStatisticsPtr->SetLastError(
1380 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1381 "GetVADStatus() failed to get VAD status");
1382 return -1;
1383 }
1384 disabledDTX = !disabledDTX;
1385 return 0;
1386}
1387
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001388int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001389Channel::SetRecPayloadType(const CodecInst& codec)
1390{
1391 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1392 "Channel::SetRecPayloadType()");
1393
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001394 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 {
1396 _engineStatisticsPtr->SetLastError(
1397 VE_ALREADY_PLAYING, kTraceError,
1398 "SetRecPayloadType() unable to set PT while playing");
1399 return -1;
1400 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001401 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001402 {
1403 _engineStatisticsPtr->SetLastError(
1404 VE_ALREADY_LISTENING, kTraceError,
1405 "SetRecPayloadType() unable to set PT while listening");
1406 return -1;
1407 }
1408
1409 if (codec.pltype == -1)
1410 {
1411 // De-register the selected codec (RTP/RTCP module and ACM)
1412
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001413 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 CodecInst rxCodec = codec;
1415
1416 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001417 rtp_payload_registry_->ReceivePayloadType(
1418 rxCodec.plname,
1419 rxCodec.plfreq,
1420 rxCodec.channels,
1421 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1422 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001423 rxCodec.pltype = pltype;
1424
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001425 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 {
1427 _engineStatisticsPtr->SetLastError(
1428 VE_RTP_RTCP_MODULE_ERROR,
1429 kTraceError,
1430 "SetRecPayloadType() RTP/RTCP-module deregistration "
1431 "failed");
1432 return -1;
1433 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001434 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 {
1436 _engineStatisticsPtr->SetLastError(
1437 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1438 "SetRecPayloadType() ACM deregistration failed - 1");
1439 return -1;
1440 }
1441 return 0;
1442 }
1443
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001444 if (rtp_receiver_->RegisterReceivePayload(
1445 codec.plname,
1446 codec.pltype,
1447 codec.plfreq,
1448 codec.channels,
1449 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001450 {
1451 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001452 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1453 if (rtp_receiver_->RegisterReceivePayload(
1454 codec.plname,
1455 codec.pltype,
1456 codec.plfreq,
1457 codec.channels,
1458 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 {
1460 _engineStatisticsPtr->SetLastError(
1461 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1462 "SetRecPayloadType() RTP/RTCP-module registration failed");
1463 return -1;
1464 }
1465 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001466 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001467 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001468 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1469 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001470 {
1471 _engineStatisticsPtr->SetLastError(
1472 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1473 "SetRecPayloadType() ACM registration failed - 1");
1474 return -1;
1475 }
1476 }
1477 return 0;
1478}
1479
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001480int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001481Channel::GetRecPayloadType(CodecInst& codec)
1482{
1483 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1484 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001485 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001486 if (rtp_payload_registry_->ReceivePayloadType(
1487 codec.plname,
1488 codec.plfreq,
1489 codec.channels,
1490 (codec.rate < 0) ? 0 : codec.rate,
1491 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001492 {
1493 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001494 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001495 "GetRecPayloadType() failed to retrieve RX payload type");
1496 return -1;
1497 }
1498 codec.pltype = payloadType;
1499 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1500 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1501 return 0;
1502}
1503
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001504int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001505Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1506{
1507 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1508 "Channel::SetSendCNPayloadType()");
1509
1510 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001511 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001512 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001513 if (frequency == kFreq32000Hz)
1514 samplingFreqHz = 32000;
1515 else if (frequency == kFreq16000Hz)
1516 samplingFreqHz = 16000;
1517
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001518 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001519 {
1520 _engineStatisticsPtr->SetLastError(
1521 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1522 "SetSendCNPayloadType() failed to retrieve default CN codec "
1523 "settings");
1524 return -1;
1525 }
1526
1527 // Modify the payload type (must be set to dynamic range)
1528 codec.pltype = type;
1529
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001530 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 {
1532 _engineStatisticsPtr->SetLastError(
1533 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1534 "SetSendCNPayloadType() failed to register CN to ACM");
1535 return -1;
1536 }
1537
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001538 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001539 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001540 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1541 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001542 {
1543 _engineStatisticsPtr->SetLastError(
1544 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1545 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1546 "module");
1547 return -1;
1548 }
1549 }
1550 return 0;
1551}
1552
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001553int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001554 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001555 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001556
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001557 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001558 _engineStatisticsPtr->SetLastError(
1559 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001560 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001561 return -1;
1562 }
1563 return 0;
1564}
1565
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001566int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001567{
1568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1569 "Channel::RegisterExternalTransport()");
1570
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001571 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001572
niklase@google.com470e71d2011-07-07 08:21:25 +00001573 if (_externalTransport)
1574 {
1575 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1576 kTraceError,
1577 "RegisterExternalTransport() external transport already enabled");
1578 return -1;
1579 }
1580 _externalTransport = true;
1581 _transportPtr = &transport;
1582 return 0;
1583}
1584
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001585int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001586Channel::DeRegisterExternalTransport()
1587{
1588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1589 "Channel::DeRegisterExternalTransport()");
1590
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001591 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001592
niklase@google.com470e71d2011-07-07 08:21:25 +00001593 if (!_transportPtr)
1594 {
1595 _engineStatisticsPtr->SetLastError(
1596 VE_INVALID_OPERATION, kTraceWarning,
1597 "DeRegisterExternalTransport() external transport already "
1598 "disabled");
1599 return 0;
1600 }
1601 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001602 _transportPtr = NULL;
1603 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1604 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001605 return 0;
1606}
1607
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001608int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001609 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001610 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1611 "Channel::ReceivedRTPPacket()");
1612
1613 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001614 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001615
1616 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001617 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1618 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001619 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1620 VoEId(_instanceId,_channelId),
1621 "Channel::SendPacket() RTP dump to input file failed");
1622 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001623 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001624 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001625 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1626 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1627 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001628 return -1;
1629 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001630 header.payload_type_frequency =
1631 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001632 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001633 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001634 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001635 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001636 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001637 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001638
1639 // Forward any packets to ViE bandwidth estimator, if enabled.
1640 {
1641 CriticalSectionScoped cs(&_callbackCritSect);
1642 if (vie_network_) {
1643 int64_t arrival_time_ms;
1644 if (packet_time.timestamp != -1) {
1645 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1646 } else {
1647 arrival_time_ms = TickTime::MillisecondTimestamp();
1648 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001649 size_t payload_length = length - header.headerLength;
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001650 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1651 payload_length, header);
1652 }
1653 }
1654
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001655 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001656}
1657
1658bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001659 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001660 const RTPHeader& header,
1661 bool in_order) {
1662 if (rtp_payload_registry_->IsEncapsulated(header)) {
1663 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001664 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001665 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001666 assert(packet_length >= header.headerLength);
1667 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001668 PayloadUnion payload_specific;
1669 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001670 &payload_specific)) {
1671 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001672 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001673 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1674 payload_specific, in_order);
1675}
1676
1677bool Channel::HandleEncapsulation(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001678 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001679 const RTPHeader& header) {
1680 if (!rtp_payload_registry_->IsRtx(header))
1681 return false;
1682
1683 // Remove the RTX header and parse the original RTP header.
1684 if (packet_length < header.headerLength)
1685 return false;
1686 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1687 return false;
1688 if (restored_packet_in_use_) {
1689 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1690 "Multiple RTX headers detected, dropping packet");
1691 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001692 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001693 uint8_t* restored_packet_ptr = restored_packet_;
1694 if (!rtp_payload_registry_->RestoreOriginalPacket(
1695 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1696 header)) {
1697 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1698 "Incoming RTX packet: invalid RTP header");
1699 return false;
1700 }
1701 restored_packet_in_use_ = true;
1702 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1703 restored_packet_in_use_ = false;
1704 return ret;
1705}
1706
1707bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1708 StreamStatistician* statistician =
1709 rtp_receive_statistics_->GetStatistician(header.ssrc);
1710 if (!statistician)
1711 return false;
1712 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001713}
1714
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001715bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1716 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001717 // Retransmissions are handled separately if RTX is enabled.
1718 if (rtp_payload_registry_->RtxEnabled())
1719 return false;
1720 StreamStatistician* statistician =
1721 rtp_receive_statistics_->GetStatistician(header.ssrc);
1722 if (!statistician)
1723 return false;
1724 // Check if this is a retransmission.
1725 uint16_t min_rtt = 0;
1726 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001727 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001728 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001729}
1730
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001731int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001732 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1733 "Channel::ReceivedRTCPPacket()");
1734 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001735 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001736
1737 // Dump the RTCP packet to a file (if RTP dump is enabled).
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001738 if (_rtpDumpIn.DumpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001739 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1740 VoEId(_instanceId,_channelId),
1741 "Channel::SendPacket() RTCP dump to input file failed");
1742 }
1743
1744 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001745 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001746 _engineStatisticsPtr->SetLastError(
1747 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1748 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1749 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001750
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001751 {
1752 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001753 uint16_t rtt = GetRTT();
1754 if (rtt == 0) {
1755 // Waiting for valid RTT.
1756 return 0;
1757 }
1758 uint32_t ntp_secs = 0;
1759 uint32_t ntp_frac = 0;
1760 uint32_t rtp_timestamp = 0;
1761 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1762 &rtp_timestamp)) {
1763 // Waiting for RTCP.
1764 return 0;
1765 }
1766 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001767 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001768 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001769}
1770
niklase@google.com470e71d2011-07-07 08:21:25 +00001771int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001772 bool loop,
1773 FileFormats format,
1774 int startPosition,
1775 float volumeScaling,
1776 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001777 const CodecInst* codecInst)
1778{
1779 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1780 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1781 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1782 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1783 startPosition, stopPosition);
1784
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001785 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001786 {
1787 _engineStatisticsPtr->SetLastError(
1788 VE_ALREADY_PLAYING, kTraceError,
1789 "StartPlayingFileLocally() is already playing");
1790 return -1;
1791 }
1792
niklase@google.com470e71d2011-07-07 08:21:25 +00001793 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001794 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001795
1796 if (_outputFilePlayerPtr)
1797 {
1798 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1799 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1800 _outputFilePlayerPtr = NULL;
1801 }
1802
1803 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1804 _outputFilePlayerId, (const FileFormats)format);
1805
1806 if (_outputFilePlayerPtr == NULL)
1807 {
1808 _engineStatisticsPtr->SetLastError(
1809 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001810 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001811 return -1;
1812 }
1813
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001814 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001815
1816 if (_outputFilePlayerPtr->StartPlayingFile(
1817 fileName,
1818 loop,
1819 startPosition,
1820 volumeScaling,
1821 notificationTime,
1822 stopPosition,
1823 (const CodecInst*)codecInst) != 0)
1824 {
1825 _engineStatisticsPtr->SetLastError(
1826 VE_BAD_FILE, kTraceError,
1827 "StartPlayingFile() failed to start file playout");
1828 _outputFilePlayerPtr->StopPlayingFile();
1829 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1830 _outputFilePlayerPtr = NULL;
1831 return -1;
1832 }
1833 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001834 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001835 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001836
1837 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001838 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001839
1840 return 0;
1841}
1842
1843int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001844 FileFormats format,
1845 int startPosition,
1846 float volumeScaling,
1847 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001848 const CodecInst* codecInst)
1849{
1850 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1851 "Channel::StartPlayingFileLocally(format=%d,"
1852 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1853 format, volumeScaling, startPosition, stopPosition);
1854
1855 if(stream == NULL)
1856 {
1857 _engineStatisticsPtr->SetLastError(
1858 VE_BAD_FILE, kTraceError,
1859 "StartPlayingFileLocally() NULL as input stream");
1860 return -1;
1861 }
1862
1863
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001864 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001865 {
1866 _engineStatisticsPtr->SetLastError(
1867 VE_ALREADY_PLAYING, kTraceError,
1868 "StartPlayingFileLocally() is already playing");
1869 return -1;
1870 }
1871
niklase@google.com470e71d2011-07-07 08:21:25 +00001872 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001873 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001874
1875 // Destroy the old instance
1876 if (_outputFilePlayerPtr)
1877 {
1878 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1879 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1880 _outputFilePlayerPtr = NULL;
1881 }
1882
1883 // Create the instance
1884 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1885 _outputFilePlayerId,
1886 (const FileFormats)format);
1887
1888 if (_outputFilePlayerPtr == NULL)
1889 {
1890 _engineStatisticsPtr->SetLastError(
1891 VE_INVALID_ARGUMENT, kTraceError,
1892 "StartPlayingFileLocally() filePlayer format isnot correct");
1893 return -1;
1894 }
1895
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001896 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001897
1898 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1899 volumeScaling,
1900 notificationTime,
1901 stopPosition, codecInst) != 0)
1902 {
1903 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1904 "StartPlayingFile() failed to "
1905 "start file playout");
1906 _outputFilePlayerPtr->StopPlayingFile();
1907 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1908 _outputFilePlayerPtr = NULL;
1909 return -1;
1910 }
1911 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001912 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001913 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001914
1915 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001916 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001917
niklase@google.com470e71d2011-07-07 08:21:25 +00001918 return 0;
1919}
1920
1921int Channel::StopPlayingFileLocally()
1922{
1923 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1924 "Channel::StopPlayingFileLocally()");
1925
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001926 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001927 {
1928 _engineStatisticsPtr->SetLastError(
1929 VE_INVALID_OPERATION, kTraceWarning,
1930 "StopPlayingFileLocally() isnot playing");
1931 return 0;
1932 }
1933
niklase@google.com470e71d2011-07-07 08:21:25 +00001934 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001935 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001936
1937 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1938 {
1939 _engineStatisticsPtr->SetLastError(
1940 VE_STOP_RECORDING_FAILED, kTraceError,
1941 "StopPlayingFile() could not stop playing");
1942 return -1;
1943 }
1944 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1945 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1946 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001947 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001948 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001949 // _fileCritSect cannot be taken while calling
1950 // SetAnonymousMixibilityStatus. Refer to comments in
1951 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001952 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1953 {
1954 _engineStatisticsPtr->SetLastError(
1955 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001956 "StopPlayingFile() failed to stop participant from playing as"
1957 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001958 return -1;
1959 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001960
1961 return 0;
1962}
1963
1964int Channel::IsPlayingFileLocally() const
1965{
1966 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1967 "Channel::IsPlayingFileLocally()");
1968
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001969 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001970}
1971
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001972int Channel::RegisterFilePlayingToMixer()
1973{
1974 // Return success for not registering for file playing to mixer if:
1975 // 1. playing file before playout is started on that channel.
1976 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001977 if (!channel_state_.Get().playing ||
1978 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001979 {
1980 return 0;
1981 }
1982
1983 // |_fileCritSect| cannot be taken while calling
1984 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1985 // frames can be pulled by the mixer. Since the frames are generated from
1986 // the file, _fileCritSect will be taken. This would result in a deadlock.
1987 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1988 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001989 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001990 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001991 _engineStatisticsPtr->SetLastError(
1992 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1993 "StartPlayingFile() failed to add participant as file to mixer");
1994 _outputFilePlayerPtr->StopPlayingFile();
1995 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1996 _outputFilePlayerPtr = NULL;
1997 return -1;
1998 }
1999
2000 return 0;
2001}
2002
niklase@google.com470e71d2011-07-07 08:21:25 +00002003int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002004 bool loop,
2005 FileFormats format,
2006 int startPosition,
2007 float volumeScaling,
2008 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002009 const CodecInst* codecInst)
2010{
2011 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2012 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2013 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2014 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2015 startPosition, stopPosition);
2016
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002017 CriticalSectionScoped cs(&_fileCritSect);
2018
2019 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002020 {
2021 _engineStatisticsPtr->SetLastError(
2022 VE_ALREADY_PLAYING, kTraceWarning,
2023 "StartPlayingFileAsMicrophone() filePlayer is playing");
2024 return 0;
2025 }
2026
niklase@google.com470e71d2011-07-07 08:21:25 +00002027 // Destroy the old instance
2028 if (_inputFilePlayerPtr)
2029 {
2030 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2031 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2032 _inputFilePlayerPtr = NULL;
2033 }
2034
2035 // Create the instance
2036 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2037 _inputFilePlayerId, (const FileFormats)format);
2038
2039 if (_inputFilePlayerPtr == NULL)
2040 {
2041 _engineStatisticsPtr->SetLastError(
2042 VE_INVALID_ARGUMENT, kTraceError,
2043 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2044 return -1;
2045 }
2046
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002047 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002048
2049 if (_inputFilePlayerPtr->StartPlayingFile(
2050 fileName,
2051 loop,
2052 startPosition,
2053 volumeScaling,
2054 notificationTime,
2055 stopPosition,
2056 (const CodecInst*)codecInst) != 0)
2057 {
2058 _engineStatisticsPtr->SetLastError(
2059 VE_BAD_FILE, kTraceError,
2060 "StartPlayingFile() failed to start file playout");
2061 _inputFilePlayerPtr->StopPlayingFile();
2062 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2063 _inputFilePlayerPtr = NULL;
2064 return -1;
2065 }
2066 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002067 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002068
2069 return 0;
2070}
2071
2072int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002073 FileFormats format,
2074 int startPosition,
2075 float volumeScaling,
2076 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002077 const CodecInst* codecInst)
2078{
2079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2080 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2081 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2082 format, volumeScaling, startPosition, stopPosition);
2083
2084 if(stream == NULL)
2085 {
2086 _engineStatisticsPtr->SetLastError(
2087 VE_BAD_FILE, kTraceError,
2088 "StartPlayingFileAsMicrophone NULL as input stream");
2089 return -1;
2090 }
2091
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002092 CriticalSectionScoped cs(&_fileCritSect);
2093
2094 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002095 {
2096 _engineStatisticsPtr->SetLastError(
2097 VE_ALREADY_PLAYING, kTraceWarning,
2098 "StartPlayingFileAsMicrophone() is playing");
2099 return 0;
2100 }
2101
niklase@google.com470e71d2011-07-07 08:21:25 +00002102 // Destroy the old instance
2103 if (_inputFilePlayerPtr)
2104 {
2105 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2106 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2107 _inputFilePlayerPtr = NULL;
2108 }
2109
2110 // Create the instance
2111 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2112 _inputFilePlayerId, (const FileFormats)format);
2113
2114 if (_inputFilePlayerPtr == NULL)
2115 {
2116 _engineStatisticsPtr->SetLastError(
2117 VE_INVALID_ARGUMENT, kTraceError,
2118 "StartPlayingInputFile() filePlayer format isnot correct");
2119 return -1;
2120 }
2121
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002122 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002123
2124 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2125 volumeScaling, notificationTime,
2126 stopPosition, codecInst) != 0)
2127 {
2128 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2129 "StartPlayingFile() failed to start "
2130 "file playout");
2131 _inputFilePlayerPtr->StopPlayingFile();
2132 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2133 _inputFilePlayerPtr = NULL;
2134 return -1;
2135 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002136
niklase@google.com470e71d2011-07-07 08:21:25 +00002137 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002138 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002139
2140 return 0;
2141}
2142
2143int Channel::StopPlayingFileAsMicrophone()
2144{
2145 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2146 "Channel::StopPlayingFileAsMicrophone()");
2147
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002148 CriticalSectionScoped cs(&_fileCritSect);
2149
2150 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002151 {
2152 _engineStatisticsPtr->SetLastError(
2153 VE_INVALID_OPERATION, kTraceWarning,
2154 "StopPlayingFileAsMicrophone() isnot playing");
2155 return 0;
2156 }
2157
niklase@google.com470e71d2011-07-07 08:21:25 +00002158 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2159 {
2160 _engineStatisticsPtr->SetLastError(
2161 VE_STOP_RECORDING_FAILED, kTraceError,
2162 "StopPlayingFile() could not stop playing");
2163 return -1;
2164 }
2165 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2166 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2167 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002168 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002169
2170 return 0;
2171}
2172
2173int Channel::IsPlayingFileAsMicrophone() const
2174{
2175 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2176 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002177 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002178}
2179
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002180int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002181 const CodecInst* codecInst)
2182{
2183 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2184 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2185
2186 if (_outputFileRecording)
2187 {
2188 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2189 "StartRecordingPlayout() is already recording");
2190 return 0;
2191 }
2192
2193 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002194 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002195 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2196
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002197 if ((codecInst != NULL) &&
2198 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002199 {
2200 _engineStatisticsPtr->SetLastError(
2201 VE_BAD_ARGUMENT, kTraceError,
2202 "StartRecordingPlayout() invalid compression");
2203 return(-1);
2204 }
2205 if(codecInst == NULL)
2206 {
2207 format = kFileFormatPcm16kHzFile;
2208 codecInst=&dummyCodec;
2209 }
2210 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2211 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2212 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2213 {
2214 format = kFileFormatWavFile;
2215 }
2216 else
2217 {
2218 format = kFileFormatCompressedFile;
2219 }
2220
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002221 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002222
2223 // Destroy the old instance
2224 if (_outputFileRecorderPtr)
2225 {
2226 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2227 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2228 _outputFileRecorderPtr = NULL;
2229 }
2230
2231 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2232 _outputFileRecorderId, (const FileFormats)format);
2233 if (_outputFileRecorderPtr == NULL)
2234 {
2235 _engineStatisticsPtr->SetLastError(
2236 VE_INVALID_ARGUMENT, kTraceError,
2237 "StartRecordingPlayout() fileRecorder format isnot correct");
2238 return -1;
2239 }
2240
2241 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2242 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2243 {
2244 _engineStatisticsPtr->SetLastError(
2245 VE_BAD_FILE, kTraceError,
2246 "StartRecordingAudioFile() failed to start file recording");
2247 _outputFileRecorderPtr->StopRecording();
2248 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2249 _outputFileRecorderPtr = NULL;
2250 return -1;
2251 }
2252 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2253 _outputFileRecording = true;
2254
2255 return 0;
2256}
2257
2258int Channel::StartRecordingPlayout(OutStream* stream,
2259 const CodecInst* codecInst)
2260{
2261 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2262 "Channel::StartRecordingPlayout()");
2263
2264 if (_outputFileRecording)
2265 {
2266 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2267 "StartRecordingPlayout() is already recording");
2268 return 0;
2269 }
2270
2271 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002272 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002273 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2274
2275 if (codecInst != NULL && codecInst->channels != 1)
2276 {
2277 _engineStatisticsPtr->SetLastError(
2278 VE_BAD_ARGUMENT, kTraceError,
2279 "StartRecordingPlayout() invalid compression");
2280 return(-1);
2281 }
2282 if(codecInst == NULL)
2283 {
2284 format = kFileFormatPcm16kHzFile;
2285 codecInst=&dummyCodec;
2286 }
2287 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2288 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2289 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2290 {
2291 format = kFileFormatWavFile;
2292 }
2293 else
2294 {
2295 format = kFileFormatCompressedFile;
2296 }
2297
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002298 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002299
2300 // Destroy the old instance
2301 if (_outputFileRecorderPtr)
2302 {
2303 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2304 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2305 _outputFileRecorderPtr = NULL;
2306 }
2307
2308 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2309 _outputFileRecorderId, (const FileFormats)format);
2310 if (_outputFileRecorderPtr == NULL)
2311 {
2312 _engineStatisticsPtr->SetLastError(
2313 VE_INVALID_ARGUMENT, kTraceError,
2314 "StartRecordingPlayout() fileRecorder format isnot correct");
2315 return -1;
2316 }
2317
2318 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2319 notificationTime) != 0)
2320 {
2321 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2322 "StartRecordingPlayout() failed to "
2323 "start file recording");
2324 _outputFileRecorderPtr->StopRecording();
2325 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2326 _outputFileRecorderPtr = NULL;
2327 return -1;
2328 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002329
niklase@google.com470e71d2011-07-07 08:21:25 +00002330 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2331 _outputFileRecording = true;
2332
2333 return 0;
2334}
2335
2336int Channel::StopRecordingPlayout()
2337{
2338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2339 "Channel::StopRecordingPlayout()");
2340
2341 if (!_outputFileRecording)
2342 {
2343 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2344 "StopRecordingPlayout() isnot recording");
2345 return -1;
2346 }
2347
2348
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002349 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002350
2351 if (_outputFileRecorderPtr->StopRecording() != 0)
2352 {
2353 _engineStatisticsPtr->SetLastError(
2354 VE_STOP_RECORDING_FAILED, kTraceError,
2355 "StopRecording() could not stop recording");
2356 return(-1);
2357 }
2358 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2359 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2360 _outputFileRecorderPtr = NULL;
2361 _outputFileRecording = false;
2362
2363 return 0;
2364}
2365
2366void
2367Channel::SetMixWithMicStatus(bool mix)
2368{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002369 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002370 _mixFileWithMicrophone=mix;
2371}
2372
2373int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002374Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002375{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002376 int8_t currentLevel = _outputAudioLevel.Level();
2377 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002378 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2379 VoEId(_instanceId,_channelId),
2380 "GetSpeechOutputLevel() => level=%u", level);
2381 return 0;
2382}
2383
2384int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002385Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002386{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002387 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2388 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002389 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2390 VoEId(_instanceId,_channelId),
2391 "GetSpeechOutputLevelFullRange() => level=%u", level);
2392 return 0;
2393}
2394
2395int
2396Channel::SetMute(bool enable)
2397{
wu@webrtc.org63420662013-10-17 18:28:55 +00002398 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2400 "Channel::SetMute(enable=%d)", enable);
2401 _mute = enable;
2402 return 0;
2403}
2404
2405bool
2406Channel::Mute() const
2407{
wu@webrtc.org63420662013-10-17 18:28:55 +00002408 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002409 return _mute;
2410}
2411
2412int
2413Channel::SetOutputVolumePan(float left, float right)
2414{
wu@webrtc.org63420662013-10-17 18:28:55 +00002415 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2417 "Channel::SetOutputVolumePan()");
2418 _panLeft = left;
2419 _panRight = right;
2420 return 0;
2421}
2422
2423int
2424Channel::GetOutputVolumePan(float& left, float& right) const
2425{
wu@webrtc.org63420662013-10-17 18:28:55 +00002426 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002427 left = _panLeft;
2428 right = _panRight;
2429 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2430 VoEId(_instanceId,_channelId),
2431 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2432 return 0;
2433}
2434
2435int
2436Channel::SetChannelOutputVolumeScaling(float scaling)
2437{
wu@webrtc.org63420662013-10-17 18:28:55 +00002438 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2440 "Channel::SetChannelOutputVolumeScaling()");
2441 _outputGain = scaling;
2442 return 0;
2443}
2444
2445int
2446Channel::GetChannelOutputVolumeScaling(float& scaling) const
2447{
wu@webrtc.org63420662013-10-17 18:28:55 +00002448 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002449 scaling = _outputGain;
2450 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2451 VoEId(_instanceId,_channelId),
2452 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2453 return 0;
2454}
2455
niklase@google.com470e71d2011-07-07 08:21:25 +00002456int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002457 int lengthMs, int attenuationDb,
2458 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002459{
2460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2461 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2462 playDtmfEvent);
2463
2464 _playOutbandDtmfEvent = playDtmfEvent;
2465
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002466 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002467 attenuationDb) != 0)
2468 {
2469 _engineStatisticsPtr->SetLastError(
2470 VE_SEND_DTMF_FAILED,
2471 kTraceWarning,
2472 "SendTelephoneEventOutband() failed to send event");
2473 return -1;
2474 }
2475 return 0;
2476}
2477
2478int Channel::SendTelephoneEventInband(unsigned char eventCode,
2479 int lengthMs,
2480 int attenuationDb,
2481 bool playDtmfEvent)
2482{
2483 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2484 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2485 playDtmfEvent);
2486
2487 _playInbandDtmfEvent = playDtmfEvent;
2488 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2489
2490 return 0;
2491}
2492
2493int
niklase@google.com470e71d2011-07-07 08:21:25 +00002494Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2495{
2496 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2497 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002498 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002499 {
2500 _engineStatisticsPtr->SetLastError(
2501 VE_INVALID_ARGUMENT, kTraceError,
2502 "SetSendTelephoneEventPayloadType() invalid type");
2503 return -1;
2504 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002505 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002506 codec.plfreq = 8000;
2507 codec.pltype = type;
2508 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002509 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002510 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002511 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2512 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2513 _engineStatisticsPtr->SetLastError(
2514 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2515 "SetSendTelephoneEventPayloadType() failed to register send"
2516 "payload type");
2517 return -1;
2518 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002519 }
2520 _sendTelephoneEventPayloadType = type;
2521 return 0;
2522}
2523
2524int
2525Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2526{
2527 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2528 "Channel::GetSendTelephoneEventPayloadType()");
2529 type = _sendTelephoneEventPayloadType;
2530 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2531 VoEId(_instanceId,_channelId),
2532 "GetSendTelephoneEventPayloadType() => type=%u", type);
2533 return 0;
2534}
2535
niklase@google.com470e71d2011-07-07 08:21:25 +00002536int
2537Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2538{
2539 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2540 "Channel::UpdateRxVadDetection()");
2541
2542 int vadDecision = 1;
2543
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002544 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002545
2546 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2547 {
2548 OnRxVadDetected(vadDecision);
2549 _oldVadDecision = vadDecision;
2550 }
2551
2552 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2553 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2554 vadDecision);
2555 return 0;
2556}
2557
2558int
2559Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2560{
2561 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2562 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002563 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002564
2565 if (_rxVadObserverPtr)
2566 {
2567 _engineStatisticsPtr->SetLastError(
2568 VE_INVALID_OPERATION, kTraceError,
2569 "RegisterRxVadObserver() observer already enabled");
2570 return -1;
2571 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002572 _rxVadObserverPtr = &observer;
2573 _RxVadDetection = true;
2574 return 0;
2575}
2576
2577int
2578Channel::DeRegisterRxVadObserver()
2579{
2580 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2581 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002582 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002583
2584 if (!_rxVadObserverPtr)
2585 {
2586 _engineStatisticsPtr->SetLastError(
2587 VE_INVALID_OPERATION, kTraceWarning,
2588 "DeRegisterRxVadObserver() observer already disabled");
2589 return 0;
2590 }
2591 _rxVadObserverPtr = NULL;
2592 _RxVadDetection = false;
2593 return 0;
2594}
2595
2596int
2597Channel::VoiceActivityIndicator(int &activity)
2598{
2599 activity = _sendFrameType;
2600
2601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002602 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002603 return 0;
2604}
2605
2606#ifdef WEBRTC_VOICE_ENGINE_AGC
2607
2608int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002609Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002610{
2611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2612 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2613 (int)enable, (int)mode);
2614
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002615 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 switch (mode)
2617 {
2618 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002619 break;
2620 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002621 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002622 break;
2623 case kAgcFixedDigital:
2624 agcMode = GainControl::kFixedDigital;
2625 break;
2626 case kAgcAdaptiveDigital:
2627 agcMode =GainControl::kAdaptiveDigital;
2628 break;
2629 default:
2630 _engineStatisticsPtr->SetLastError(
2631 VE_INVALID_ARGUMENT, kTraceError,
2632 "SetRxAgcStatus() invalid Agc mode");
2633 return -1;
2634 }
2635
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002636 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002637 {
2638 _engineStatisticsPtr->SetLastError(
2639 VE_APM_ERROR, kTraceError,
2640 "SetRxAgcStatus() failed to set Agc mode");
2641 return -1;
2642 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002643 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002644 {
2645 _engineStatisticsPtr->SetLastError(
2646 VE_APM_ERROR, kTraceError,
2647 "SetRxAgcStatus() failed to set Agc state");
2648 return -1;
2649 }
2650
2651 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002652 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002653
2654 return 0;
2655}
2656
2657int
2658Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2659{
2660 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2661 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2662
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002663 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002664 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002665 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002666
2667 enabled = enable;
2668
2669 switch (agcMode)
2670 {
2671 case GainControl::kFixedDigital:
2672 mode = kAgcFixedDigital;
2673 break;
2674 case GainControl::kAdaptiveDigital:
2675 mode = kAgcAdaptiveDigital;
2676 break;
2677 default:
2678 _engineStatisticsPtr->SetLastError(
2679 VE_APM_ERROR, kTraceError,
2680 "GetRxAgcStatus() invalid Agc mode");
2681 return -1;
2682 }
2683
2684 return 0;
2685}
2686
2687int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002688Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002689{
2690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2691 "Channel::SetRxAgcConfig()");
2692
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002693 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002694 config.targetLeveldBOv) != 0)
2695 {
2696 _engineStatisticsPtr->SetLastError(
2697 VE_APM_ERROR, kTraceError,
2698 "SetRxAgcConfig() failed to set target peak |level|"
2699 "(or envelope) of the Agc");
2700 return -1;
2701 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002702 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002703 config.digitalCompressionGaindB) != 0)
2704 {
2705 _engineStatisticsPtr->SetLastError(
2706 VE_APM_ERROR, kTraceError,
2707 "SetRxAgcConfig() failed to set the range in |gain| the"
2708 " digital compression stage may apply");
2709 return -1;
2710 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002711 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002712 config.limiterEnable) != 0)
2713 {
2714 _engineStatisticsPtr->SetLastError(
2715 VE_APM_ERROR, kTraceError,
2716 "SetRxAgcConfig() failed to set hard limiter to the signal");
2717 return -1;
2718 }
2719
2720 return 0;
2721}
2722
2723int
2724Channel::GetRxAgcConfig(AgcConfig& config)
2725{
2726 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2727 "Channel::GetRxAgcConfig(config=%?)");
2728
2729 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002730 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002731 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002732 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002733 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002734 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002735
2736 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2737 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2738 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2739 " limiterEnable=%d",
2740 config.targetLeveldBOv,
2741 config.digitalCompressionGaindB,
2742 config.limiterEnable);
2743
2744 return 0;
2745}
2746
2747#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2748
2749#ifdef WEBRTC_VOICE_ENGINE_NR
2750
2751int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002752Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002753{
2754 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2755 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2756 (int)enable, (int)mode);
2757
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002758 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002759 switch (mode)
2760 {
2761
2762 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002763 break;
2764 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002765 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002766 break;
2767 case kNsConference:
2768 nsLevel = NoiseSuppression::kHigh;
2769 break;
2770 case kNsLowSuppression:
2771 nsLevel = NoiseSuppression::kLow;
2772 break;
2773 case kNsModerateSuppression:
2774 nsLevel = NoiseSuppression::kModerate;
2775 break;
2776 case kNsHighSuppression:
2777 nsLevel = NoiseSuppression::kHigh;
2778 break;
2779 case kNsVeryHighSuppression:
2780 nsLevel = NoiseSuppression::kVeryHigh;
2781 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002782 }
2783
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002784 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002785 != 0)
2786 {
2787 _engineStatisticsPtr->SetLastError(
2788 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002789 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002790 return -1;
2791 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002792 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002793 {
2794 _engineStatisticsPtr->SetLastError(
2795 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002796 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 return -1;
2798 }
2799
2800 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002801 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002802
2803 return 0;
2804}
2805
2806int
2807Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2808{
2809 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2810 "Channel::GetRxNsStatus(enable=?, mode=?)");
2811
2812 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002813 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002814 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002815 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002816
2817 enabled = enable;
2818
2819 switch (ncLevel)
2820 {
2821 case NoiseSuppression::kLow:
2822 mode = kNsLowSuppression;
2823 break;
2824 case NoiseSuppression::kModerate:
2825 mode = kNsModerateSuppression;
2826 break;
2827 case NoiseSuppression::kHigh:
2828 mode = kNsHighSuppression;
2829 break;
2830 case NoiseSuppression::kVeryHigh:
2831 mode = kNsVeryHighSuppression;
2832 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002833 }
2834
2835 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2836 VoEId(_instanceId,_channelId),
2837 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2838 return 0;
2839}
2840
2841#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2842
2843int
niklase@google.com470e71d2011-07-07 08:21:25 +00002844Channel::SetLocalSSRC(unsigned int ssrc)
2845{
2846 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2847 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002848 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002849 {
2850 _engineStatisticsPtr->SetLastError(
2851 VE_ALREADY_SENDING, kTraceError,
2852 "SetLocalSSRC() already sending");
2853 return -1;
2854 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002855 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002856 return 0;
2857}
2858
2859int
2860Channel::GetLocalSSRC(unsigned int& ssrc)
2861{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002862 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002863 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2864 VoEId(_instanceId,_channelId),
2865 "GetLocalSSRC() => ssrc=%lu", ssrc);
2866 return 0;
2867}
2868
2869int
2870Channel::GetRemoteSSRC(unsigned int& ssrc)
2871{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002872 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002873 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2874 VoEId(_instanceId,_channelId),
2875 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2876 return 0;
2877}
2878
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002879int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002880 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002881 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002882}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002883
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002884int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2885 unsigned char id) {
2886 rtp_header_parser_->DeregisterRtpHeaderExtension(
2887 kRtpExtensionAudioLevel);
2888 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2889 kRtpExtensionAudioLevel, id)) {
2890 return -1;
2891 }
2892 return 0;
2893}
2894
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002895int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2896 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2897}
2898
2899int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2900 rtp_header_parser_->DeregisterRtpHeaderExtension(
2901 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002902 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2903 kRtpExtensionAbsoluteSendTime, id)) {
2904 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002905 }
2906 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002907}
2908
2909int
2910Channel::SetRTCPStatus(bool enable)
2911{
2912 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2913 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002914 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00002915 kRtcpCompound : kRtcpOff) != 0)
2916 {
2917 _engineStatisticsPtr->SetLastError(
2918 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2919 "SetRTCPStatus() failed to set RTCP status");
2920 return -1;
2921 }
2922 return 0;
2923}
2924
2925int
2926Channel::GetRTCPStatus(bool& enabled)
2927{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002928 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002929 enabled = (method != kRtcpOff);
2930 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2931 VoEId(_instanceId,_channelId),
2932 "GetRTCPStatus() => enabled=%d", enabled);
2933 return 0;
2934}
2935
2936int
2937Channel::SetRTCP_CNAME(const char cName[256])
2938{
2939 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2940 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002941 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002942 {
2943 _engineStatisticsPtr->SetLastError(
2944 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2945 "SetRTCP_CNAME() failed to set RTCP CNAME");
2946 return -1;
2947 }
2948 return 0;
2949}
2950
2951int
niklase@google.com470e71d2011-07-07 08:21:25 +00002952Channel::GetRemoteRTCP_CNAME(char cName[256])
2953{
2954 if (cName == NULL)
2955 {
2956 _engineStatisticsPtr->SetLastError(
2957 VE_INVALID_ARGUMENT, kTraceError,
2958 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2959 return -1;
2960 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002961 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002962 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002963 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002964 {
2965 _engineStatisticsPtr->SetLastError(
2966 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2967 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2968 return -1;
2969 }
2970 strcpy(cName, cname);
2971 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2972 VoEId(_instanceId, _channelId),
2973 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2974 return 0;
2975}
2976
2977int
2978Channel::GetRemoteRTCPData(
2979 unsigned int& NTPHigh,
2980 unsigned int& NTPLow,
2981 unsigned int& timestamp,
2982 unsigned int& playoutTimestamp,
2983 unsigned int* jitter,
2984 unsigned short* fractionLost)
2985{
2986 // --- Information from sender info in received Sender Reports
2987
2988 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002989 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002990 {
2991 _engineStatisticsPtr->SetLastError(
2992 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002993 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002994 "side");
2995 return -1;
2996 }
2997
2998 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2999 // and octet count)
3000 NTPHigh = senderInfo.NTPseconds;
3001 NTPLow = senderInfo.NTPfraction;
3002 timestamp = senderInfo.RTPtimeStamp;
3003
3004 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3005 VoEId(_instanceId, _channelId),
3006 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3007 "timestamp=%lu",
3008 NTPHigh, NTPLow, timestamp);
3009
3010 // --- Locally derived information
3011
3012 // This value is updated on each incoming RTCP packet (0 when no packet
3013 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003014 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003015
3016 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3017 VoEId(_instanceId, _channelId),
3018 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003019 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003020
3021 if (NULL != jitter || NULL != fractionLost)
3022 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003023 // Get all RTCP receiver report blocks that have been received on this
3024 // channel. If we receive RTP packets from a remote source we know the
3025 // remote SSRC and use the report block from him.
3026 // Otherwise use the first report block.
3027 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003028 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003029 remote_stats.empty()) {
3030 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3031 VoEId(_instanceId, _channelId),
3032 "GetRemoteRTCPData() failed to measure statistics due"
3033 " to lack of received RTP and/or RTCP packets");
3034 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003035 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003036
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003037 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003038 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3039 for (; it != remote_stats.end(); ++it) {
3040 if (it->remoteSSRC == remoteSSRC)
3041 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003042 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003043
3044 if (it == remote_stats.end()) {
3045 // If we have not received any RTCP packets from this SSRC it probably
3046 // means that we have not received any RTP packets.
3047 // Use the first received report block instead.
3048 it = remote_stats.begin();
3049 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003050 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003051
xians@webrtc.org79af7342012-01-31 12:22:14 +00003052 if (jitter) {
3053 *jitter = it->jitter;
3054 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3055 VoEId(_instanceId, _channelId),
3056 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3057 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003058
xians@webrtc.org79af7342012-01-31 12:22:14 +00003059 if (fractionLost) {
3060 *fractionLost = it->fractionLost;
3061 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3062 VoEId(_instanceId, _channelId),
3063 "GetRemoteRTCPData() => fractionLost = %lu",
3064 *fractionLost);
3065 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003066 }
3067 return 0;
3068}
3069
3070int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003071Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003072 unsigned int name,
3073 const char* data,
3074 unsigned short dataLengthInBytes)
3075{
3076 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3077 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003078 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003079 {
3080 _engineStatisticsPtr->SetLastError(
3081 VE_NOT_SENDING, kTraceError,
3082 "SendApplicationDefinedRTCPPacket() not sending");
3083 return -1;
3084 }
3085 if (NULL == data)
3086 {
3087 _engineStatisticsPtr->SetLastError(
3088 VE_INVALID_ARGUMENT, kTraceError,
3089 "SendApplicationDefinedRTCPPacket() invalid data value");
3090 return -1;
3091 }
3092 if (dataLengthInBytes % 4 != 0)
3093 {
3094 _engineStatisticsPtr->SetLastError(
3095 VE_INVALID_ARGUMENT, kTraceError,
3096 "SendApplicationDefinedRTCPPacket() invalid length value");
3097 return -1;
3098 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003099 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003100 if (status == kRtcpOff)
3101 {
3102 _engineStatisticsPtr->SetLastError(
3103 VE_RTCP_ERROR, kTraceError,
3104 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3105 return -1;
3106 }
3107
3108 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003109 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003110 subType,
3111 name,
3112 (const unsigned char*) data,
3113 dataLengthInBytes) != 0)
3114 {
3115 _engineStatisticsPtr->SetLastError(
3116 VE_SEND_ERROR, kTraceError,
3117 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3118 return -1;
3119 }
3120 return 0;
3121}
3122
3123int
3124Channel::GetRTPStatistics(
3125 unsigned int& averageJitterMs,
3126 unsigned int& maxJitterMs,
3127 unsigned int& discardedPackets)
3128{
niklase@google.com470e71d2011-07-07 08:21:25 +00003129 // The jitter statistics is updated for each received RTP packet and is
3130 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003131 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3132 // If RTCP is off, there is no timed thread in the RTCP module regularly
3133 // generating new stats, trigger the update manually here instead.
3134 StreamStatistician* statistician =
3135 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3136 if (statistician) {
3137 // Don't use returned statistics, use data from proxy instead so that
3138 // max jitter can be fetched atomically.
3139 RtcpStatistics s;
3140 statistician->GetStatistics(&s, true);
3141 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003142 }
3143
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003144 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003145 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003146 if (playoutFrequency > 0) {
3147 // Scale RTP statistics given the current playout frequency
3148 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3149 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003150 }
3151
3152 discardedPackets = _numberOfDiscardedPackets;
3153
3154 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3155 VoEId(_instanceId, _channelId),
3156 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003157 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003158 averageJitterMs, maxJitterMs, discardedPackets);
3159 return 0;
3160}
3161
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003162int Channel::GetRemoteRTCPReportBlocks(
3163 std::vector<ReportBlock>* report_blocks) {
3164 if (report_blocks == NULL) {
3165 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3166 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3167 return -1;
3168 }
3169
3170 // Get the report blocks from the latest received RTCP Sender or Receiver
3171 // Report. Each element in the vector contains the sender's SSRC and a
3172 // report block according to RFC 3550.
3173 std::vector<RTCPReportBlock> rtcp_report_blocks;
3174 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3175 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3176 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3177 return -1;
3178 }
3179
3180 if (rtcp_report_blocks.empty())
3181 return 0;
3182
3183 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3184 for (; it != rtcp_report_blocks.end(); ++it) {
3185 ReportBlock report_block;
3186 report_block.sender_SSRC = it->remoteSSRC;
3187 report_block.source_SSRC = it->sourceSSRC;
3188 report_block.fraction_lost = it->fractionLost;
3189 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3190 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3191 report_block.interarrival_jitter = it->jitter;
3192 report_block.last_SR_timestamp = it->lastSR;
3193 report_block.delay_since_last_SR = it->delaySinceLastSR;
3194 report_blocks->push_back(report_block);
3195 }
3196 return 0;
3197}
3198
niklase@google.com470e71d2011-07-07 08:21:25 +00003199int
3200Channel::GetRTPStatistics(CallStatistics& stats)
3201{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003202 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003203
3204 // The jitter statistics is updated for each received RTP packet and is
3205 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003206 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003207 StreamStatistician* statistician =
3208 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3209 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003210 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3213 "GetRTPStatistics() failed to read RTP statistics from the "
3214 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003215 }
3216
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003217 stats.fractionLost = statistics.fraction_lost;
3218 stats.cumulativeLost = statistics.cumulative_lost;
3219 stats.extendedMax = statistics.extended_max_sequence_number;
3220 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003221
3222 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3223 VoEId(_instanceId, _channelId),
3224 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003225 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003226 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3227 stats.jitterSamples);
3228
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003229 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003230 stats.rttMs = GetRTT();
niklase@google.com470e71d2011-07-07 08:21:25 +00003231
3232 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3233 VoEId(_instanceId, _channelId),
3234 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3235
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003236 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003237
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003238 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003239 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003240 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003241 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003242
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003243 if (statistician) {
3244 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3245 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003246
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003247 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003248 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003249 {
3250 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3251 VoEId(_instanceId, _channelId),
3252 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003253 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003254 }
3255
3256 stats.bytesSent = bytesSent;
3257 stats.packetsSent = packetsSent;
3258 stats.bytesReceived = bytesReceived;
3259 stats.packetsReceived = packetsReceived;
3260
3261 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3262 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003263 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3264 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3266 stats.packetsReceived);
3267
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003268 // --- Timestamps
3269 {
3270 CriticalSectionScoped lock(ts_stats_lock_.get());
3271 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3272 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003273 return 0;
3274}
3275
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003276int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003277 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003278 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003279
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003280 if (enable) {
3281 if (redPayloadtype < 0 || redPayloadtype > 127) {
3282 _engineStatisticsPtr->SetLastError(
3283 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003284 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003285 return -1;
3286 }
3287
3288 if (SetRedPayloadType(redPayloadtype) < 0) {
3289 _engineStatisticsPtr->SetLastError(
3290 VE_CODEC_ERROR, kTraceError,
3291 "SetSecondarySendCodec() Failed to register RED ACM");
3292 return -1;
3293 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003294 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003295
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003296 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003297 _engineStatisticsPtr->SetLastError(
3298 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003299 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003300 return -1;
3301 }
3302 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003303}
3304
3305int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003306Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003307{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003308 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003309 if (enabled)
3310 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003311 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003312 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003313 {
3314 _engineStatisticsPtr->SetLastError(
3315 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003316 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003317 "module");
3318 return -1;
3319 }
3320 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3321 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003322 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003323 enabled, redPayloadtype);
3324 return 0;
3325 }
3326 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3327 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003328 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003329 return 0;
3330}
3331
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003332int Channel::SetCodecFECStatus(bool enable) {
3333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3334 "Channel::SetCodecFECStatus()");
3335
3336 if (audio_coding_->SetCodecFEC(enable) != 0) {
3337 _engineStatisticsPtr->SetLastError(
3338 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3339 "SetCodecFECStatus() failed to set FEC state");
3340 return -1;
3341 }
3342 return 0;
3343}
3344
3345bool Channel::GetCodecFECStatus() {
3346 bool enabled = audio_coding_->CodecFEC();
3347 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3348 VoEId(_instanceId, _channelId),
3349 "GetCodecFECStatus() => enabled=%d", enabled);
3350 return enabled;
3351}
3352
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003353void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3354 // None of these functions can fail.
3355 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003356 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3357 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003358 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003359 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003360 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003361 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003362}
3363
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003364// Called when we are missing one or more packets.
3365int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003366 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3367}
3368
niklase@google.com470e71d2011-07-07 08:21:25 +00003369int
niklase@google.com470e71d2011-07-07 08:21:25 +00003370Channel::StartRTPDump(const char fileNameUTF8[1024],
3371 RTPDirections direction)
3372{
3373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3374 "Channel::StartRTPDump()");
3375 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3376 {
3377 _engineStatisticsPtr->SetLastError(
3378 VE_INVALID_ARGUMENT, kTraceError,
3379 "StartRTPDump() invalid RTP direction");
3380 return -1;
3381 }
3382 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3383 &_rtpDumpIn : &_rtpDumpOut;
3384 if (rtpDumpPtr == NULL)
3385 {
3386 assert(false);
3387 return -1;
3388 }
3389 if (rtpDumpPtr->IsActive())
3390 {
3391 rtpDumpPtr->Stop();
3392 }
3393 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3394 {
3395 _engineStatisticsPtr->SetLastError(
3396 VE_BAD_FILE, kTraceError,
3397 "StartRTPDump() failed to create file");
3398 return -1;
3399 }
3400 return 0;
3401}
3402
3403int
3404Channel::StopRTPDump(RTPDirections direction)
3405{
3406 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3407 "Channel::StopRTPDump()");
3408 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3409 {
3410 _engineStatisticsPtr->SetLastError(
3411 VE_INVALID_ARGUMENT, kTraceError,
3412 "StopRTPDump() invalid RTP direction");
3413 return -1;
3414 }
3415 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3416 &_rtpDumpIn : &_rtpDumpOut;
3417 if (rtpDumpPtr == NULL)
3418 {
3419 assert(false);
3420 return -1;
3421 }
3422 if (!rtpDumpPtr->IsActive())
3423 {
3424 return 0;
3425 }
3426 return rtpDumpPtr->Stop();
3427}
3428
3429bool
3430Channel::RTPDumpIsActive(RTPDirections direction)
3431{
3432 if ((direction != kRtpIncoming) &&
3433 (direction != kRtpOutgoing))
3434 {
3435 _engineStatisticsPtr->SetLastError(
3436 VE_INVALID_ARGUMENT, kTraceError,
3437 "RTPDumpIsActive() invalid RTP direction");
3438 return false;
3439 }
3440 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3441 &_rtpDumpIn : &_rtpDumpOut;
3442 return rtpDumpPtr->IsActive();
3443}
3444
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003445void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3446 int video_channel) {
3447 CriticalSectionScoped cs(&_callbackCritSect);
3448 if (vie_network_) {
3449 vie_network_->Release();
3450 vie_network_ = NULL;
3451 }
3452 video_channel_ = -1;
3453
3454 if (vie_network != NULL && video_channel != -1) {
3455 vie_network_ = vie_network;
3456 video_channel_ = video_channel;
3457 }
3458}
3459
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003460uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003461Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003462{
3463 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003464 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003465 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003466 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003467 return 0;
3468}
3469
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003470void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003471 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003472 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003473 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003474 CodecInst codec;
3475 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003476
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003477 if (!mono_recording_audio_.get()) {
3478 // Temporary space for DownConvertToCodecFormat.
3479 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003480 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003481 DownConvertToCodecFormat(audio_data,
3482 number_of_frames,
3483 number_of_channels,
3484 sample_rate,
3485 codec.channels,
3486 codec.plfreq,
3487 mono_recording_audio_.get(),
3488 &input_resampler_,
3489 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003490}
3491
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003492uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003493Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003494{
3495 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3496 "Channel::PrepareEncodeAndSend()");
3497
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003498 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003499 {
3500 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3501 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003502 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003503 }
3504
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003505 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003506 {
3507 MixOrReplaceAudioWithFile(mixingFrequency);
3508 }
3509
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003510 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3511 if (is_muted) {
3512 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003513 }
3514
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003515 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003516 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003517 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003518 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003519 if (_inputExternalMediaCallbackPtr)
3520 {
3521 _inputExternalMediaCallbackPtr->Process(
3522 _channelId,
3523 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003524 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003525 _audioFrame.samples_per_channel_,
3526 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003527 isStereo);
3528 }
3529 }
3530
3531 InsertInbandDtmfTone();
3532
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003533 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003534 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003535 if (is_muted) {
3536 rms_level_.ProcessMuted(length);
3537 } else {
3538 rms_level_.Process(_audioFrame.data_, length);
3539 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003540 }
3541
niklase@google.com470e71d2011-07-07 08:21:25 +00003542 return 0;
3543}
3544
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003545uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003546Channel::EncodeAndSend()
3547{
3548 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3549 "Channel::EncodeAndSend()");
3550
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003551 assert(_audioFrame.num_channels_ <= 2);
3552 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003553 {
3554 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3555 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003556 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003557 }
3558
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003559 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003560
3561 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3562
3563 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003564 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003565 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003566 {
3567 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3568 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003569 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003570 }
3571
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003572 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003573
3574 // --- Encode if complete frame is ready
3575
3576 // This call will trigger AudioPacketizationCallback::SendData if encoding
3577 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003578 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003579}
3580
3581int Channel::RegisterExternalMediaProcessing(
3582 ProcessingTypes type,
3583 VoEMediaProcess& processObject)
3584{
3585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3586 "Channel::RegisterExternalMediaProcessing()");
3587
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003588 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003589
3590 if (kPlaybackPerChannel == type)
3591 {
3592 if (_outputExternalMediaCallbackPtr)
3593 {
3594 _engineStatisticsPtr->SetLastError(
3595 VE_INVALID_OPERATION, kTraceError,
3596 "Channel::RegisterExternalMediaProcessing() "
3597 "output external media already enabled");
3598 return -1;
3599 }
3600 _outputExternalMediaCallbackPtr = &processObject;
3601 _outputExternalMedia = true;
3602 }
3603 else if (kRecordingPerChannel == type)
3604 {
3605 if (_inputExternalMediaCallbackPtr)
3606 {
3607 _engineStatisticsPtr->SetLastError(
3608 VE_INVALID_OPERATION, kTraceError,
3609 "Channel::RegisterExternalMediaProcessing() "
3610 "output external media already enabled");
3611 return -1;
3612 }
3613 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003614 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003615 }
3616 return 0;
3617}
3618
3619int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3620{
3621 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3622 "Channel::DeRegisterExternalMediaProcessing()");
3623
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003624 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003625
3626 if (kPlaybackPerChannel == type)
3627 {
3628 if (!_outputExternalMediaCallbackPtr)
3629 {
3630 _engineStatisticsPtr->SetLastError(
3631 VE_INVALID_OPERATION, kTraceWarning,
3632 "Channel::DeRegisterExternalMediaProcessing() "
3633 "output external media already disabled");
3634 return 0;
3635 }
3636 _outputExternalMedia = false;
3637 _outputExternalMediaCallbackPtr = NULL;
3638 }
3639 else if (kRecordingPerChannel == type)
3640 {
3641 if (!_inputExternalMediaCallbackPtr)
3642 {
3643 _engineStatisticsPtr->SetLastError(
3644 VE_INVALID_OPERATION, kTraceWarning,
3645 "Channel::DeRegisterExternalMediaProcessing() "
3646 "input external media already disabled");
3647 return 0;
3648 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003649 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003650 _inputExternalMediaCallbackPtr = NULL;
3651 }
3652
3653 return 0;
3654}
3655
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003656int Channel::SetExternalMixing(bool enabled) {
3657 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3658 "Channel::SetExternalMixing(enabled=%d)", enabled);
3659
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003660 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003661 {
3662 _engineStatisticsPtr->SetLastError(
3663 VE_INVALID_OPERATION, kTraceError,
3664 "Channel::SetExternalMixing() "
3665 "external mixing cannot be changed while playing.");
3666 return -1;
3667 }
3668
3669 _externalMixing = enabled;
3670
3671 return 0;
3672}
3673
niklase@google.com470e71d2011-07-07 08:21:25 +00003674int
niklase@google.com470e71d2011-07-07 08:21:25 +00003675Channel::GetNetworkStatistics(NetworkStatistics& stats)
3676{
3677 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3678 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003679 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003680 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003681 if (return_value >= 0) {
3682 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3683 }
3684 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003685}
3686
wu@webrtc.org24301a62013-12-13 19:17:43 +00003687void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3688 audio_coding_->GetDecodingCallStatistics(stats);
3689}
3690
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003691bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3692 int* playout_buffer_delay_ms) const {
3693 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003694 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003695 "Channel::GetDelayEstimate() no valid estimate.");
3696 return false;
3697 }
3698 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3699 _recPacketDelayMs;
3700 *playout_buffer_delay_ms = playout_delay_ms_;
3701 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3702 "Channel::GetDelayEstimate()");
3703 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003704}
3705
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003706int Channel::SetInitialPlayoutDelay(int delay_ms)
3707{
3708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3709 "Channel::SetInitialPlayoutDelay()");
3710 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3711 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3712 {
3713 _engineStatisticsPtr->SetLastError(
3714 VE_INVALID_ARGUMENT, kTraceError,
3715 "SetInitialPlayoutDelay() invalid min delay");
3716 return -1;
3717 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003718 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003719 {
3720 _engineStatisticsPtr->SetLastError(
3721 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3722 "SetInitialPlayoutDelay() failed to set min playout delay");
3723 return -1;
3724 }
3725 return 0;
3726}
3727
3728
niklase@google.com470e71d2011-07-07 08:21:25 +00003729int
3730Channel::SetMinimumPlayoutDelay(int delayMs)
3731{
3732 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3733 "Channel::SetMinimumPlayoutDelay()");
3734 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3735 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3736 {
3737 _engineStatisticsPtr->SetLastError(
3738 VE_INVALID_ARGUMENT, kTraceError,
3739 "SetMinimumPlayoutDelay() invalid min delay");
3740 return -1;
3741 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003742 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003743 {
3744 _engineStatisticsPtr->SetLastError(
3745 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3746 "SetMinimumPlayoutDelay() failed to set min playout delay");
3747 return -1;
3748 }
3749 return 0;
3750}
3751
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003752void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3753 uint32_t playout_timestamp = 0;
3754
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003755 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003756 // This can happen if this channel has not been received any RTP packet. In
3757 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003758 return;
3759 }
3760
3761 uint16_t delay_ms = 0;
3762 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3763 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3764 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3765 " delay from the ADM");
3766 _engineStatisticsPtr->SetLastError(
3767 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3768 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3769 return;
3770 }
3771
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003772 jitter_buffer_playout_timestamp_ = playout_timestamp;
3773
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003774 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003775 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003776
3777 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3778 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3779 playout_timestamp);
3780
3781 if (rtcp) {
3782 playout_timestamp_rtcp_ = playout_timestamp;
3783 } else {
3784 playout_timestamp_rtp_ = playout_timestamp;
3785 }
3786 playout_delay_ms_ = delay_ms;
3787}
3788
3789int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3790 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3791 "Channel::GetPlayoutTimestamp()");
3792 if (playout_timestamp_rtp_ == 0) {
3793 _engineStatisticsPtr->SetLastError(
3794 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3795 "GetPlayoutTimestamp() failed to retrieve timestamp");
3796 return -1;
3797 }
3798 timestamp = playout_timestamp_rtp_;
3799 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3800 VoEId(_instanceId,_channelId),
3801 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3802 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003803}
3804
3805int
3806Channel::SetInitTimestamp(unsigned int timestamp)
3807{
3808 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3809 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003810 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003811 {
3812 _engineStatisticsPtr->SetLastError(
3813 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
3814 return -1;
3815 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003816 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003817 {
3818 _engineStatisticsPtr->SetLastError(
3819 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3820 "SetInitTimestamp() failed to set timestamp");
3821 return -1;
3822 }
3823 return 0;
3824}
3825
3826int
3827Channel::SetInitSequenceNumber(short sequenceNumber)
3828{
3829 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3830 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003831 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003832 {
3833 _engineStatisticsPtr->SetLastError(
3834 VE_SENDING, kTraceError,
3835 "SetInitSequenceNumber() already sending");
3836 return -1;
3837 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003838 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003839 {
3840 _engineStatisticsPtr->SetLastError(
3841 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3842 "SetInitSequenceNumber() failed to set sequence number");
3843 return -1;
3844 }
3845 return 0;
3846}
3847
3848int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003849Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003850{
3851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3852 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003853 *rtpRtcpModule = _rtpRtcpModule.get();
3854 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003855 return 0;
3856}
3857
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003858// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3859// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003860int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003861Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003862{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00003863 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003864 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003865
3866 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003867 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003868
3869 if (_inputFilePlayerPtr == NULL)
3870 {
3871 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3872 VoEId(_instanceId, _channelId),
3873 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3874 " doesnt exist");
3875 return -1;
3876 }
3877
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003878 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003879 fileSamples,
3880 mixingFrequency) == -1)
3881 {
3882 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3883 VoEId(_instanceId, _channelId),
3884 "Channel::MixOrReplaceAudioWithFile() file mixing "
3885 "failed");
3886 return -1;
3887 }
3888 if (fileSamples == 0)
3889 {
3890 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3891 VoEId(_instanceId, _channelId),
3892 "Channel::MixOrReplaceAudioWithFile() file is ended");
3893 return 0;
3894 }
3895 }
3896
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003897 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003898
3899 if (_mixFileWithMicrophone)
3900 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003901 // Currently file stream is always mono.
3902 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003903 MixWithSat(_audioFrame.data_,
3904 _audioFrame.num_channels_,
3905 fileBuffer.get(),
3906 1,
3907 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003908 }
3909 else
3910 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003911 // Replace ACM audio with file.
3912 // Currently file stream is always mono.
3913 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003915 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003916 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003917 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003918 mixingFrequency,
3919 AudioFrame::kNormalSpeech,
3920 AudioFrame::kVadUnknown,
3921 1);
3922
3923 }
3924 return 0;
3925}
3926
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003927int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003928Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003929 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003930{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003931 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003932
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003933 scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003934 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003935
3936 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003937 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003938
3939 if (_outputFilePlayerPtr == NULL)
3940 {
3941 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3942 VoEId(_instanceId, _channelId),
3943 "Channel::MixAudioWithFile() file mixing failed");
3944 return -1;
3945 }
3946
3947 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003948 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003949 fileSamples,
3950 mixingFrequency) == -1)
3951 {
3952 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3953 VoEId(_instanceId, _channelId),
3954 "Channel::MixAudioWithFile() file mixing failed");
3955 return -1;
3956 }
3957 }
3958
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003959 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003960 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003961 // Currently file stream is always mono.
3962 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003963 MixWithSat(audioFrame.data_,
3964 audioFrame.num_channels_,
3965 fileBuffer.get(),
3966 1,
3967 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003968 }
3969 else
3970 {
3971 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003972 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003973 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003974 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003975 return -1;
3976 }
3977
3978 return 0;
3979}
3980
3981int
3982Channel::InsertInbandDtmfTone()
3983{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003984 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003985 if (_inbandDtmfQueue.PendingDtmf() &&
3986 !_inbandDtmfGenerator.IsAddingTone() &&
3987 _inbandDtmfGenerator.DelaySinceLastTone() >
3988 kMinTelephoneEventSeparationMs)
3989 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003990 int8_t eventCode(0);
3991 uint16_t lengthMs(0);
3992 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003993
3994 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3995 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3996 if (_playInbandDtmfEvent)
3997 {
3998 // Add tone to output mixer using a reduced length to minimize
3999 // risk of echo.
4000 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4001 attenuationDb);
4002 }
4003 }
4004
4005 if (_inbandDtmfGenerator.IsAddingTone())
4006 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004007 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004008 _inbandDtmfGenerator.GetSampleRate(frequency);
4009
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004010 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004011 {
4012 // Update sample rate of Dtmf tone since the mixing frequency
4013 // has changed.
4014 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004015 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004016 // Reset the tone to be added taking the new sample rate into
4017 // account.
4018 _inbandDtmfGenerator.ResetTone();
4019 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004020
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004021 int16_t toneBuffer[320];
4022 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004023 // Get 10ms tone segment and set time since last tone to zero
4024 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4025 {
4026 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4027 VoEId(_instanceId, _channelId),
4028 "Channel::EncodeAndSend() inserting Dtmf failed");
4029 return -1;
4030 }
4031
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004032 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004033 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004034 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004035 sample++)
4036 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004037 for (int channel = 0;
4038 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004039 channel++)
4040 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004041 const int index = sample * _audioFrame.num_channels_ + channel;
4042 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004043 }
4044 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004045
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004046 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004047 } else
4048 {
4049 // Add 10ms to "delay-since-last-tone" counter
4050 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4051 }
4052 return 0;
4053}
4054
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004055int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00004056Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00004057{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004058 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004059 if (_transportPtr == NULL)
4060 {
4061 return -1;
4062 }
4063 if (!RTCP)
4064 {
4065 return _transportPtr->SendPacket(_channelId, data, len);
4066 }
4067 else
4068 {
4069 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4070 }
4071}
4072
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004073// Called for incoming RTP packets after successful RTP header parsing.
4074void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4075 uint16_t sequence_number) {
4076 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4077 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4078 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004079
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004080 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004081 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004082
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004083 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004084 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004085
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004086 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4087 // every incoming packet.
4088 uint32_t timestamp_diff_ms = (rtp_timestamp -
4089 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004090 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4091 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4092 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4093 // timestamp, the resulting difference is negative, but is set to zero.
4094 // This can happen when a network glitch causes a packet to arrive late,
4095 // and during long comfort noise periods with clock drift.
4096 timestamp_diff_ms = 0;
4097 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004098
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004099 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4100 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004101
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004102 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004103
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004104 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004105
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004106 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4107 _recPacketDelayMs = packet_delay_ms;
4108 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004109
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004110 if (_average_jitter_buffer_delay_us == 0) {
4111 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4112 return;
4113 }
4114
4115 // Filter average delay value using exponential filter (alpha is
4116 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4117 // risk of rounding error) and compensate for it in GetDelayEstimate()
4118 // later.
4119 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4120 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004121}
4122
4123void
4124Channel::RegisterReceiveCodecsToRTPModule()
4125{
4126 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4127 "Channel::RegisterReceiveCodecsToRTPModule()");
4128
4129
4130 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004131 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004132
4133 for (int idx = 0; idx < nSupportedCodecs; idx++)
4134 {
4135 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004136 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004137 (rtp_receiver_->RegisterReceivePayload(
4138 codec.plname,
4139 codec.pltype,
4140 codec.plfreq,
4141 codec.channels,
4142 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004143 {
4144 WEBRTC_TRACE(
4145 kTraceWarning,
4146 kTraceVoice,
4147 VoEId(_instanceId, _channelId),
4148 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4149 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4150 codec.plname, codec.pltype, codec.plfreq,
4151 codec.channels, codec.rate);
4152 }
4153 else
4154 {
4155 WEBRTC_TRACE(
4156 kTraceInfo,
4157 kTraceVoice,
4158 VoEId(_instanceId, _channelId),
4159 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004160 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004161 "receiver",
4162 codec.plname, codec.pltype, codec.plfreq,
4163 codec.channels, codec.rate);
4164 }
4165 }
4166}
4167
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004168int Channel::SetSecondarySendCodec(const CodecInst& codec,
4169 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004170 // Sanity check for payload type.
4171 if (red_payload_type < 0 || red_payload_type > 127) {
4172 _engineStatisticsPtr->SetLastError(
4173 VE_PLTYPE_ERROR, kTraceError,
4174 "SetRedPayloadType() invalid RED payload type");
4175 return -1;
4176 }
4177
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004178 if (SetRedPayloadType(red_payload_type) < 0) {
4179 _engineStatisticsPtr->SetLastError(
4180 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4181 "SetSecondarySendCodec() Failed to register RED ACM");
4182 return -1;
4183 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004184 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004185 _engineStatisticsPtr->SetLastError(
4186 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4187 "SetSecondarySendCodec() Failed to register secondary send codec in "
4188 "ACM");
4189 return -1;
4190 }
4191
4192 return 0;
4193}
4194
4195void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004196 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004197}
4198
4199int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004200 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004201 _engineStatisticsPtr->SetLastError(
4202 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4203 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4204 return -1;
4205 }
4206 return 0;
4207}
4208
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004209// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004210int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004211 CodecInst codec;
4212 bool found_red = false;
4213
4214 // Get default RED settings from the ACM database
4215 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4216 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004217 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004218 if (!STR_CASE_CMP(codec.plname, "RED")) {
4219 found_red = true;
4220 break;
4221 }
4222 }
4223
4224 if (!found_red) {
4225 _engineStatisticsPtr->SetLastError(
4226 VE_CODEC_ERROR, kTraceError,
4227 "SetRedPayloadType() RED is not supported");
4228 return -1;
4229 }
4230
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004231 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004232 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004233 _engineStatisticsPtr->SetLastError(
4234 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4235 "SetRedPayloadType() RED registration in ACM module failed");
4236 return -1;
4237 }
4238
4239 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4240 _engineStatisticsPtr->SetLastError(
4241 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4242 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4243 return -1;
4244 }
4245 return 0;
4246}
4247
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004248int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4249 unsigned char id) {
4250 int error = 0;
4251 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4252 if (enable) {
4253 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4254 }
4255 return error;
4256}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004257
wu@webrtc.org94454b72014-06-05 20:34:08 +00004258int32_t Channel::GetPlayoutFrequency() {
4259 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4260 CodecInst current_recive_codec;
4261 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4262 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4263 // Even though the actual sampling rate for G.722 audio is
4264 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4265 // 8,000 Hz because that value was erroneously assigned in
4266 // RFC 1890 and must remain unchanged for backward compatibility.
4267 playout_frequency = 8000;
4268 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4269 // We are resampling Opus internally to 32,000 Hz until all our
4270 // DSP routines can operate at 48,000 Hz, but the RTP clock
4271 // rate for the Opus payload format is standardized to 48,000 Hz,
4272 // because that is the maximum supported decoding sampling rate.
4273 playout_frequency = 48000;
4274 }
4275 }
4276 return playout_frequency;
4277}
4278
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004279int Channel::GetRTT() const {
4280 RTCPMethod method = _rtpRtcpModule->RTCP();
4281 if (method == kRtcpOff) {
4282 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4283 VoEId(_instanceId, _channelId),
4284 "GetRTPStatistics() RTCP is disabled => valid RTT "
4285 "measurements cannot be retrieved");
4286 return 0;
4287 }
4288 std::vector<RTCPReportBlock> report_blocks;
4289 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4290 if (report_blocks.empty()) {
4291 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4292 VoEId(_instanceId, _channelId),
4293 "GetRTPStatistics() failed to measure RTT since no "
4294 "RTCP packets have been received yet");
4295 return 0;
4296 }
4297
4298 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4299 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4300 for (; it != report_blocks.end(); ++it) {
4301 if (it->remoteSSRC == remoteSSRC)
4302 break;
4303 }
4304 if (it == report_blocks.end()) {
4305 // We have not received packets with SSRC matching the report blocks.
4306 // To calculate RTT we try with the SSRC of the first report block.
4307 // This is very important for send-only channels where we don't know
4308 // the SSRC of the other end.
4309 remoteSSRC = report_blocks[0].remoteSSRC;
4310 }
4311 uint16_t rtt = 0;
4312 uint16_t avg_rtt = 0;
4313 uint16_t max_rtt= 0;
4314 uint16_t min_rtt = 0;
4315 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4316 != 0) {
4317 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4318 VoEId(_instanceId, _channelId),
4319 "GetRTPStatistics() failed to retrieve RTT from "
4320 "the RTP/RTCP module");
4321 return 0;
4322 }
4323 return static_cast<int>(rtt);
4324}
4325
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004326} // namespace voe
4327} // namespace webrtc