blob: 063ffa680a771696757b3b4412eee6c8c1dfe212 [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
Henrik Lundin64dad832015-05-11 12:44:23 +020013#include <algorithm>
14
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000015#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000016#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000017#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020018#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000019#include "webrtc/modules/audio_device/include/audio_device.h"
20#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000021#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000022#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
23#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
24#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
25#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000026#include "webrtc/modules/utility/interface/audio_frame_operations.h"
27#include "webrtc/modules/utility/interface/process_thread.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000028#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
29#include "webrtc/system_wrappers/interface/logging.h"
30#include "webrtc/system_wrappers/interface/trace.h"
31#include "webrtc/voice_engine/include/voe_base.h"
32#include "webrtc/voice_engine/include/voe_external_media.h"
33#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
34#include "webrtc/voice_engine/output_mixer.h"
35#include "webrtc/voice_engine/statistics.h"
36#include "webrtc/voice_engine/transmit_mixer.h"
37#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000038
39#if defined(_WIN32)
40#include <Qos.h>
41#endif
42
andrew@webrtc.org50419b02012-11-14 19:07:54 +000043namespace webrtc {
44namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000045
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000046// Extend the default RTCP statistics struct with max_jitter, defined as the
47// maximum jitter value seen in an RTCP report block.
48struct ChannelStatistics : public RtcpStatistics {
49 ChannelStatistics() : rtcp(), max_jitter(0) {}
50
51 RtcpStatistics rtcp;
52 uint32_t max_jitter;
53};
54
55// Statistics callback, called at each generation of a new RTCP report block.
56class StatisticsProxy : public RtcpStatisticsCallback {
57 public:
58 StatisticsProxy(uint32_t ssrc)
59 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
60 ssrc_(ssrc) {}
61 virtual ~StatisticsProxy() {}
62
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000063 void StatisticsUpdated(const RtcpStatistics& statistics,
64 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000065 if (ssrc != ssrc_)
66 return;
67
68 CriticalSectionScoped cs(stats_lock_.get());
69 stats_.rtcp = statistics;
70 if (statistics.jitter > stats_.max_jitter) {
71 stats_.max_jitter = statistics.jitter;
72 }
73 }
74
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000075 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +000076
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000077 void ResetStatistics() {
78 CriticalSectionScoped cs(stats_lock_.get());
79 stats_ = ChannelStatistics();
80 }
81
82 ChannelStatistics GetStats() {
83 CriticalSectionScoped cs(stats_lock_.get());
84 return stats_;
85 }
86
87 private:
88 // StatisticsUpdated calls are triggered from threads in the RTP module,
89 // while GetStats calls can be triggered from the public voice engine API,
90 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000091 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000092 const uint32_t ssrc_;
93 ChannelStatistics stats_;
94};
95
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000096class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000097 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000098 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
99 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000100
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000101 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
102 // Not used for Voice Engine.
103 }
104
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000105 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
106 int64_t rtt,
107 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000108 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
109 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
110 // report for VoiceEngine?
111 if (report_blocks.empty())
112 return;
113
114 int fraction_lost_aggregate = 0;
115 int total_number_of_packets = 0;
116
117 // If receiving multiple report blocks, calculate the weighted average based
118 // on the number of packets a report refers to.
119 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
120 block_it != report_blocks.end(); ++block_it) {
121 // Find the previous extended high sequence number for this remote SSRC,
122 // to calculate the number of RTP packets this report refers to. Ignore if
123 // we haven't seen this SSRC before.
124 std::map<uint32_t, uint32_t>::iterator seq_num_it =
125 extended_max_sequence_number_.find(block_it->sourceSSRC);
126 int number_of_packets = 0;
127 if (seq_num_it != extended_max_sequence_number_.end()) {
128 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
129 }
130 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
131 total_number_of_packets += number_of_packets;
132
133 extended_max_sequence_number_[block_it->sourceSSRC] =
134 block_it->extendedHighSeqNum;
135 }
136 int weighted_fraction_lost = 0;
137 if (total_number_of_packets > 0) {
138 weighted_fraction_lost = (fraction_lost_aggregate +
139 total_number_of_packets / 2) / total_number_of_packets;
140 }
141 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000142 }
143
144 private:
145 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000146 // Maps remote side ssrc to extended highest sequence number received.
147 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000148};
149
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000151Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000152 uint8_t payloadType,
153 uint32_t timeStamp,
154 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 const RTPFragmentationHeader* fragmentation)
157{
158 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
159 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000160 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
161 frameType, payloadType, timeStamp,
162 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000163
164 if (_includeAudioLevelIndication)
165 {
166 // Store current audio level in the RTP/RTCP module.
167 // The level will be used in combination with voice-activity state
168 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000169 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 }
171
172 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
173 // packetization.
174 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000175 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 payloadType,
177 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000178 // Leaving the time when this frame was
179 // received from the capture device as
180 // undefined for voice for now.
181 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 payloadData,
183 payloadSize,
184 fragmentation) == -1)
185 {
186 _engineStatisticsPtr->SetLastError(
187 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
188 "Channel::SendData() failed to send data to RTP/RTCP module");
189 return -1;
190 }
191
192 _lastLocalTimeStamp = timeStamp;
193 _lastPayloadType = payloadType;
194
195 return 0;
196}
197
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000198int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000199Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000200{
201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000202 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000204 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000205 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 return 0;
207}
208
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000209int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000210Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000211{
212 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
213 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
214
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000215 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216 if (_rxVadObserverPtr)
217 {
218 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
219 }
220
221 return 0;
222}
223
224int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000225Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000226{
227 channel = VoEChannelId(channel);
228 assert(channel == _channelId);
229
230 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000231 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
232 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000234 CriticalSectionScoped cs(&_callbackCritSect);
235
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 if (_transportPtr == NULL)
237 {
238 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
239 "Channel::SendPacket() failed to send RTP packet due to"
240 " invalid transport object");
241 return -1;
242 }
243
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000244 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000245 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000247 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
248 bufferLength);
249 if (n < 0) {
250 std::string transport_name =
251 _externalTransport ? "external transport" : "WebRtc sockets";
252 WEBRTC_TRACE(kTraceError, kTraceVoice,
253 VoEId(_instanceId,_channelId),
254 "Channel::SendPacket() RTP transmission using %s failed",
255 transport_name.c_str());
256 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259}
260
261int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000262Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000263{
264 channel = VoEChannelId(channel);
265 assert(channel == _channelId);
266
267 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000268 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
269 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000271 CriticalSectionScoped cs(&_callbackCritSect);
272 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000274 WEBRTC_TRACE(kTraceError, kTraceVoice,
275 VoEId(_instanceId,_channelId),
276 "Channel::SendRTCPPacket() failed to send RTCP packet"
277 " due to invalid transport object");
278 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 }
280
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000281 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000282 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000284 int n = _transportPtr->SendRTCPPacket(channel,
285 bufferToSendPtr,
286 bufferLength);
287 if (n < 0) {
288 std::string transport_name =
289 _externalTransport ? "external transport" : "WebRtc sockets";
290 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
291 VoEId(_instanceId,_channelId),
292 "Channel::SendRTCPPacket() transmission using %s failed",
293 transport_name.c_str());
294 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000296 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000297}
298
299void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000300Channel::OnPlayTelephoneEvent(int32_t id,
301 uint8_t event,
302 uint16_t lengthMs,
303 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000304{
305 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
306 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000307 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
309 if (!_playOutbandDtmfEvent || (event > 15))
310 {
311 // Ignore callback since feedback is disabled or event is not a
312 // Dtmf tone event.
313 return;
314 }
315
316 assert(_outputMixerPtr != NULL);
317
318 // Start playing out the Dtmf tone (if playout is enabled).
319 // Reduce length of tone with 80ms to the reduce risk of echo.
320 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
321}
322
323void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000324Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000325{
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
327 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000328 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000329
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000330 // Update ssrc so that NTP for AV sync can be updated.
331 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332}
333
pbos@webrtc.org92135212013-05-14 08:31:39 +0000334void Channel::OnIncomingCSRCChanged(int32_t id,
335 uint32_t CSRC,
336 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000337{
338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
339 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
340 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000341}
342
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000343void Channel::ResetStatistics(uint32_t ssrc) {
344 StreamStatistician* statistician =
345 rtp_receive_statistics_->GetStatistician(ssrc);
346 if (statistician) {
347 statistician->ResetStatistics();
348 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000349 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000350}
351
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000352int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000353Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000354 int32_t id,
355 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000356 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000357 int frequency,
358 uint8_t channels,
359 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000360{
361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
362 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
363 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
364 id, payloadType, payloadName, frequency, channels, rate);
365
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000366 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000368 CodecInst receiveCodec = {0};
369 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000370
371 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 receiveCodec.plfreq = frequency;
373 receiveCodec.channels = channels;
374 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000375 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000376
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000377 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 receiveCodec.pacsize = dummyCodec.pacsize;
379
380 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000381 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 {
383 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000384 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 "Channel::OnInitializeDecoder() invalid codec ("
386 "pt=%d, name=%s) received - 1", payloadType, payloadName);
387 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
388 return -1;
389 }
390
391 return 0;
392}
393
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000394int32_t
395Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000396 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 const WebRtcRTPHeader* rtpHeader)
398{
399 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000400 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000401 " payloadType=%u, audioChannel=%u)",
402 payloadSize,
403 rtpHeader->header.payloadType,
404 rtpHeader->type.Audio.channel);
405
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000406 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 {
408 // Avoid inserting into NetEQ when we are not playing. Count the
409 // packet as discarded.
410 WEBRTC_TRACE(kTraceStream, kTraceVoice,
411 VoEId(_instanceId, _channelId),
412 "received packet is discarded since playing is not"
413 " activated");
414 _numberOfDiscardedPackets++;
415 return 0;
416 }
417
418 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000419 if (audio_coding_->IncomingPacket(payloadData,
420 payloadSize,
421 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 {
423 _engineStatisticsPtr->SetLastError(
424 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
425 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
426 return -1;
427 }
428
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000429 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 UpdatePacketDelay(rtpHeader->header.timestamp,
431 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000432
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000433 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000434 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
435 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000436
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000437 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000438 round_trip_time);
439 if (!nack_list.empty()) {
440 // Can't use nack_list.data() since it's not supported by all
441 // compilers.
442 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000443 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 return 0;
445}
446
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000447bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000448 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000449 RTPHeader header;
450 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
451 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
452 "IncomingPacket invalid RTP header");
453 return false;
454 }
455 header.payload_type_frequency =
456 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
457 if (header.payload_type_frequency < 0)
458 return false;
459 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
460}
461
pbos@webrtc.org92135212013-05-14 08:31:39 +0000462int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000463{
464 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
465 "Channel::GetAudioFrame(id=%d)", id);
466
467 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000468 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
469 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 {
471 WEBRTC_TRACE(kTraceError, kTraceVoice,
472 VoEId(_instanceId,_channelId),
473 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000474 // In all likelihood, the audio in this frame is garbage. We return an
475 // error so that the audio mixer module doesn't add it to the mix. As
476 // a result, it won't be played out and the actions skipped here are
477 // irrelevant.
478 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 }
480
481 if (_RxVadDetection)
482 {
483 UpdateRxVadDetection(audioFrame);
484 }
485
486 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000487 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000489 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000490
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000491 ChannelState::State state = channel_state_.Get();
492
493 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000494 int err = rx_audioproc_->ProcessStream(&audioFrame);
495 if (err) {
496 LOG(LS_ERROR) << "ProcessStream() error: " << err;
497 assert(false);
498 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 }
500
wu@webrtc.org63420662013-10-17 18:28:55 +0000501 float output_gain = 1.0f;
502 float left_pan = 1.0f;
503 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000505 CriticalSectionScoped cs(&volume_settings_critsect_);
506 output_gain = _outputGain;
507 left_pan = _panLeft;
508 right_pan= _panRight;
509 }
510
511 // Output volume scaling
512 if (output_gain < 0.99f || output_gain > 1.01f)
513 {
514 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 }
516
517 // Scale left and/or right channel(s) if stereo and master balance is
518 // active
519
wu@webrtc.org63420662013-10-17 18:28:55 +0000520 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000522 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000523 {
524 // Emulate stereo mode since panning is active.
525 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000526 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 }
528 // For true stereo mode (when we are receiving a stereo signal), no
529 // action is needed.
530
531 // Do the panning operation (the audio frame contains stereo at this
532 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000533 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 }
535
536 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000537 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000539 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 }
541
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 // External media
543 if (_outputExternalMedia)
544 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000545 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000546 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 if (_outputExternalMediaCallbackPtr)
548 {
549 _outputExternalMediaCallbackPtr->Process(
550 _channelId,
551 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000552 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000553 audioFrame.samples_per_channel_,
554 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 isStereo);
556 }
557 }
558
559 // Record playout if enabled
560 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000561 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562
563 if (_outputFileRecording && _outputFileRecorderPtr)
564 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000565 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 }
567 }
568
569 // Measure audio level (0-9)
570 _outputAudioLevel.ComputeLevel(audioFrame);
571
wu@webrtc.org94454b72014-06-05 20:34:08 +0000572 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
573 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000574 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000575 }
576
577 if (capture_start_rtp_time_stamp_ >= 0) {
578 // audioFrame.timestamp_ should be valid from now on.
579
580 // Compute elapsed time.
581 int64_t unwrap_timestamp =
582 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
583 audioFrame.elapsed_time_ms_ =
584 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
585 (GetPlayoutFrequency() / 1000);
586
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000587 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000588 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000589 // Compute ntp time.
590 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
591 audioFrame.timestamp_);
592 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
593 if (audioFrame.ntp_time_ms_ > 0) {
594 // Compute |capture_start_ntp_time_ms_| so that
595 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
596 capture_start_ntp_time_ms_ =
597 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
598 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000599 }
600 }
601
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 return 0;
603}
604
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000605int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000606Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000607{
608 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
609 "Channel::NeededFrequency(id=%d)", id);
610
611 int highestNeeded = 0;
612
613 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000614 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
616 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000617 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000619 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 }
621 else
622 {
623 highestNeeded = receiveFrequency;
624 }
625
626 // Special case, if we're playing a file on the playout side
627 // we take that frequency into consideration as well
628 // This is not needed on sending side, since the codec will
629 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000630 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000632 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000633 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 {
635 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
636 {
637 highestNeeded=_outputFilePlayerPtr->Frequency();
638 }
639 }
640 }
641
642 return(highestNeeded);
643}
644
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000645int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000646Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000647 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000648 uint32_t instanceId,
649 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000650{
651 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
652 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
653 channelId, instanceId);
654
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000655 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 if (channel == NULL)
657 {
658 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
659 VoEId(instanceId,channelId),
660 "Channel::CreateChannel() unable to allocate memory for"
661 " channel");
662 return -1;
663 }
664 return 0;
665}
666
667void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000668Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000669{
670 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
671 "Channel::PlayNotification(id=%d, durationMs=%d)",
672 id, durationMs);
673
674 // Not implement yet
675}
676
677void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000678Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000679{
680 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
681 "Channel::RecordNotification(id=%d, durationMs=%d)",
682 id, durationMs);
683
684 // Not implement yet
685}
686
687void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000688Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000689{
690 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
691 "Channel::PlayFileEnded(id=%d)", id);
692
693 if (id == _inputFilePlayerId)
694 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000695 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
697 VoEId(_instanceId,_channelId),
698 "Channel::PlayFileEnded() => input file player module is"
699 " shutdown");
700 }
701 else if (id == _outputFilePlayerId)
702 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000703 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
705 VoEId(_instanceId,_channelId),
706 "Channel::PlayFileEnded() => output file player module is"
707 " shutdown");
708 }
709}
710
711void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000712Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000713{
714 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
715 "Channel::RecordFileEnded(id=%d)", id);
716
717 assert(id == _outputFileRecorderId);
718
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000719 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720
721 _outputFileRecording = false;
722 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
723 VoEId(_instanceId,_channelId),
724 "Channel::RecordFileEnded() => output file recorder module is"
725 " shutdown");
726}
727
pbos@webrtc.org92135212013-05-14 08:31:39 +0000728Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000729 uint32_t instanceId,
730 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
732 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000733 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000735 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000736 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000737 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000738 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000739 rtp_receive_statistics_(ReceiveStatistics::Create(
740 Clock::GetRealTimeClock())),
741 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
742 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
743 this, this, rtp_payload_registry_.get())),
744 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000746 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000747 _inputFilePlayerPtr(NULL),
748 _outputFilePlayerPtr(NULL),
749 _outputFileRecorderPtr(NULL),
750 // Avoid conflict with other channels by adding 1024 - 1026,
751 // won't use as much as 1024 channels.
752 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
753 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
754 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000755 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000756 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
757 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000758 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 _inputExternalMediaCallbackPtr(NULL),
760 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000761 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
762 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000763 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000764 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000765 playout_timestamp_rtp_(0),
766 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000767 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000768 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000769 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000770 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000771 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
772 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000773 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000774 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000775 _outputMixerPtr(NULL),
776 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _moduleProcessThreadPtr(NULL),
778 _audioDeviceModulePtr(NULL),
779 _voiceEngineObserverPtr(NULL),
780 _callbackCritSectPtr(NULL),
781 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000782 _rxVadObserverPtr(NULL),
783 _oldVadDecision(-1),
784 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000785 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000786 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 _mute(false),
788 _panLeft(1.0f),
789 _panRight(1.0f),
790 _outputGain(1.0f),
791 _playOutbandDtmfEvent(false),
792 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000793 _lastLocalTimeStamp(0),
794 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000795 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000797 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000798 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 _previousTimestamp(0),
800 _recPacketDelayMs(20),
801 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000803 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000804 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000805 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200806 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
807 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
808 associate_send_channel_(ChannelOwner(nullptr))
niklase@google.com470e71d2011-07-07 08:21:25 +0000809{
810 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
811 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200812 AudioCodingModule::Config acm_config;
813 acm_config.id = VoEModuleId(instanceId, channelId);
814 if (config.Get<NetEqCapacityConfig>().enabled) {
815 // Clamping the buffer capacity at 20 packets. While going lower will
816 // probably work, it makes little sense.
817 acm_config.neteq_config.max_packets_in_buffer =
818 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
819 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200820 acm_config.neteq_config.enable_fast_accelerate =
821 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200822 audio_coding_.reset(AudioCodingModule::Create(acm_config));
823
niklase@google.com470e71d2011-07-07 08:21:25 +0000824 _inbandDtmfQueue.ResetDtmf();
825 _inbandDtmfGenerator.Init();
826 _outputAudioLevel.Clear();
827
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000828 RtpRtcp::Configuration configuration;
829 configuration.id = VoEModuleId(instanceId, channelId);
830 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000831 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000832 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000833 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000834 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000835
836 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000837
838 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
839 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
840 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000841
842 Config audioproc_config;
843 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
844 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000845}
846
847Channel::~Channel()
848{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000849 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
851 "Channel::~Channel() - dtor");
852
853 if (_outputExternalMedia)
854 {
855 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
856 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000857 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000858 {
859 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
860 }
861 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 StopPlayout();
863
864 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000865 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 if (_inputFilePlayerPtr)
867 {
868 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
869 _inputFilePlayerPtr->StopPlayingFile();
870 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
871 _inputFilePlayerPtr = NULL;
872 }
873 if (_outputFilePlayerPtr)
874 {
875 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
876 _outputFilePlayerPtr->StopPlayingFile();
877 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
878 _outputFilePlayerPtr = NULL;
879 }
880 if (_outputFileRecorderPtr)
881 {
882 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
883 _outputFileRecorderPtr->StopRecording();
884 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
885 _outputFileRecorderPtr = NULL;
886 }
887 }
888
889 // The order to safely shutdown modules in a channel is:
890 // 1. De-register callbacks in modules
891 // 2. De-register modules in process thread
892 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000893 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000894 {
895 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
896 VoEId(_instanceId,_channelId),
897 "~Channel() failed to de-register transport callback"
898 " (Audio coding module)");
899 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000900 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 {
902 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
903 VoEId(_instanceId,_channelId),
904 "~Channel() failed to de-register VAD callback"
905 " (Audio coding module)");
906 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000908 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
909
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 // End of modules shutdown
911
912 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000915 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000916}
917
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000918int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000919Channel::Init()
920{
921 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
922 "Channel::Init()");
923
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000924 channel_state_.Reset();
925
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 // --- Initial sanity
927
928 if ((_engineStatisticsPtr == NULL) ||
929 (_moduleProcessThreadPtr == NULL))
930 {
931 WEBRTC_TRACE(kTraceError, kTraceVoice,
932 VoEId(_instanceId,_channelId),
933 "Channel::Init() must call SetEngineInformation() first");
934 return -1;
935 }
936
937 // --- Add modules to process thread (for periodic schedulation)
938
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000939 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
940
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000941 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000942
Henrik Lundin45c64492015-03-30 19:00:44 +0200943 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000944#ifdef WEBRTC_CODEC_AVT
945 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200946 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000947#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200948 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 {
950 _engineStatisticsPtr->SetLastError(
951 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
952 "Channel::Init() unable to initialize the ACM - 1");
953 return -1;
954 }
955
956 // --- RTP/RTCP module initialization
957
958 // Ensure that RTCP is enabled by default for the created channel.
959 // Note that, the module will keep generating RTCP until it is explicitly
960 // disabled by the user.
961 // After StopListen (when no sockets exists), RTCP packets will no longer
962 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000963 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
964 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000965 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
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
1329 return 0;
1330}
1331
Ivo Creusenadf89b72015-04-29 16:03:33 +02001332void Channel::SetBitRate(int bitrate_bps) {
1333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1334 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1335 audio_coding_->SetBitRate(bitrate_bps);
1336}
1337
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001338void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001339 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001340 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1341
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001342 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001343 if (audio_coding_->SetPacketLossRate(
1344 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001345 assert(false); // This should not happen.
1346 }
1347}
1348
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001349int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001350Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1351{
1352 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1353 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001354 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 // To disable VAD, DTX must be disabled too
1356 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001357 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001358 {
1359 _engineStatisticsPtr->SetLastError(
1360 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1361 "SetVADStatus() failed to set VAD");
1362 return -1;
1363 }
1364 return 0;
1365}
1366
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001367int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001368Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1369{
1370 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1371 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001372 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 {
1374 _engineStatisticsPtr->SetLastError(
1375 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1376 "GetVADStatus() failed to get VAD status");
1377 return -1;
1378 }
1379 disabledDTX = !disabledDTX;
1380 return 0;
1381}
1382
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001383int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001384Channel::SetRecPayloadType(const CodecInst& codec)
1385{
1386 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1387 "Channel::SetRecPayloadType()");
1388
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001389 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 {
1391 _engineStatisticsPtr->SetLastError(
1392 VE_ALREADY_PLAYING, kTraceError,
1393 "SetRecPayloadType() unable to set PT while playing");
1394 return -1;
1395 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001396 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001397 {
1398 _engineStatisticsPtr->SetLastError(
1399 VE_ALREADY_LISTENING, kTraceError,
1400 "SetRecPayloadType() unable to set PT while listening");
1401 return -1;
1402 }
1403
1404 if (codec.pltype == -1)
1405 {
1406 // De-register the selected codec (RTP/RTCP module and ACM)
1407
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001408 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 CodecInst rxCodec = codec;
1410
1411 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001412 rtp_payload_registry_->ReceivePayloadType(
1413 rxCodec.plname,
1414 rxCodec.plfreq,
1415 rxCodec.channels,
1416 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1417 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001418 rxCodec.pltype = pltype;
1419
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001420 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001421 {
1422 _engineStatisticsPtr->SetLastError(
1423 VE_RTP_RTCP_MODULE_ERROR,
1424 kTraceError,
1425 "SetRecPayloadType() RTP/RTCP-module deregistration "
1426 "failed");
1427 return -1;
1428 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001429 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 {
1431 _engineStatisticsPtr->SetLastError(
1432 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1433 "SetRecPayloadType() ACM deregistration failed - 1");
1434 return -1;
1435 }
1436 return 0;
1437 }
1438
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001439 if (rtp_receiver_->RegisterReceivePayload(
1440 codec.plname,
1441 codec.pltype,
1442 codec.plfreq,
1443 codec.channels,
1444 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 {
1446 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001447 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1448 if (rtp_receiver_->RegisterReceivePayload(
1449 codec.plname,
1450 codec.pltype,
1451 codec.plfreq,
1452 codec.channels,
1453 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001454 {
1455 _engineStatisticsPtr->SetLastError(
1456 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1457 "SetRecPayloadType() RTP/RTCP-module registration failed");
1458 return -1;
1459 }
1460 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001461 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001463 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1464 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 {
1466 _engineStatisticsPtr->SetLastError(
1467 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1468 "SetRecPayloadType() ACM registration failed - 1");
1469 return -1;
1470 }
1471 }
1472 return 0;
1473}
1474
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001475int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001476Channel::GetRecPayloadType(CodecInst& codec)
1477{
1478 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1479 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001480 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001481 if (rtp_payload_registry_->ReceivePayloadType(
1482 codec.plname,
1483 codec.plfreq,
1484 codec.channels,
1485 (codec.rate < 0) ? 0 : codec.rate,
1486 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001487 {
1488 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001489 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001490 "GetRecPayloadType() failed to retrieve RX payload type");
1491 return -1;
1492 }
1493 codec.pltype = payloadType;
1494 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001495 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001496 return 0;
1497}
1498
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001499int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001500Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1501{
1502 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1503 "Channel::SetSendCNPayloadType()");
1504
1505 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001506 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001507 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001508 if (frequency == kFreq32000Hz)
1509 samplingFreqHz = 32000;
1510 else if (frequency == kFreq16000Hz)
1511 samplingFreqHz = 16000;
1512
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001513 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001514 {
1515 _engineStatisticsPtr->SetLastError(
1516 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1517 "SetSendCNPayloadType() failed to retrieve default CN codec "
1518 "settings");
1519 return -1;
1520 }
1521
1522 // Modify the payload type (must be set to dynamic range)
1523 codec.pltype = type;
1524
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001525 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001526 {
1527 _engineStatisticsPtr->SetLastError(
1528 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1529 "SetSendCNPayloadType() failed to register CN to ACM");
1530 return -1;
1531 }
1532
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001533 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001535 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1536 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 {
1538 _engineStatisticsPtr->SetLastError(
1539 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1540 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1541 "module");
1542 return -1;
1543 }
1544 }
1545 return 0;
1546}
1547
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001548int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001550 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001551
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001552 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001553 _engineStatisticsPtr->SetLastError(
1554 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001555 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001556 return -1;
1557 }
1558 return 0;
1559}
1560
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001561int Channel::SetOpusDtx(bool enable_dtx) {
1562 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1563 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001564 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001565 : audio_coding_->DisableOpusDtx();
1566 if (ret != 0) {
1567 _engineStatisticsPtr->SetLastError(
1568 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1569 return -1;
1570 }
1571 return 0;
1572}
1573
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001574int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001575{
1576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1577 "Channel::RegisterExternalTransport()");
1578
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001579 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001580
niklase@google.com470e71d2011-07-07 08:21:25 +00001581 if (_externalTransport)
1582 {
1583 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1584 kTraceError,
1585 "RegisterExternalTransport() external transport already enabled");
1586 return -1;
1587 }
1588 _externalTransport = true;
1589 _transportPtr = &transport;
1590 return 0;
1591}
1592
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001593int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001594Channel::DeRegisterExternalTransport()
1595{
1596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1597 "Channel::DeRegisterExternalTransport()");
1598
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001599 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001600
niklase@google.com470e71d2011-07-07 08:21:25 +00001601 if (!_transportPtr)
1602 {
1603 _engineStatisticsPtr->SetLastError(
1604 VE_INVALID_OPERATION, kTraceWarning,
1605 "DeRegisterExternalTransport() external transport already "
1606 "disabled");
1607 return 0;
1608 }
1609 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001610 _transportPtr = NULL;
1611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1612 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001613 return 0;
1614}
1615
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001616int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001617 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001618 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1619 "Channel::ReceivedRTPPacket()");
1620
1621 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001622 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001623
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001624 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001625 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001626 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1627 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1628 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001629 return -1;
1630 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001631 header.payload_type_frequency =
1632 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001633 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001634 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001635 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001636 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001637 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001638 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001639
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001640 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001641}
1642
1643bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001644 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001645 const RTPHeader& header,
1646 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001647 if (rtp_payload_registry_->IsRtx(header)) {
1648 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001649 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001650 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001651 assert(packet_length >= header.headerLength);
1652 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001653 PayloadUnion payload_specific;
1654 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001655 &payload_specific)) {
1656 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001657 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001658 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1659 payload_specific, in_order);
1660}
1661
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001662bool Channel::HandleRtxPacket(const uint8_t* packet,
1663 size_t packet_length,
1664 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001665 if (!rtp_payload_registry_->IsRtx(header))
1666 return false;
1667
1668 // Remove the RTX header and parse the original RTP header.
1669 if (packet_length < header.headerLength)
1670 return false;
1671 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1672 return false;
1673 if (restored_packet_in_use_) {
1674 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1675 "Multiple RTX headers detected, dropping packet");
1676 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001677 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001678 uint8_t* restored_packet_ptr = restored_packet_;
1679 if (!rtp_payload_registry_->RestoreOriginalPacket(
1680 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1681 header)) {
1682 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1683 "Incoming RTX packet: invalid RTP header");
1684 return false;
1685 }
1686 restored_packet_in_use_ = true;
1687 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1688 restored_packet_in_use_ = false;
1689 return ret;
1690}
1691
1692bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1693 StreamStatistician* statistician =
1694 rtp_receive_statistics_->GetStatistician(header.ssrc);
1695 if (!statistician)
1696 return false;
1697 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001698}
1699
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001700bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1701 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001702 // Retransmissions are handled separately if RTX is enabled.
1703 if (rtp_payload_registry_->RtxEnabled())
1704 return false;
1705 StreamStatistician* statistician =
1706 rtp_receive_statistics_->GetStatistician(header.ssrc);
1707 if (!statistician)
1708 return false;
1709 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001710 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001711 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001712 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001713 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001714}
1715
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001716int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001717 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1718 "Channel::ReceivedRTCPPacket()");
1719 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001720 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001721
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001722 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001723 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001724 _engineStatisticsPtr->SetLastError(
1725 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1726 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1727 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001728
Minyue2013aec2015-05-13 14:14:42 +02001729 int64_t rtt = GetRTT(true);
1730 if (rtt == 0) {
1731 // Waiting for valid RTT.
1732 return 0;
1733 }
1734 uint32_t ntp_secs = 0;
1735 uint32_t ntp_frac = 0;
1736 uint32_t rtp_timestamp = 0;
1737 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1738 &rtp_timestamp)) {
1739 // Waiting for RTCP.
1740 return 0;
1741 }
1742
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001743 {
1744 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001745 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001746 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001747 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001748}
1749
niklase@google.com470e71d2011-07-07 08:21:25 +00001750int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001751 bool loop,
1752 FileFormats format,
1753 int startPosition,
1754 float volumeScaling,
1755 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001756 const CodecInst* codecInst)
1757{
1758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1759 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1760 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1761 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1762 startPosition, stopPosition);
1763
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001764 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001765 {
1766 _engineStatisticsPtr->SetLastError(
1767 VE_ALREADY_PLAYING, kTraceError,
1768 "StartPlayingFileLocally() is already playing");
1769 return -1;
1770 }
1771
niklase@google.com470e71d2011-07-07 08:21:25 +00001772 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001773 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001774
1775 if (_outputFilePlayerPtr)
1776 {
1777 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1778 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1779 _outputFilePlayerPtr = NULL;
1780 }
1781
1782 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1783 _outputFilePlayerId, (const FileFormats)format);
1784
1785 if (_outputFilePlayerPtr == NULL)
1786 {
1787 _engineStatisticsPtr->SetLastError(
1788 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001789 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001790 return -1;
1791 }
1792
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001793 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001794
1795 if (_outputFilePlayerPtr->StartPlayingFile(
1796 fileName,
1797 loop,
1798 startPosition,
1799 volumeScaling,
1800 notificationTime,
1801 stopPosition,
1802 (const CodecInst*)codecInst) != 0)
1803 {
1804 _engineStatisticsPtr->SetLastError(
1805 VE_BAD_FILE, kTraceError,
1806 "StartPlayingFile() failed to start file playout");
1807 _outputFilePlayerPtr->StopPlayingFile();
1808 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1809 _outputFilePlayerPtr = NULL;
1810 return -1;
1811 }
1812 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001813 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001814 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001815
1816 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001817 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001818
1819 return 0;
1820}
1821
1822int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001823 FileFormats format,
1824 int startPosition,
1825 float volumeScaling,
1826 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001827 const CodecInst* codecInst)
1828{
1829 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1830 "Channel::StartPlayingFileLocally(format=%d,"
1831 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1832 format, volumeScaling, startPosition, stopPosition);
1833
1834 if(stream == NULL)
1835 {
1836 _engineStatisticsPtr->SetLastError(
1837 VE_BAD_FILE, kTraceError,
1838 "StartPlayingFileLocally() NULL as input stream");
1839 return -1;
1840 }
1841
1842
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001843 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001844 {
1845 _engineStatisticsPtr->SetLastError(
1846 VE_ALREADY_PLAYING, kTraceError,
1847 "StartPlayingFileLocally() is already playing");
1848 return -1;
1849 }
1850
niklase@google.com470e71d2011-07-07 08:21:25 +00001851 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001852 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001853
1854 // Destroy the old instance
1855 if (_outputFilePlayerPtr)
1856 {
1857 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1858 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1859 _outputFilePlayerPtr = NULL;
1860 }
1861
1862 // Create the instance
1863 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1864 _outputFilePlayerId,
1865 (const FileFormats)format);
1866
1867 if (_outputFilePlayerPtr == NULL)
1868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_INVALID_ARGUMENT, kTraceError,
1871 "StartPlayingFileLocally() filePlayer format isnot correct");
1872 return -1;
1873 }
1874
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001875 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001876
1877 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1878 volumeScaling,
1879 notificationTime,
1880 stopPosition, codecInst) != 0)
1881 {
1882 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1883 "StartPlayingFile() failed to "
1884 "start file playout");
1885 _outputFilePlayerPtr->StopPlayingFile();
1886 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1887 _outputFilePlayerPtr = NULL;
1888 return -1;
1889 }
1890 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001891 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001892 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001893
1894 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001895 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001896
niklase@google.com470e71d2011-07-07 08:21:25 +00001897 return 0;
1898}
1899
1900int Channel::StopPlayingFileLocally()
1901{
1902 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1903 "Channel::StopPlayingFileLocally()");
1904
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001905 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001906 {
1907 _engineStatisticsPtr->SetLastError(
1908 VE_INVALID_OPERATION, kTraceWarning,
1909 "StopPlayingFileLocally() isnot playing");
1910 return 0;
1911 }
1912
niklase@google.com470e71d2011-07-07 08:21:25 +00001913 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001914 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001915
1916 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_STOP_RECORDING_FAILED, kTraceError,
1920 "StopPlayingFile() could not stop playing");
1921 return -1;
1922 }
1923 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1924 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1925 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001926 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001927 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001928 // _fileCritSect cannot be taken while calling
1929 // SetAnonymousMixibilityStatus. Refer to comments in
1930 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001931 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1932 {
1933 _engineStatisticsPtr->SetLastError(
1934 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001935 "StopPlayingFile() failed to stop participant from playing as"
1936 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001937 return -1;
1938 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001939
1940 return 0;
1941}
1942
1943int Channel::IsPlayingFileLocally() const
1944{
1945 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1946 "Channel::IsPlayingFileLocally()");
1947
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001948 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001949}
1950
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001951int Channel::RegisterFilePlayingToMixer()
1952{
1953 // Return success for not registering for file playing to mixer if:
1954 // 1. playing file before playout is started on that channel.
1955 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001956 if (!channel_state_.Get().playing ||
1957 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001958 {
1959 return 0;
1960 }
1961
1962 // |_fileCritSect| cannot be taken while calling
1963 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1964 // frames can be pulled by the mixer. Since the frames are generated from
1965 // the file, _fileCritSect will be taken. This would result in a deadlock.
1966 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1967 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001968 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001969 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001970 _engineStatisticsPtr->SetLastError(
1971 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1972 "StartPlayingFile() failed to add participant as file to mixer");
1973 _outputFilePlayerPtr->StopPlayingFile();
1974 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1975 _outputFilePlayerPtr = NULL;
1976 return -1;
1977 }
1978
1979 return 0;
1980}
1981
niklase@google.com470e71d2011-07-07 08:21:25 +00001982int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001983 bool loop,
1984 FileFormats format,
1985 int startPosition,
1986 float volumeScaling,
1987 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001988 const CodecInst* codecInst)
1989{
1990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1991 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1992 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1993 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1994 startPosition, stopPosition);
1995
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001996 CriticalSectionScoped cs(&_fileCritSect);
1997
1998 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001999 {
2000 _engineStatisticsPtr->SetLastError(
2001 VE_ALREADY_PLAYING, kTraceWarning,
2002 "StartPlayingFileAsMicrophone() filePlayer is playing");
2003 return 0;
2004 }
2005
niklase@google.com470e71d2011-07-07 08:21:25 +00002006 // Destroy the old instance
2007 if (_inputFilePlayerPtr)
2008 {
2009 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2010 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2011 _inputFilePlayerPtr = NULL;
2012 }
2013
2014 // Create the instance
2015 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2016 _inputFilePlayerId, (const FileFormats)format);
2017
2018 if (_inputFilePlayerPtr == NULL)
2019 {
2020 _engineStatisticsPtr->SetLastError(
2021 VE_INVALID_ARGUMENT, kTraceError,
2022 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2023 return -1;
2024 }
2025
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002026 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002027
2028 if (_inputFilePlayerPtr->StartPlayingFile(
2029 fileName,
2030 loop,
2031 startPosition,
2032 volumeScaling,
2033 notificationTime,
2034 stopPosition,
2035 (const CodecInst*)codecInst) != 0)
2036 {
2037 _engineStatisticsPtr->SetLastError(
2038 VE_BAD_FILE, kTraceError,
2039 "StartPlayingFile() failed to start file playout");
2040 _inputFilePlayerPtr->StopPlayingFile();
2041 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2042 _inputFilePlayerPtr = NULL;
2043 return -1;
2044 }
2045 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002046 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002047
2048 return 0;
2049}
2050
2051int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002052 FileFormats format,
2053 int startPosition,
2054 float volumeScaling,
2055 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002056 const CodecInst* codecInst)
2057{
2058 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2059 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2060 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2061 format, volumeScaling, startPosition, stopPosition);
2062
2063 if(stream == NULL)
2064 {
2065 _engineStatisticsPtr->SetLastError(
2066 VE_BAD_FILE, kTraceError,
2067 "StartPlayingFileAsMicrophone NULL as input stream");
2068 return -1;
2069 }
2070
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002071 CriticalSectionScoped cs(&_fileCritSect);
2072
2073 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002074 {
2075 _engineStatisticsPtr->SetLastError(
2076 VE_ALREADY_PLAYING, kTraceWarning,
2077 "StartPlayingFileAsMicrophone() is playing");
2078 return 0;
2079 }
2080
niklase@google.com470e71d2011-07-07 08:21:25 +00002081 // Destroy the old instance
2082 if (_inputFilePlayerPtr)
2083 {
2084 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2085 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2086 _inputFilePlayerPtr = NULL;
2087 }
2088
2089 // Create the instance
2090 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2091 _inputFilePlayerId, (const FileFormats)format);
2092
2093 if (_inputFilePlayerPtr == NULL)
2094 {
2095 _engineStatisticsPtr->SetLastError(
2096 VE_INVALID_ARGUMENT, kTraceError,
2097 "StartPlayingInputFile() filePlayer format isnot correct");
2098 return -1;
2099 }
2100
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002101 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002102
2103 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2104 volumeScaling, notificationTime,
2105 stopPosition, codecInst) != 0)
2106 {
2107 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2108 "StartPlayingFile() failed to start "
2109 "file playout");
2110 _inputFilePlayerPtr->StopPlayingFile();
2111 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2112 _inputFilePlayerPtr = NULL;
2113 return -1;
2114 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002115
niklase@google.com470e71d2011-07-07 08:21:25 +00002116 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002117 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002118
2119 return 0;
2120}
2121
2122int Channel::StopPlayingFileAsMicrophone()
2123{
2124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2125 "Channel::StopPlayingFileAsMicrophone()");
2126
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002127 CriticalSectionScoped cs(&_fileCritSect);
2128
2129 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002130 {
2131 _engineStatisticsPtr->SetLastError(
2132 VE_INVALID_OPERATION, kTraceWarning,
2133 "StopPlayingFileAsMicrophone() isnot playing");
2134 return 0;
2135 }
2136
niklase@google.com470e71d2011-07-07 08:21:25 +00002137 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2138 {
2139 _engineStatisticsPtr->SetLastError(
2140 VE_STOP_RECORDING_FAILED, kTraceError,
2141 "StopPlayingFile() could not stop playing");
2142 return -1;
2143 }
2144 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2145 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2146 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002147 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002148
2149 return 0;
2150}
2151
2152int Channel::IsPlayingFileAsMicrophone() const
2153{
2154 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2155 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002156 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002157}
2158
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002159int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002160 const CodecInst* codecInst)
2161{
2162 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2163 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2164
2165 if (_outputFileRecording)
2166 {
2167 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2168 "StartRecordingPlayout() is already recording");
2169 return 0;
2170 }
2171
2172 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002173 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002174 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2175
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002176 if ((codecInst != NULL) &&
2177 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002178 {
2179 _engineStatisticsPtr->SetLastError(
2180 VE_BAD_ARGUMENT, kTraceError,
2181 "StartRecordingPlayout() invalid compression");
2182 return(-1);
2183 }
2184 if(codecInst == NULL)
2185 {
2186 format = kFileFormatPcm16kHzFile;
2187 codecInst=&dummyCodec;
2188 }
2189 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2190 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2191 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2192 {
2193 format = kFileFormatWavFile;
2194 }
2195 else
2196 {
2197 format = kFileFormatCompressedFile;
2198 }
2199
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002200 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002201
2202 // Destroy the old instance
2203 if (_outputFileRecorderPtr)
2204 {
2205 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2206 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2207 _outputFileRecorderPtr = NULL;
2208 }
2209
2210 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2211 _outputFileRecorderId, (const FileFormats)format);
2212 if (_outputFileRecorderPtr == NULL)
2213 {
2214 _engineStatisticsPtr->SetLastError(
2215 VE_INVALID_ARGUMENT, kTraceError,
2216 "StartRecordingPlayout() fileRecorder format isnot correct");
2217 return -1;
2218 }
2219
2220 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2221 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2222 {
2223 _engineStatisticsPtr->SetLastError(
2224 VE_BAD_FILE, kTraceError,
2225 "StartRecordingAudioFile() failed to start file recording");
2226 _outputFileRecorderPtr->StopRecording();
2227 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2228 _outputFileRecorderPtr = NULL;
2229 return -1;
2230 }
2231 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2232 _outputFileRecording = true;
2233
2234 return 0;
2235}
2236
2237int Channel::StartRecordingPlayout(OutStream* stream,
2238 const CodecInst* codecInst)
2239{
2240 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2241 "Channel::StartRecordingPlayout()");
2242
2243 if (_outputFileRecording)
2244 {
2245 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2246 "StartRecordingPlayout() is already recording");
2247 return 0;
2248 }
2249
2250 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002251 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002252 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2253
2254 if (codecInst != NULL && codecInst->channels != 1)
2255 {
2256 _engineStatisticsPtr->SetLastError(
2257 VE_BAD_ARGUMENT, kTraceError,
2258 "StartRecordingPlayout() invalid compression");
2259 return(-1);
2260 }
2261 if(codecInst == NULL)
2262 {
2263 format = kFileFormatPcm16kHzFile;
2264 codecInst=&dummyCodec;
2265 }
2266 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2267 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2268 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2269 {
2270 format = kFileFormatWavFile;
2271 }
2272 else
2273 {
2274 format = kFileFormatCompressedFile;
2275 }
2276
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002277 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002278
2279 // Destroy the old instance
2280 if (_outputFileRecorderPtr)
2281 {
2282 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2283 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2284 _outputFileRecorderPtr = NULL;
2285 }
2286
2287 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2288 _outputFileRecorderId, (const FileFormats)format);
2289 if (_outputFileRecorderPtr == NULL)
2290 {
2291 _engineStatisticsPtr->SetLastError(
2292 VE_INVALID_ARGUMENT, kTraceError,
2293 "StartRecordingPlayout() fileRecorder format isnot correct");
2294 return -1;
2295 }
2296
2297 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2298 notificationTime) != 0)
2299 {
2300 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2301 "StartRecordingPlayout() failed to "
2302 "start file recording");
2303 _outputFileRecorderPtr->StopRecording();
2304 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2305 _outputFileRecorderPtr = NULL;
2306 return -1;
2307 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002308
niklase@google.com470e71d2011-07-07 08:21:25 +00002309 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2310 _outputFileRecording = true;
2311
2312 return 0;
2313}
2314
2315int Channel::StopRecordingPlayout()
2316{
2317 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2318 "Channel::StopRecordingPlayout()");
2319
2320 if (!_outputFileRecording)
2321 {
2322 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2323 "StopRecordingPlayout() isnot recording");
2324 return -1;
2325 }
2326
2327
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002328 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002329
2330 if (_outputFileRecorderPtr->StopRecording() != 0)
2331 {
2332 _engineStatisticsPtr->SetLastError(
2333 VE_STOP_RECORDING_FAILED, kTraceError,
2334 "StopRecording() could not stop recording");
2335 return(-1);
2336 }
2337 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2338 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2339 _outputFileRecorderPtr = NULL;
2340 _outputFileRecording = false;
2341
2342 return 0;
2343}
2344
2345void
2346Channel::SetMixWithMicStatus(bool mix)
2347{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002348 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002349 _mixFileWithMicrophone=mix;
2350}
2351
2352int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002353Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002354{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002355 int8_t currentLevel = _outputAudioLevel.Level();
2356 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002357 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2358 VoEId(_instanceId,_channelId),
2359 "GetSpeechOutputLevel() => level=%u", level);
2360 return 0;
2361}
2362
2363int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002364Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002365{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002366 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2367 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002368 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2369 VoEId(_instanceId,_channelId),
2370 "GetSpeechOutputLevelFullRange() => level=%u", level);
2371 return 0;
2372}
2373
2374int
2375Channel::SetMute(bool enable)
2376{
wu@webrtc.org63420662013-10-17 18:28:55 +00002377 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2379 "Channel::SetMute(enable=%d)", enable);
2380 _mute = enable;
2381 return 0;
2382}
2383
2384bool
2385Channel::Mute() const
2386{
wu@webrtc.org63420662013-10-17 18:28:55 +00002387 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002388 return _mute;
2389}
2390
2391int
2392Channel::SetOutputVolumePan(float left, float right)
2393{
wu@webrtc.org63420662013-10-17 18:28:55 +00002394 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002395 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2396 "Channel::SetOutputVolumePan()");
2397 _panLeft = left;
2398 _panRight = right;
2399 return 0;
2400}
2401
2402int
2403Channel::GetOutputVolumePan(float& left, float& right) const
2404{
wu@webrtc.org63420662013-10-17 18:28:55 +00002405 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002406 left = _panLeft;
2407 right = _panRight;
2408 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2409 VoEId(_instanceId,_channelId),
2410 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2411 return 0;
2412}
2413
2414int
2415Channel::SetChannelOutputVolumeScaling(float scaling)
2416{
wu@webrtc.org63420662013-10-17 18:28:55 +00002417 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002418 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2419 "Channel::SetChannelOutputVolumeScaling()");
2420 _outputGain = scaling;
2421 return 0;
2422}
2423
2424int
2425Channel::GetChannelOutputVolumeScaling(float& scaling) const
2426{
wu@webrtc.org63420662013-10-17 18:28:55 +00002427 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002428 scaling = _outputGain;
2429 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2430 VoEId(_instanceId,_channelId),
2431 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2432 return 0;
2433}
2434
niklase@google.com470e71d2011-07-07 08:21:25 +00002435int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002436 int lengthMs, int attenuationDb,
2437 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002438{
2439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2440 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2441 playDtmfEvent);
2442
2443 _playOutbandDtmfEvent = playDtmfEvent;
2444
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002445 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002446 attenuationDb) != 0)
2447 {
2448 _engineStatisticsPtr->SetLastError(
2449 VE_SEND_DTMF_FAILED,
2450 kTraceWarning,
2451 "SendTelephoneEventOutband() failed to send event");
2452 return -1;
2453 }
2454 return 0;
2455}
2456
2457int Channel::SendTelephoneEventInband(unsigned char eventCode,
2458 int lengthMs,
2459 int attenuationDb,
2460 bool playDtmfEvent)
2461{
2462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2463 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2464 playDtmfEvent);
2465
2466 _playInbandDtmfEvent = playDtmfEvent;
2467 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2468
2469 return 0;
2470}
2471
2472int
niklase@google.com470e71d2011-07-07 08:21:25 +00002473Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2474{
2475 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2476 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002477 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002478 {
2479 _engineStatisticsPtr->SetLastError(
2480 VE_INVALID_ARGUMENT, kTraceError,
2481 "SetSendTelephoneEventPayloadType() invalid type");
2482 return -1;
2483 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002484 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002485 codec.plfreq = 8000;
2486 codec.pltype = type;
2487 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002488 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002489 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002490 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2491 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2492 _engineStatisticsPtr->SetLastError(
2493 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2494 "SetSendTelephoneEventPayloadType() failed to register send"
2495 "payload type");
2496 return -1;
2497 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002498 }
2499 _sendTelephoneEventPayloadType = type;
2500 return 0;
2501}
2502
2503int
2504Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2505{
2506 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2507 "Channel::GetSendTelephoneEventPayloadType()");
2508 type = _sendTelephoneEventPayloadType;
2509 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2510 VoEId(_instanceId,_channelId),
2511 "GetSendTelephoneEventPayloadType() => type=%u", type);
2512 return 0;
2513}
2514
niklase@google.com470e71d2011-07-07 08:21:25 +00002515int
2516Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2517{
2518 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2519 "Channel::UpdateRxVadDetection()");
2520
2521 int vadDecision = 1;
2522
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002523 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002524
2525 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2526 {
2527 OnRxVadDetected(vadDecision);
2528 _oldVadDecision = vadDecision;
2529 }
2530
2531 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2532 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2533 vadDecision);
2534 return 0;
2535}
2536
2537int
2538Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2539{
2540 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2541 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002542 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002543
2544 if (_rxVadObserverPtr)
2545 {
2546 _engineStatisticsPtr->SetLastError(
2547 VE_INVALID_OPERATION, kTraceError,
2548 "RegisterRxVadObserver() observer already enabled");
2549 return -1;
2550 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002551 _rxVadObserverPtr = &observer;
2552 _RxVadDetection = true;
2553 return 0;
2554}
2555
2556int
2557Channel::DeRegisterRxVadObserver()
2558{
2559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2560 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002561 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002562
2563 if (!_rxVadObserverPtr)
2564 {
2565 _engineStatisticsPtr->SetLastError(
2566 VE_INVALID_OPERATION, kTraceWarning,
2567 "DeRegisterRxVadObserver() observer already disabled");
2568 return 0;
2569 }
2570 _rxVadObserverPtr = NULL;
2571 _RxVadDetection = false;
2572 return 0;
2573}
2574
2575int
2576Channel::VoiceActivityIndicator(int &activity)
2577{
2578 activity = _sendFrameType;
2579
2580 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002581 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002582 return 0;
2583}
2584
2585#ifdef WEBRTC_VOICE_ENGINE_AGC
2586
2587int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002588Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002589{
2590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2591 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2592 (int)enable, (int)mode);
2593
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002594 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002595 switch (mode)
2596 {
2597 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002598 break;
2599 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002600 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002601 break;
2602 case kAgcFixedDigital:
2603 agcMode = GainControl::kFixedDigital;
2604 break;
2605 case kAgcAdaptiveDigital:
2606 agcMode =GainControl::kAdaptiveDigital;
2607 break;
2608 default:
2609 _engineStatisticsPtr->SetLastError(
2610 VE_INVALID_ARGUMENT, kTraceError,
2611 "SetRxAgcStatus() invalid Agc mode");
2612 return -1;
2613 }
2614
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002615 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 {
2617 _engineStatisticsPtr->SetLastError(
2618 VE_APM_ERROR, kTraceError,
2619 "SetRxAgcStatus() failed to set Agc mode");
2620 return -1;
2621 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002622 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002623 {
2624 _engineStatisticsPtr->SetLastError(
2625 VE_APM_ERROR, kTraceError,
2626 "SetRxAgcStatus() failed to set Agc state");
2627 return -1;
2628 }
2629
2630 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002631 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002632
2633 return 0;
2634}
2635
2636int
2637Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2638{
2639 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2640 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2641
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002642 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002643 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002644 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002645
2646 enabled = enable;
2647
2648 switch (agcMode)
2649 {
2650 case GainControl::kFixedDigital:
2651 mode = kAgcFixedDigital;
2652 break;
2653 case GainControl::kAdaptiveDigital:
2654 mode = kAgcAdaptiveDigital;
2655 break;
2656 default:
2657 _engineStatisticsPtr->SetLastError(
2658 VE_APM_ERROR, kTraceError,
2659 "GetRxAgcStatus() invalid Agc mode");
2660 return -1;
2661 }
2662
2663 return 0;
2664}
2665
2666int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002667Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002668{
2669 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2670 "Channel::SetRxAgcConfig()");
2671
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002672 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002673 config.targetLeveldBOv) != 0)
2674 {
2675 _engineStatisticsPtr->SetLastError(
2676 VE_APM_ERROR, kTraceError,
2677 "SetRxAgcConfig() failed to set target peak |level|"
2678 "(or envelope) of the Agc");
2679 return -1;
2680 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002681 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002682 config.digitalCompressionGaindB) != 0)
2683 {
2684 _engineStatisticsPtr->SetLastError(
2685 VE_APM_ERROR, kTraceError,
2686 "SetRxAgcConfig() failed to set the range in |gain| the"
2687 " digital compression stage may apply");
2688 return -1;
2689 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002690 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002691 config.limiterEnable) != 0)
2692 {
2693 _engineStatisticsPtr->SetLastError(
2694 VE_APM_ERROR, kTraceError,
2695 "SetRxAgcConfig() failed to set hard limiter to the signal");
2696 return -1;
2697 }
2698
2699 return 0;
2700}
2701
2702int
2703Channel::GetRxAgcConfig(AgcConfig& config)
2704{
2705 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2706 "Channel::GetRxAgcConfig(config=%?)");
2707
2708 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002709 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002710 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002711 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002712 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002713 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002714
2715 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2716 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2717 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2718 " limiterEnable=%d",
2719 config.targetLeveldBOv,
2720 config.digitalCompressionGaindB,
2721 config.limiterEnable);
2722
2723 return 0;
2724}
2725
2726#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2727
2728#ifdef WEBRTC_VOICE_ENGINE_NR
2729
2730int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002731Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002732{
2733 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2734 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2735 (int)enable, (int)mode);
2736
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002737 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002738 switch (mode)
2739 {
2740
2741 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002742 break;
2743 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002744 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002745 break;
2746 case kNsConference:
2747 nsLevel = NoiseSuppression::kHigh;
2748 break;
2749 case kNsLowSuppression:
2750 nsLevel = NoiseSuppression::kLow;
2751 break;
2752 case kNsModerateSuppression:
2753 nsLevel = NoiseSuppression::kModerate;
2754 break;
2755 case kNsHighSuppression:
2756 nsLevel = NoiseSuppression::kHigh;
2757 break;
2758 case kNsVeryHighSuppression:
2759 nsLevel = NoiseSuppression::kVeryHigh;
2760 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 }
2762
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002763 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 != 0)
2765 {
2766 _engineStatisticsPtr->SetLastError(
2767 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002768 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002769 return -1;
2770 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002771 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002772 {
2773 _engineStatisticsPtr->SetLastError(
2774 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002775 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002776 return -1;
2777 }
2778
2779 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002780 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002781
2782 return 0;
2783}
2784
2785int
2786Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2787{
2788 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2789 "Channel::GetRxNsStatus(enable=?, mode=?)");
2790
2791 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002792 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002793 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002794 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002795
2796 enabled = enable;
2797
2798 switch (ncLevel)
2799 {
2800 case NoiseSuppression::kLow:
2801 mode = kNsLowSuppression;
2802 break;
2803 case NoiseSuppression::kModerate:
2804 mode = kNsModerateSuppression;
2805 break;
2806 case NoiseSuppression::kHigh:
2807 mode = kNsHighSuppression;
2808 break;
2809 case NoiseSuppression::kVeryHigh:
2810 mode = kNsVeryHighSuppression;
2811 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002812 }
2813
2814 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2815 VoEId(_instanceId,_channelId),
2816 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2817 return 0;
2818}
2819
2820#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2821
2822int
niklase@google.com470e71d2011-07-07 08:21:25 +00002823Channel::SetLocalSSRC(unsigned int ssrc)
2824{
2825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2826 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002827 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002828 {
2829 _engineStatisticsPtr->SetLastError(
2830 VE_ALREADY_SENDING, kTraceError,
2831 "SetLocalSSRC() already sending");
2832 return -1;
2833 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002834 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002835 return 0;
2836}
2837
2838int
2839Channel::GetLocalSSRC(unsigned int& ssrc)
2840{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002841 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002842 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2843 VoEId(_instanceId,_channelId),
2844 "GetLocalSSRC() => ssrc=%lu", ssrc);
2845 return 0;
2846}
2847
2848int
2849Channel::GetRemoteSSRC(unsigned int& ssrc)
2850{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002851 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002852 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2853 VoEId(_instanceId,_channelId),
2854 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2855 return 0;
2856}
2857
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002858int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002859 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002860 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002861}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002862
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002863int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2864 unsigned char id) {
2865 rtp_header_parser_->DeregisterRtpHeaderExtension(
2866 kRtpExtensionAudioLevel);
2867 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2868 kRtpExtensionAudioLevel, id)) {
2869 return -1;
2870 }
2871 return 0;
2872}
2873
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002874int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2875 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2876}
2877
2878int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2879 rtp_header_parser_->DeregisterRtpHeaderExtension(
2880 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002881 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2882 kRtpExtensionAbsoluteSendTime, id)) {
2883 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002884 }
2885 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002886}
2887
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002888void Channel::SetRTCPStatus(bool enable) {
2889 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2890 "Channel::SetRTCPStatus()");
2891 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002892}
2893
2894int
2895Channel::GetRTCPStatus(bool& enabled)
2896{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002897 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002898 enabled = (method != kRtcpOff);
2899 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2900 VoEId(_instanceId,_channelId),
2901 "GetRTCPStatus() => enabled=%d", enabled);
2902 return 0;
2903}
2904
2905int
2906Channel::SetRTCP_CNAME(const char cName[256])
2907{
2908 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2909 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002910 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002911 {
2912 _engineStatisticsPtr->SetLastError(
2913 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2914 "SetRTCP_CNAME() failed to set RTCP CNAME");
2915 return -1;
2916 }
2917 return 0;
2918}
2919
2920int
niklase@google.com470e71d2011-07-07 08:21:25 +00002921Channel::GetRemoteRTCP_CNAME(char cName[256])
2922{
2923 if (cName == NULL)
2924 {
2925 _engineStatisticsPtr->SetLastError(
2926 VE_INVALID_ARGUMENT, kTraceError,
2927 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2928 return -1;
2929 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002930 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002931 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002932 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002933 {
2934 _engineStatisticsPtr->SetLastError(
2935 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2936 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2937 return -1;
2938 }
2939 strcpy(cName, cname);
2940 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2941 VoEId(_instanceId, _channelId),
2942 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2943 return 0;
2944}
2945
2946int
2947Channel::GetRemoteRTCPData(
2948 unsigned int& NTPHigh,
2949 unsigned int& NTPLow,
2950 unsigned int& timestamp,
2951 unsigned int& playoutTimestamp,
2952 unsigned int* jitter,
2953 unsigned short* fractionLost)
2954{
2955 // --- Information from sender info in received Sender Reports
2956
2957 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002958 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002959 {
2960 _engineStatisticsPtr->SetLastError(
2961 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002962 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002963 "side");
2964 return -1;
2965 }
2966
2967 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2968 // and octet count)
2969 NTPHigh = senderInfo.NTPseconds;
2970 NTPLow = senderInfo.NTPfraction;
2971 timestamp = senderInfo.RTPtimeStamp;
2972
2973 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2974 VoEId(_instanceId, _channelId),
2975 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2976 "timestamp=%lu",
2977 NTPHigh, NTPLow, timestamp);
2978
2979 // --- Locally derived information
2980
2981 // This value is updated on each incoming RTCP packet (0 when no packet
2982 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002983 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002984
2985 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2986 VoEId(_instanceId, _channelId),
2987 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002988 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002989
2990 if (NULL != jitter || NULL != fractionLost)
2991 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002992 // Get all RTCP receiver report blocks that have been received on this
2993 // channel. If we receive RTP packets from a remote source we know the
2994 // remote SSRC and use the report block from him.
2995 // Otherwise use the first report block.
2996 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002997 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002998 remote_stats.empty()) {
2999 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3000 VoEId(_instanceId, _channelId),
3001 "GetRemoteRTCPData() failed to measure statistics due"
3002 " to lack of received RTP and/or RTCP packets");
3003 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003004 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003005
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003006 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003007 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3008 for (; it != remote_stats.end(); ++it) {
3009 if (it->remoteSSRC == remoteSSRC)
3010 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003011 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003012
3013 if (it == remote_stats.end()) {
3014 // If we have not received any RTCP packets from this SSRC it probably
3015 // means that we have not received any RTP packets.
3016 // Use the first received report block instead.
3017 it = remote_stats.begin();
3018 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003019 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003020
xians@webrtc.org79af7342012-01-31 12:22:14 +00003021 if (jitter) {
3022 *jitter = it->jitter;
3023 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3024 VoEId(_instanceId, _channelId),
3025 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3026 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003027
xians@webrtc.org79af7342012-01-31 12:22:14 +00003028 if (fractionLost) {
3029 *fractionLost = it->fractionLost;
3030 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3031 VoEId(_instanceId, _channelId),
3032 "GetRemoteRTCPData() => fractionLost = %lu",
3033 *fractionLost);
3034 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003035 }
3036 return 0;
3037}
3038
3039int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003040Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003041 unsigned int name,
3042 const char* data,
3043 unsigned short dataLengthInBytes)
3044{
3045 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3046 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003047 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003048 {
3049 _engineStatisticsPtr->SetLastError(
3050 VE_NOT_SENDING, kTraceError,
3051 "SendApplicationDefinedRTCPPacket() not sending");
3052 return -1;
3053 }
3054 if (NULL == data)
3055 {
3056 _engineStatisticsPtr->SetLastError(
3057 VE_INVALID_ARGUMENT, kTraceError,
3058 "SendApplicationDefinedRTCPPacket() invalid data value");
3059 return -1;
3060 }
3061 if (dataLengthInBytes % 4 != 0)
3062 {
3063 _engineStatisticsPtr->SetLastError(
3064 VE_INVALID_ARGUMENT, kTraceError,
3065 "SendApplicationDefinedRTCPPacket() invalid length value");
3066 return -1;
3067 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003068 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003069 if (status == kRtcpOff)
3070 {
3071 _engineStatisticsPtr->SetLastError(
3072 VE_RTCP_ERROR, kTraceError,
3073 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3074 return -1;
3075 }
3076
3077 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003078 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003079 subType,
3080 name,
3081 (const unsigned char*) data,
3082 dataLengthInBytes) != 0)
3083 {
3084 _engineStatisticsPtr->SetLastError(
3085 VE_SEND_ERROR, kTraceError,
3086 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3087 return -1;
3088 }
3089 return 0;
3090}
3091
3092int
3093Channel::GetRTPStatistics(
3094 unsigned int& averageJitterMs,
3095 unsigned int& maxJitterMs,
3096 unsigned int& discardedPackets)
3097{
niklase@google.com470e71d2011-07-07 08:21:25 +00003098 // The jitter statistics is updated for each received RTP packet and is
3099 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003100 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3101 // If RTCP is off, there is no timed thread in the RTCP module regularly
3102 // generating new stats, trigger the update manually here instead.
3103 StreamStatistician* statistician =
3104 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3105 if (statistician) {
3106 // Don't use returned statistics, use data from proxy instead so that
3107 // max jitter can be fetched atomically.
3108 RtcpStatistics s;
3109 statistician->GetStatistics(&s, true);
3110 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003111 }
3112
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003113 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003114 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003115 if (playoutFrequency > 0) {
3116 // Scale RTP statistics given the current playout frequency
3117 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3118 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 }
3120
3121 discardedPackets = _numberOfDiscardedPackets;
3122
3123 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3124 VoEId(_instanceId, _channelId),
3125 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003126 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 averageJitterMs, maxJitterMs, discardedPackets);
3128 return 0;
3129}
3130
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003131int Channel::GetRemoteRTCPReportBlocks(
3132 std::vector<ReportBlock>* report_blocks) {
3133 if (report_blocks == NULL) {
3134 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3135 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3136 return -1;
3137 }
3138
3139 // Get the report blocks from the latest received RTCP Sender or Receiver
3140 // Report. Each element in the vector contains the sender's SSRC and a
3141 // report block according to RFC 3550.
3142 std::vector<RTCPReportBlock> rtcp_report_blocks;
3143 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3144 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3145 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3146 return -1;
3147 }
3148
3149 if (rtcp_report_blocks.empty())
3150 return 0;
3151
3152 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3153 for (; it != rtcp_report_blocks.end(); ++it) {
3154 ReportBlock report_block;
3155 report_block.sender_SSRC = it->remoteSSRC;
3156 report_block.source_SSRC = it->sourceSSRC;
3157 report_block.fraction_lost = it->fractionLost;
3158 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3159 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3160 report_block.interarrival_jitter = it->jitter;
3161 report_block.last_SR_timestamp = it->lastSR;
3162 report_block.delay_since_last_SR = it->delaySinceLastSR;
3163 report_blocks->push_back(report_block);
3164 }
3165 return 0;
3166}
3167
niklase@google.com470e71d2011-07-07 08:21:25 +00003168int
3169Channel::GetRTPStatistics(CallStatistics& stats)
3170{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003171 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003172
3173 // The jitter statistics is updated for each received RTP packet and is
3174 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003175 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003176 StreamStatistician* statistician =
3177 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3178 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003179 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3180 _engineStatisticsPtr->SetLastError(
3181 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3182 "GetRTPStatistics() failed to read RTP statistics from the "
3183 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003184 }
3185
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003186 stats.fractionLost = statistics.fraction_lost;
3187 stats.cumulativeLost = statistics.cumulative_lost;
3188 stats.extendedMax = statistics.extended_max_sequence_number;
3189 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003190
3191 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3192 VoEId(_instanceId, _channelId),
3193 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003194 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003195 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3196 stats.jitterSamples);
3197
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003198 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003199 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003200 if (stats.rttMs == 0) {
3201 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3202 "GetRTPStatistics() failed to get RTT");
3203 } else {
3204 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003205 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003206 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003207
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003208 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003209
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003210 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003211 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003212 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003213 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003214
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003215 if (statistician) {
3216 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3217 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003218
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003219 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003220 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003221 {
3222 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3223 VoEId(_instanceId, _channelId),
3224 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003225 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003226 }
3227
3228 stats.bytesSent = bytesSent;
3229 stats.packetsSent = packetsSent;
3230 stats.bytesReceived = bytesReceived;
3231 stats.packetsReceived = packetsReceived;
3232
3233 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3234 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003235 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3236 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003237 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3238 stats.packetsReceived);
3239
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003240 // --- Timestamps
3241 {
3242 CriticalSectionScoped lock(ts_stats_lock_.get());
3243 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3244 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003245 return 0;
3246}
3247
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003248int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003250 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003251
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003252 if (enable) {
3253 if (redPayloadtype < 0 || redPayloadtype > 127) {
3254 _engineStatisticsPtr->SetLastError(
3255 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003256 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003257 return -1;
3258 }
3259
3260 if (SetRedPayloadType(redPayloadtype) < 0) {
3261 _engineStatisticsPtr->SetLastError(
3262 VE_CODEC_ERROR, kTraceError,
3263 "SetSecondarySendCodec() Failed to register RED ACM");
3264 return -1;
3265 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003266 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003267
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003268 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003269 _engineStatisticsPtr->SetLastError(
3270 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003271 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003272 return -1;
3273 }
3274 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003275}
3276
3277int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003278Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003279{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003280 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 if (enabled)
3282 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003283 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003284 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003285 {
3286 _engineStatisticsPtr->SetLastError(
3287 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003288 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003289 "module");
3290 return -1;
3291 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003292 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003293 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3294 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003295 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 enabled, redPayloadtype);
3297 return 0;
3298 }
3299 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3300 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003301 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003302 return 0;
3303}
3304
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003305int Channel::SetCodecFECStatus(bool enable) {
3306 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3307 "Channel::SetCodecFECStatus()");
3308
3309 if (audio_coding_->SetCodecFEC(enable) != 0) {
3310 _engineStatisticsPtr->SetLastError(
3311 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3312 "SetCodecFECStatus() failed to set FEC state");
3313 return -1;
3314 }
3315 return 0;
3316}
3317
3318bool Channel::GetCodecFECStatus() {
3319 bool enabled = audio_coding_->CodecFEC();
3320 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3321 VoEId(_instanceId, _channelId),
3322 "GetCodecFECStatus() => enabled=%d", enabled);
3323 return enabled;
3324}
3325
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003326void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3327 // None of these functions can fail.
3328 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003329 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3330 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003331 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003332 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003333 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003334 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003335}
3336
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003337// Called when we are missing one or more packets.
3338int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003339 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3340}
3341
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003342uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003343Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003344{
3345 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003346 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003347 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003348 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003349 return 0;
3350}
3351
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003352void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003353 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003354 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003355 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003356 CodecInst codec;
3357 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003358
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003359 if (!mono_recording_audio_.get()) {
3360 // Temporary space for DownConvertToCodecFormat.
3361 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003362 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003363 DownConvertToCodecFormat(audio_data,
3364 number_of_frames,
3365 number_of_channels,
3366 sample_rate,
3367 codec.channels,
3368 codec.plfreq,
3369 mono_recording_audio_.get(),
3370 &input_resampler_,
3371 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003372}
3373
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003374uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003375Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003376{
3377 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3378 "Channel::PrepareEncodeAndSend()");
3379
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003380 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003381 {
3382 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3383 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003384 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003385 }
3386
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003387 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003388 {
3389 MixOrReplaceAudioWithFile(mixingFrequency);
3390 }
3391
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003392 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3393 if (is_muted) {
3394 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003395 }
3396
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003397 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003398 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003399 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003400 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003401 if (_inputExternalMediaCallbackPtr)
3402 {
3403 _inputExternalMediaCallbackPtr->Process(
3404 _channelId,
3405 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003406 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003407 _audioFrame.samples_per_channel_,
3408 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003409 isStereo);
3410 }
3411 }
3412
3413 InsertInbandDtmfTone();
3414
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003415 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003416 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003417 if (is_muted) {
3418 rms_level_.ProcessMuted(length);
3419 } else {
3420 rms_level_.Process(_audioFrame.data_, length);
3421 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003422 }
3423
niklase@google.com470e71d2011-07-07 08:21:25 +00003424 return 0;
3425}
3426
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003427uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003428Channel::EncodeAndSend()
3429{
3430 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3431 "Channel::EncodeAndSend()");
3432
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003433 assert(_audioFrame.num_channels_ <= 2);
3434 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003435 {
3436 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3437 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003438 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003439 }
3440
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003441 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003442
3443 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3444
3445 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003446 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003447 // This call will trigger AudioPacketizationCallback::SendData if encoding
3448 // is done and payload is ready for packetization and transmission.
3449 // Otherwise, it will return without invoking the callback.
3450 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003451 {
3452 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3453 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003454 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003455 }
3456
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003457 _timeStamp += _audioFrame.samples_per_channel_;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003458 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003459}
3460
Minyue2013aec2015-05-13 14:14:42 +02003461void Channel::DisassociateSendChannel(int channel_id) {
3462 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3463 Channel* channel = associate_send_channel_.channel();
3464 if (channel && channel->ChannelId() == channel_id) {
3465 // If this channel is associated with a send channel of the specified
3466 // Channel ID, disassociate with it.
3467 ChannelOwner ref(NULL);
3468 associate_send_channel_ = ref;
3469 }
3470}
3471
niklase@google.com470e71d2011-07-07 08:21:25 +00003472int Channel::RegisterExternalMediaProcessing(
3473 ProcessingTypes type,
3474 VoEMediaProcess& processObject)
3475{
3476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3477 "Channel::RegisterExternalMediaProcessing()");
3478
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003479 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003480
3481 if (kPlaybackPerChannel == type)
3482 {
3483 if (_outputExternalMediaCallbackPtr)
3484 {
3485 _engineStatisticsPtr->SetLastError(
3486 VE_INVALID_OPERATION, kTraceError,
3487 "Channel::RegisterExternalMediaProcessing() "
3488 "output external media already enabled");
3489 return -1;
3490 }
3491 _outputExternalMediaCallbackPtr = &processObject;
3492 _outputExternalMedia = true;
3493 }
3494 else if (kRecordingPerChannel == type)
3495 {
3496 if (_inputExternalMediaCallbackPtr)
3497 {
3498 _engineStatisticsPtr->SetLastError(
3499 VE_INVALID_OPERATION, kTraceError,
3500 "Channel::RegisterExternalMediaProcessing() "
3501 "output external media already enabled");
3502 return -1;
3503 }
3504 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003505 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003506 }
3507 return 0;
3508}
3509
3510int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3511{
3512 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3513 "Channel::DeRegisterExternalMediaProcessing()");
3514
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003515 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003516
3517 if (kPlaybackPerChannel == type)
3518 {
3519 if (!_outputExternalMediaCallbackPtr)
3520 {
3521 _engineStatisticsPtr->SetLastError(
3522 VE_INVALID_OPERATION, kTraceWarning,
3523 "Channel::DeRegisterExternalMediaProcessing() "
3524 "output external media already disabled");
3525 return 0;
3526 }
3527 _outputExternalMedia = false;
3528 _outputExternalMediaCallbackPtr = NULL;
3529 }
3530 else if (kRecordingPerChannel == type)
3531 {
3532 if (!_inputExternalMediaCallbackPtr)
3533 {
3534 _engineStatisticsPtr->SetLastError(
3535 VE_INVALID_OPERATION, kTraceWarning,
3536 "Channel::DeRegisterExternalMediaProcessing() "
3537 "input external media already disabled");
3538 return 0;
3539 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003540 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003541 _inputExternalMediaCallbackPtr = NULL;
3542 }
3543
3544 return 0;
3545}
3546
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003547int Channel::SetExternalMixing(bool enabled) {
3548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3549 "Channel::SetExternalMixing(enabled=%d)", enabled);
3550
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003551 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003552 {
3553 _engineStatisticsPtr->SetLastError(
3554 VE_INVALID_OPERATION, kTraceError,
3555 "Channel::SetExternalMixing() "
3556 "external mixing cannot be changed while playing.");
3557 return -1;
3558 }
3559
3560 _externalMixing = enabled;
3561
3562 return 0;
3563}
3564
niklase@google.com470e71d2011-07-07 08:21:25 +00003565int
niklase@google.com470e71d2011-07-07 08:21:25 +00003566Channel::GetNetworkStatistics(NetworkStatistics& stats)
3567{
3568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3569 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003570 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003571}
3572
wu@webrtc.org24301a62013-12-13 19:17:43 +00003573void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3574 audio_coding_->GetDecodingCallStatistics(stats);
3575}
3576
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003577bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3578 int* playout_buffer_delay_ms) const {
3579 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003580 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003581 "Channel::GetDelayEstimate() no valid estimate.");
3582 return false;
3583 }
3584 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3585 _recPacketDelayMs;
3586 *playout_buffer_delay_ms = playout_delay_ms_;
3587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3588 "Channel::GetDelayEstimate()");
3589 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003590}
3591
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003592int Channel::SetInitialPlayoutDelay(int delay_ms)
3593{
3594 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3595 "Channel::SetInitialPlayoutDelay()");
3596 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3597 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3598 {
3599 _engineStatisticsPtr->SetLastError(
3600 VE_INVALID_ARGUMENT, kTraceError,
3601 "SetInitialPlayoutDelay() invalid min delay");
3602 return -1;
3603 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003604 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003605 {
3606 _engineStatisticsPtr->SetLastError(
3607 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3608 "SetInitialPlayoutDelay() failed to set min playout delay");
3609 return -1;
3610 }
3611 return 0;
3612}
3613
3614
niklase@google.com470e71d2011-07-07 08:21:25 +00003615int
3616Channel::SetMinimumPlayoutDelay(int delayMs)
3617{
3618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3619 "Channel::SetMinimumPlayoutDelay()");
3620 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3621 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3622 {
3623 _engineStatisticsPtr->SetLastError(
3624 VE_INVALID_ARGUMENT, kTraceError,
3625 "SetMinimumPlayoutDelay() invalid min delay");
3626 return -1;
3627 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003628 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003629 {
3630 _engineStatisticsPtr->SetLastError(
3631 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3632 "SetMinimumPlayoutDelay() failed to set min playout delay");
3633 return -1;
3634 }
3635 return 0;
3636}
3637
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003638void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3639 uint32_t playout_timestamp = 0;
3640
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003641 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003642 // This can happen if this channel has not been received any RTP packet. In
3643 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003644 return;
3645 }
3646
3647 uint16_t delay_ms = 0;
3648 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3649 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3650 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3651 " delay from the ADM");
3652 _engineStatisticsPtr->SetLastError(
3653 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3654 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3655 return;
3656 }
3657
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003658 jitter_buffer_playout_timestamp_ = playout_timestamp;
3659
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003660 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003661 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003662
3663 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3664 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3665 playout_timestamp);
3666
3667 if (rtcp) {
3668 playout_timestamp_rtcp_ = playout_timestamp;
3669 } else {
3670 playout_timestamp_rtp_ = playout_timestamp;
3671 }
3672 playout_delay_ms_ = delay_ms;
3673}
3674
3675int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3676 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3677 "Channel::GetPlayoutTimestamp()");
3678 if (playout_timestamp_rtp_ == 0) {
3679 _engineStatisticsPtr->SetLastError(
3680 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3681 "GetPlayoutTimestamp() failed to retrieve timestamp");
3682 return -1;
3683 }
3684 timestamp = playout_timestamp_rtp_;
3685 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3686 VoEId(_instanceId,_channelId),
3687 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3688 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003689}
3690
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003691int Channel::SetInitTimestamp(unsigned int timestamp) {
3692 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003693 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003694 if (channel_state_.Get().sending) {
3695 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3696 "SetInitTimestamp() already sending");
3697 return -1;
3698 }
3699 _rtpRtcpModule->SetStartTimestamp(timestamp);
3700 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003701}
3702
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003703int Channel::SetInitSequenceNumber(short sequenceNumber) {
3704 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3705 "Channel::SetInitSequenceNumber()");
3706 if (channel_state_.Get().sending) {
3707 _engineStatisticsPtr->SetLastError(
3708 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3709 return -1;
3710 }
3711 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3712 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003713}
3714
3715int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003716Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003717{
3718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3719 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003720 *rtpRtcpModule = _rtpRtcpModule.get();
3721 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 return 0;
3723}
3724
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003725// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3726// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003727int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003728Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003729{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003730 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003731 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003732
3733 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003734 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003735
3736 if (_inputFilePlayerPtr == NULL)
3737 {
3738 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3739 VoEId(_instanceId, _channelId),
3740 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3741 " doesnt exist");
3742 return -1;
3743 }
3744
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003745 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003746 fileSamples,
3747 mixingFrequency) == -1)
3748 {
3749 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3750 VoEId(_instanceId, _channelId),
3751 "Channel::MixOrReplaceAudioWithFile() file mixing "
3752 "failed");
3753 return -1;
3754 }
3755 if (fileSamples == 0)
3756 {
3757 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3758 VoEId(_instanceId, _channelId),
3759 "Channel::MixOrReplaceAudioWithFile() file is ended");
3760 return 0;
3761 }
3762 }
3763
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003764 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003765
3766 if (_mixFileWithMicrophone)
3767 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003768 // Currently file stream is always mono.
3769 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003770 MixWithSat(_audioFrame.data_,
3771 _audioFrame.num_channels_,
3772 fileBuffer.get(),
3773 1,
3774 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003775 }
3776 else
3777 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003778 // Replace ACM audio with file.
3779 // Currently file stream is always mono.
3780 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003781 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003782 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003783 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003784 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003785 mixingFrequency,
3786 AudioFrame::kNormalSpeech,
3787 AudioFrame::kVadUnknown,
3788 1);
3789
3790 }
3791 return 0;
3792}
3793
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003794int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003795Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003796 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003797{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003798 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003799
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003800 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003801 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003802
3803 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003804 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003805
3806 if (_outputFilePlayerPtr == NULL)
3807 {
3808 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3809 VoEId(_instanceId, _channelId),
3810 "Channel::MixAudioWithFile() file mixing failed");
3811 return -1;
3812 }
3813
3814 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003815 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003816 fileSamples,
3817 mixingFrequency) == -1)
3818 {
3819 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3820 VoEId(_instanceId, _channelId),
3821 "Channel::MixAudioWithFile() file mixing failed");
3822 return -1;
3823 }
3824 }
3825
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003826 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003827 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003828 // Currently file stream is always mono.
3829 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003830 MixWithSat(audioFrame.data_,
3831 audioFrame.num_channels_,
3832 fileBuffer.get(),
3833 1,
3834 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003835 }
3836 else
3837 {
3838 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003839 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003840 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003841 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003842 return -1;
3843 }
3844
3845 return 0;
3846}
3847
3848int
3849Channel::InsertInbandDtmfTone()
3850{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003851 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003852 if (_inbandDtmfQueue.PendingDtmf() &&
3853 !_inbandDtmfGenerator.IsAddingTone() &&
3854 _inbandDtmfGenerator.DelaySinceLastTone() >
3855 kMinTelephoneEventSeparationMs)
3856 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003857 int8_t eventCode(0);
3858 uint16_t lengthMs(0);
3859 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003860
3861 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3862 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3863 if (_playInbandDtmfEvent)
3864 {
3865 // Add tone to output mixer using a reduced length to minimize
3866 // risk of echo.
3867 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3868 attenuationDb);
3869 }
3870 }
3871
3872 if (_inbandDtmfGenerator.IsAddingTone())
3873 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003874 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003875 _inbandDtmfGenerator.GetSampleRate(frequency);
3876
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003877 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003878 {
3879 // Update sample rate of Dtmf tone since the mixing frequency
3880 // has changed.
3881 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003882 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003883 // Reset the tone to be added taking the new sample rate into
3884 // account.
3885 _inbandDtmfGenerator.ResetTone();
3886 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003887
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003888 int16_t toneBuffer[320];
3889 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 // Get 10ms tone segment and set time since last tone to zero
3891 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3892 {
3893 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3894 VoEId(_instanceId, _channelId),
3895 "Channel::EncodeAndSend() inserting Dtmf failed");
3896 return -1;
3897 }
3898
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003899 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003900 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003901 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003902 sample++)
3903 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003904 for (int channel = 0;
3905 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003906 channel++)
3907 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003908 const int index = sample * _audioFrame.num_channels_ + channel;
3909 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003910 }
3911 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003912
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003913 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 } else
3915 {
3916 // Add 10ms to "delay-since-last-tone" counter
3917 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3918 }
3919 return 0;
3920}
3921
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003922int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003923Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003924{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003925 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003926 if (_transportPtr == NULL)
3927 {
3928 return -1;
3929 }
3930 if (!RTCP)
3931 {
3932 return _transportPtr->SendPacket(_channelId, data, len);
3933 }
3934 else
3935 {
3936 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3937 }
3938}
3939
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003940// Called for incoming RTP packets after successful RTP header parsing.
3941void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3942 uint16_t sequence_number) {
3943 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3944 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3945 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003946
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003947 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003948 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003949
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00003950 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003951 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00003952
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003953 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3954 // every incoming packet.
3955 uint32_t timestamp_diff_ms = (rtp_timestamp -
3956 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003957 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3958 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3959 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3960 // timestamp, the resulting difference is negative, but is set to zero.
3961 // This can happen when a network glitch causes a packet to arrive late,
3962 // and during long comfort noise periods with clock drift.
3963 timestamp_diff_ms = 0;
3964 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003965
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3967 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003968
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003969 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003970
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003971 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003972
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003973 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3974 _recPacketDelayMs = packet_delay_ms;
3975 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003976
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003977 if (_average_jitter_buffer_delay_us == 0) {
3978 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3979 return;
3980 }
3981
3982 // Filter average delay value using exponential filter (alpha is
3983 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3984 // risk of rounding error) and compensate for it in GetDelayEstimate()
3985 // later.
3986 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3987 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00003988}
3989
3990void
3991Channel::RegisterReceiveCodecsToRTPModule()
3992{
3993 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3994 "Channel::RegisterReceiveCodecsToRTPModule()");
3995
3996
3997 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003998 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003999
4000 for (int idx = 0; idx < nSupportedCodecs; idx++)
4001 {
4002 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004003 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004004 (rtp_receiver_->RegisterReceivePayload(
4005 codec.plname,
4006 codec.pltype,
4007 codec.plfreq,
4008 codec.channels,
4009 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004010 {
4011 WEBRTC_TRACE(
4012 kTraceWarning,
4013 kTraceVoice,
4014 VoEId(_instanceId, _channelId),
4015 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4016 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4017 codec.plname, codec.pltype, codec.plfreq,
4018 codec.channels, codec.rate);
4019 }
4020 else
4021 {
4022 WEBRTC_TRACE(
4023 kTraceInfo,
4024 kTraceVoice,
4025 VoEId(_instanceId, _channelId),
4026 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004027 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004028 "receiver",
4029 codec.plname, codec.pltype, codec.plfreq,
4030 codec.channels, codec.rate);
4031 }
4032 }
4033}
4034
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004035// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004036int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004037 CodecInst codec;
4038 bool found_red = false;
4039
4040 // Get default RED settings from the ACM database
4041 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4042 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004043 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004044 if (!STR_CASE_CMP(codec.plname, "RED")) {
4045 found_red = true;
4046 break;
4047 }
4048 }
4049
4050 if (!found_red) {
4051 _engineStatisticsPtr->SetLastError(
4052 VE_CODEC_ERROR, kTraceError,
4053 "SetRedPayloadType() RED is not supported");
4054 return -1;
4055 }
4056
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004057 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004058 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004059 _engineStatisticsPtr->SetLastError(
4060 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4061 "SetRedPayloadType() RED registration in ACM module failed");
4062 return -1;
4063 }
4064
4065 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4066 _engineStatisticsPtr->SetLastError(
4067 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4068 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4069 return -1;
4070 }
4071 return 0;
4072}
4073
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004074int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4075 unsigned char id) {
4076 int error = 0;
4077 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4078 if (enable) {
4079 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4080 }
4081 return error;
4082}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004083
wu@webrtc.org94454b72014-06-05 20:34:08 +00004084int32_t Channel::GetPlayoutFrequency() {
4085 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4086 CodecInst current_recive_codec;
4087 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4088 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4089 // Even though the actual sampling rate for G.722 audio is
4090 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4091 // 8,000 Hz because that value was erroneously assigned in
4092 // RFC 1890 and must remain unchanged for backward compatibility.
4093 playout_frequency = 8000;
4094 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4095 // We are resampling Opus internally to 32,000 Hz until all our
4096 // DSP routines can operate at 48,000 Hz, but the RTP clock
4097 // rate for the Opus payload format is standardized to 48,000 Hz,
4098 // because that is the maximum supported decoding sampling rate.
4099 playout_frequency = 48000;
4100 }
4101 }
4102 return playout_frequency;
4103}
4104
Minyue2013aec2015-05-13 14:14:42 +02004105int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004106 RTCPMethod method = _rtpRtcpModule->RTCP();
4107 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004108 return 0;
4109 }
4110 std::vector<RTCPReportBlock> report_blocks;
4111 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004112
4113 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004114 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004115 if (allow_associate_channel) {
4116 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4117 Channel* channel = associate_send_channel_.channel();
4118 // Tries to get RTT from an associated channel. This is important for
4119 // receive-only channels.
4120 if (channel) {
4121 // To prevent infinite recursion and deadlock, calling GetRTT of
4122 // associate channel should always use "false" for argument:
4123 // |allow_associate_channel|.
4124 rtt = channel->GetRTT(false);
4125 }
4126 }
4127 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004128 }
4129
4130 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4131 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4132 for (; it != report_blocks.end(); ++it) {
4133 if (it->remoteSSRC == remoteSSRC)
4134 break;
4135 }
4136 if (it == report_blocks.end()) {
4137 // We have not received packets with SSRC matching the report blocks.
4138 // To calculate RTT we try with the SSRC of the first report block.
4139 // This is very important for send-only channels where we don't know
4140 // the SSRC of the other end.
4141 remoteSSRC = report_blocks[0].remoteSSRC;
4142 }
Minyue2013aec2015-05-13 14:14:42 +02004143
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004144 int64_t avg_rtt = 0;
4145 int64_t max_rtt= 0;
4146 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004147 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4148 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004149 return 0;
4150 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004151 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004152}
4153
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004154} // namespace voe
4155} // namespace webrtc