blob: 6ec001218c5f86a3bd199c885660ca13b2dd333a [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>
Tommif888bb52015-12-12 01:37:01 +010014#include <utility>
Henrik Lundin64dad832015-05-11 12:44:23 +020015
Ivo Creusenae856f22015-09-17 16:30:16 +020016#include "webrtc/base/checks.h"
tommi31fc21f2016-01-21 10:37:37 -080017#include "webrtc/base/criticalsection.h"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000018#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080019#include "webrtc/base/logging.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010020#include "webrtc/base/thread_checker.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000021#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000022#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020023#include "webrtc/config.h"
ossue3525782016-05-25 07:37:43 -070024#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000025#include "webrtc/modules/audio_device/include/audio_device.h"
26#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010027#include "webrtc/modules/include/module_common_types.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010028#include "webrtc/modules/pacing/packet_router.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010029#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
30#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
31#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000032#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010033#include "webrtc/modules/utility/include/audio_frame_operations.h"
34#include "webrtc/modules/utility/include/process_thread.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010035#include "webrtc/system_wrappers/include/trace.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000036#include "webrtc/voice_engine/include/voe_base.h"
37#include "webrtc/voice_engine/include/voe_external_media.h"
38#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
39#include "webrtc/voice_engine/output_mixer.h"
40#include "webrtc/voice_engine/statistics.h"
41#include "webrtc/voice_engine/transmit_mixer.h"
42#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000043
andrew@webrtc.org50419b02012-11-14 19:07:54 +000044namespace webrtc {
45namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000046
kwibergc8d071e2016-04-06 12:22:38 -070047namespace {
48
49bool RegisterReceiveCodec(std::unique_ptr<AudioCodingModule>* acm,
50 acm2::RentACodec* rac,
51 const CodecInst& ci) {
kwibergabe95ba2016-06-02 02:58:59 -070052 const int result = (*acm)->RegisterReceiveCodec(
53 ci, [&] { return rac->RentIsacDecoder(ci.plfreq); });
kwibergc8d071e2016-04-06 12:22:38 -070054 return result == 0;
55}
56
57} // namespace
58
solenberg8842c3e2016-03-11 03:06:41 -080059const int kTelephoneEventAttenuationdB = 10;
60
Stefan Holmerb86d4e42015-12-07 10:26:18 +010061class TransportFeedbackProxy : public TransportFeedbackObserver {
62 public:
63 TransportFeedbackProxy() : feedback_observer_(nullptr) {
64 pacer_thread_.DetachFromThread();
65 network_thread_.DetachFromThread();
66 }
67
68 void SetTransportFeedbackObserver(
69 TransportFeedbackObserver* feedback_observer) {
70 RTC_DCHECK(thread_checker_.CalledOnValidThread());
71 rtc::CritScope lock(&crit_);
72 feedback_observer_ = feedback_observer;
73 }
74
75 // Implements TransportFeedbackObserver.
76 void AddPacket(uint16_t sequence_number,
77 size_t length,
philipela1ed0b32016-06-01 06:31:17 -070078 bool was_paced,
79 int probe_cluster_id) override {
Stefan Holmerb86d4e42015-12-07 10:26:18 +010080 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
81 rtc::CritScope lock(&crit_);
82 if (feedback_observer_)
philipela1ed0b32016-06-01 06:31:17 -070083 feedback_observer_->AddPacket(sequence_number, length, was_paced,
84 probe_cluster_id);
Stefan Holmerb86d4e42015-12-07 10:26:18 +010085 }
86 void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
87 RTC_DCHECK(network_thread_.CalledOnValidThread());
88 rtc::CritScope lock(&crit_);
89 if (feedback_observer_)
90 feedback_observer_->OnTransportFeedback(feedback);
91 }
92
93 private:
94 rtc::CriticalSection crit_;
95 rtc::ThreadChecker thread_checker_;
96 rtc::ThreadChecker pacer_thread_;
97 rtc::ThreadChecker network_thread_;
98 TransportFeedbackObserver* feedback_observer_ GUARDED_BY(&crit_);
99};
100
101class TransportSequenceNumberProxy : public TransportSequenceNumberAllocator {
102 public:
103 TransportSequenceNumberProxy() : seq_num_allocator_(nullptr) {
104 pacer_thread_.DetachFromThread();
105 }
106
107 void SetSequenceNumberAllocator(
108 TransportSequenceNumberAllocator* seq_num_allocator) {
109 RTC_DCHECK(thread_checker_.CalledOnValidThread());
110 rtc::CritScope lock(&crit_);
111 seq_num_allocator_ = seq_num_allocator;
112 }
113
114 // Implements TransportSequenceNumberAllocator.
115 uint16_t AllocateSequenceNumber() override {
116 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
117 rtc::CritScope lock(&crit_);
118 if (!seq_num_allocator_)
119 return 0;
120 return seq_num_allocator_->AllocateSequenceNumber();
121 }
122
123 private:
124 rtc::CriticalSection crit_;
125 rtc::ThreadChecker thread_checker_;
126 rtc::ThreadChecker pacer_thread_;
127 TransportSequenceNumberAllocator* seq_num_allocator_ GUARDED_BY(&crit_);
128};
129
130class RtpPacketSenderProxy : public RtpPacketSender {
131 public:
kwiberg55b97fe2016-01-28 05:22:45 -0800132 RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {}
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100133
134 void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
135 RTC_DCHECK(thread_checker_.CalledOnValidThread());
136 rtc::CritScope lock(&crit_);
137 rtp_packet_sender_ = rtp_packet_sender;
138 }
139
140 // Implements RtpPacketSender.
141 void InsertPacket(Priority priority,
142 uint32_t ssrc,
143 uint16_t sequence_number,
144 int64_t capture_time_ms,
145 size_t bytes,
146 bool retransmission) override {
147 rtc::CritScope lock(&crit_);
148 if (rtp_packet_sender_) {
149 rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
150 capture_time_ms, bytes, retransmission);
151 }
152 }
153
154 private:
155 rtc::ThreadChecker thread_checker_;
156 rtc::CriticalSection crit_;
157 RtpPacketSender* rtp_packet_sender_ GUARDED_BY(&crit_);
158};
159
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000160// Extend the default RTCP statistics struct with max_jitter, defined as the
161// maximum jitter value seen in an RTCP report block.
162struct ChannelStatistics : public RtcpStatistics {
163 ChannelStatistics() : rtcp(), max_jitter(0) {}
164
165 RtcpStatistics rtcp;
166 uint32_t max_jitter;
167};
168
169// Statistics callback, called at each generation of a new RTCP report block.
170class StatisticsProxy : public RtcpStatisticsCallback {
171 public:
tommi31fc21f2016-01-21 10:37:37 -0800172 StatisticsProxy(uint32_t ssrc) : ssrc_(ssrc) {}
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000173 virtual ~StatisticsProxy() {}
174
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000175 void StatisticsUpdated(const RtcpStatistics& statistics,
176 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000177 if (ssrc != ssrc_)
178 return;
179
tommi31fc21f2016-01-21 10:37:37 -0800180 rtc::CritScope cs(&stats_lock_);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000181 stats_.rtcp = statistics;
182 if (statistics.jitter > stats_.max_jitter) {
183 stats_.max_jitter = statistics.jitter;
184 }
185 }
186
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000187 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000188
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000189 ChannelStatistics GetStats() {
tommi31fc21f2016-01-21 10:37:37 -0800190 rtc::CritScope cs(&stats_lock_);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000191 return stats_;
192 }
193
194 private:
195 // StatisticsUpdated calls are triggered from threads in the RTP module,
196 // while GetStats calls can be triggered from the public voice engine API,
197 // hence synchronization is needed.
tommi31fc21f2016-01-21 10:37:37 -0800198 rtc::CriticalSection stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000199 const uint32_t ssrc_;
200 ChannelStatistics stats_;
201};
202
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000203class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000204 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000205 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
206 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000207
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000208 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
209 // Not used for Voice Engine.
210 }
211
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000212 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
213 int64_t rtt,
214 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000215 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
216 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
217 // report for VoiceEngine?
218 if (report_blocks.empty())
219 return;
220
221 int fraction_lost_aggregate = 0;
222 int total_number_of_packets = 0;
223
224 // If receiving multiple report blocks, calculate the weighted average based
225 // on the number of packets a report refers to.
226 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
227 block_it != report_blocks.end(); ++block_it) {
228 // Find the previous extended high sequence number for this remote SSRC,
229 // to calculate the number of RTP packets this report refers to. Ignore if
230 // we haven't seen this SSRC before.
231 std::map<uint32_t, uint32_t>::iterator seq_num_it =
232 extended_max_sequence_number_.find(block_it->sourceSSRC);
233 int number_of_packets = 0;
234 if (seq_num_it != extended_max_sequence_number_.end()) {
235 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
236 }
237 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
238 total_number_of_packets += number_of_packets;
239
240 extended_max_sequence_number_[block_it->sourceSSRC] =
241 block_it->extendedHighSeqNum;
242 }
243 int weighted_fraction_lost = 0;
244 if (total_number_of_packets > 0) {
kwiberg55b97fe2016-01-28 05:22:45 -0800245 weighted_fraction_lost =
246 (fraction_lost_aggregate + total_number_of_packets / 2) /
247 total_number_of_packets;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000248 }
249 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000250 }
251
252 private:
253 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000254 // Maps remote side ssrc to extended highest sequence number received.
255 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000256};
257
kwiberg55b97fe2016-01-28 05:22:45 -0800258int32_t Channel::SendData(FrameType frameType,
259 uint8_t payloadType,
260 uint32_t timeStamp,
261 const uint8_t* payloadData,
262 size_t payloadSize,
263 const RTPFragmentationHeader* fragmentation) {
264 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
265 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
266 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
267 frameType, payloadType, timeStamp, payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000268
kwiberg55b97fe2016-01-28 05:22:45 -0800269 if (_includeAudioLevelIndication) {
270 // Store current audio level in the RTP/RTCP module.
271 // The level will be used in combination with voice-activity state
272 // (frameType) to add an RTP header extension
273 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
274 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000275
kwiberg55b97fe2016-01-28 05:22:45 -0800276 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
277 // packetization.
278 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
279 if (_rtpRtcpModule->SendOutgoingData(
280 (FrameType&)frameType, payloadType, timeStamp,
281 // Leaving the time when this frame was
282 // received from the capture device as
283 // undefined for voice for now.
284 -1, payloadData, payloadSize, fragmentation) == -1) {
285 _engineStatisticsPtr->SetLastError(
286 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
287 "Channel::SendData() failed to send data to RTP/RTCP module");
288 return -1;
289 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
kwiberg55b97fe2016-01-28 05:22:45 -0800291 _lastLocalTimeStamp = timeStamp;
292 _lastPayloadType = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293
kwiberg55b97fe2016-01-28 05:22:45 -0800294 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295}
296
kwiberg55b97fe2016-01-28 05:22:45 -0800297int32_t Channel::InFrameType(FrameType frame_type) {
298 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
299 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300
kwiberg55b97fe2016-01-28 05:22:45 -0800301 rtc::CritScope cs(&_callbackCritSect);
302 _sendFrameType = (frame_type == kAudioFrameSpeech);
303 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000304}
305
kwiberg55b97fe2016-01-28 05:22:45 -0800306int32_t Channel::OnRxVadDetected(int vadDecision) {
307 rtc::CritScope cs(&_callbackCritSect);
308 if (_rxVadObserverPtr) {
309 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
310 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
kwiberg55b97fe2016-01-28 05:22:45 -0800312 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000313}
314
stefan1d8a5062015-10-02 03:39:33 -0700315bool Channel::SendRtp(const uint8_t* data,
316 size_t len,
317 const PacketOptions& options) {
kwiberg55b97fe2016-01-28 05:22:45 -0800318 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
319 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000320
kwiberg55b97fe2016-01-28 05:22:45 -0800321 rtc::CritScope cs(&_callbackCritSect);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000322
kwiberg55b97fe2016-01-28 05:22:45 -0800323 if (_transportPtr == NULL) {
324 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
325 "Channel::SendPacket() failed to send RTP packet due to"
326 " invalid transport object");
327 return false;
328 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000329
kwiberg55b97fe2016-01-28 05:22:45 -0800330 uint8_t* bufferToSendPtr = (uint8_t*)data;
331 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000332
kwiberg55b97fe2016-01-28 05:22:45 -0800333 if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
334 std::string transport_name =
335 _externalTransport ? "external transport" : "WebRtc sockets";
336 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
337 "Channel::SendPacket() RTP transmission using %s failed",
338 transport_name.c_str());
339 return false;
340 }
341 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000342}
343
kwiberg55b97fe2016-01-28 05:22:45 -0800344bool Channel::SendRtcp(const uint8_t* data, size_t len) {
345 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
346 "Channel::SendRtcp(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347
kwiberg55b97fe2016-01-28 05:22:45 -0800348 rtc::CritScope cs(&_callbackCritSect);
349 if (_transportPtr == NULL) {
350 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
351 "Channel::SendRtcp() failed to send RTCP packet"
352 " due to invalid transport object");
353 return false;
354 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000355
kwiberg55b97fe2016-01-28 05:22:45 -0800356 uint8_t* bufferToSendPtr = (uint8_t*)data;
357 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000358
kwiberg55b97fe2016-01-28 05:22:45 -0800359 int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength);
360 if (n < 0) {
361 std::string transport_name =
362 _externalTransport ? "external transport" : "WebRtc sockets";
363 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
364 "Channel::SendRtcp() transmission using %s failed",
365 transport_name.c_str());
366 return false;
367 }
368 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000369}
370
kwiberg55b97fe2016-01-28 05:22:45 -0800371void Channel::OnIncomingSSRCChanged(uint32_t ssrc) {
372 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
373 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
kwiberg55b97fe2016-01-28 05:22:45 -0800375 // Update ssrc so that NTP for AV sync can be updated.
376 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000377}
378
Peter Boströmac547a62015-09-17 23:03:57 +0200379void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
381 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
382 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000383}
384
Peter Boströmac547a62015-09-17 23:03:57 +0200385int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000386 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000387 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000388 int frequency,
Peter Kasting69558702016-01-12 16:26:35 -0800389 size_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200390 uint32_t rate) {
kwiberg55b97fe2016-01-28 05:22:45 -0800391 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
392 "Channel::OnInitializeDecoder(payloadType=%d, "
393 "payloadName=%s, frequency=%u, channels=%" PRIuS ", rate=%u)",
394 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000395
kwiberg55b97fe2016-01-28 05:22:45 -0800396 CodecInst receiveCodec = {0};
397 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
kwiberg55b97fe2016-01-28 05:22:45 -0800399 receiveCodec.pltype = payloadType;
400 receiveCodec.plfreq = frequency;
401 receiveCodec.channels = channels;
402 receiveCodec.rate = rate;
403 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000404
kwiberg55b97fe2016-01-28 05:22:45 -0800405 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
406 receiveCodec.pacsize = dummyCodec.pacsize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000407
kwiberg55b97fe2016-01-28 05:22:45 -0800408 // Register the new codec to the ACM
kwibergc8d071e2016-04-06 12:22:38 -0700409 if (!RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, receiveCodec)) {
kwiberg55b97fe2016-01-28 05:22:45 -0800410 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
411 "Channel::OnInitializeDecoder() invalid codec ("
412 "pt=%d, name=%s) received - 1",
413 payloadType, payloadName);
414 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
415 return -1;
416 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000417
kwiberg55b97fe2016-01-28 05:22:45 -0800418 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000419}
420
kwiberg55b97fe2016-01-28 05:22:45 -0800421int32_t Channel::OnReceivedPayloadData(const uint8_t* payloadData,
422 size_t payloadSize,
423 const WebRtcRTPHeader* rtpHeader) {
424 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
425 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS
426 ","
427 " payloadType=%u, audioChannel=%" PRIuS ")",
428 payloadSize, rtpHeader->header.payloadType,
429 rtpHeader->type.Audio.channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000430
kwiberg55b97fe2016-01-28 05:22:45 -0800431 if (!channel_state_.Get().playing) {
432 // Avoid inserting into NetEQ when we are not playing. Count the
433 // packet as discarded.
434 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
435 "received packet is discarded since playing is not"
436 " activated");
437 _numberOfDiscardedPackets++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -0800439 }
440
441 // Push the incoming payload (parsed and ready for decoding) into the ACM
442 if (audio_coding_->IncomingPacket(payloadData, payloadSize, *rtpHeader) !=
443 0) {
444 _engineStatisticsPtr->SetLastError(
445 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
446 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
447 return -1;
448 }
449
450 // Update the packet delay.
451 UpdatePacketDelay(rtpHeader->header.timestamp,
452 rtpHeader->header.sequenceNumber);
453
454 int64_t round_trip_time = 0;
455 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time, NULL, NULL,
456 NULL);
457
458 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(round_trip_time);
459 if (!nack_list.empty()) {
460 // Can't use nack_list.data() since it's not supported by all
461 // compilers.
462 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
463 }
464 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465}
466
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000467bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000468 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000469 RTPHeader header;
470 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
471 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
472 "IncomingPacket invalid RTP header");
473 return false;
474 }
475 header.payload_type_frequency =
476 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
477 if (header.payload_type_frequency < 0)
478 return false;
479 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
480}
481
henrik.lundin42dda502016-05-18 05:36:01 -0700482MixerParticipant::AudioFrameInfo Channel::GetAudioFrameWithMuted(
483 int32_t id,
484 AudioFrame* audioFrame) {
kwiberg55b97fe2016-01-28 05:22:45 -0800485 if (event_log_) {
486 unsigned int ssrc;
487 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
488 event_log_->LogAudioPlayout(ssrc);
489 }
490 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
henrik.lundind4ccb002016-05-17 12:21:55 -0700491 bool muted;
492 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_, audioFrame,
493 &muted) == -1) {
kwiberg55b97fe2016-01-28 05:22:45 -0800494 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
495 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
496 // In all likelihood, the audio in this frame is garbage. We return an
497 // error so that the audio mixer module doesn't add it to the mix. As
498 // a result, it won't be played out and the actions skipped here are
499 // irrelevant.
henrik.lundin42dda502016-05-18 05:36:01 -0700500 return MixerParticipant::AudioFrameInfo::kError;
kwiberg55b97fe2016-01-28 05:22:45 -0800501 }
henrik.lundina89ab962016-05-18 08:52:45 -0700502
503 if (muted) {
504 // TODO(henrik.lundin): We should be able to do better than this. But we
505 // will have to go through all the cases below where the audio samples may
506 // be used, and handle the muted case in some way.
507 audioFrame->Mute();
508 }
kwiberg55b97fe2016-01-28 05:22:45 -0800509
510 if (_RxVadDetection) {
511 UpdateRxVadDetection(*audioFrame);
512 }
513
514 // Convert module ID to internal VoE channel ID
515 audioFrame->id_ = VoEChannelId(audioFrame->id_);
516 // Store speech type for dead-or-alive detection
517 _outputSpeechType = audioFrame->speech_type_;
518
519 ChannelState::State state = channel_state_.Get();
520
521 if (state.rx_apm_is_enabled) {
522 int err = rx_audioproc_->ProcessStream(audioFrame);
523 if (err) {
524 LOG(LS_ERROR) << "ProcessStream() error: " << err;
525 assert(false);
Ivo Creusenae856f22015-09-17 16:30:16 +0200526 }
kwiberg55b97fe2016-01-28 05:22:45 -0800527 }
528
529 {
530 // Pass the audio buffers to an optional sink callback, before applying
531 // scaling/panning, as that applies to the mix operation.
532 // External recipients of the audio (e.g. via AudioTrack), will do their
533 // own mixing/dynamic processing.
534 rtc::CritScope cs(&_callbackCritSect);
535 if (audio_sink_) {
536 AudioSinkInterface::Data data(
537 &audioFrame->data_[0], audioFrame->samples_per_channel_,
538 audioFrame->sample_rate_hz_, audioFrame->num_channels_,
539 audioFrame->timestamp_);
540 audio_sink_->OnData(data);
541 }
542 }
543
544 float output_gain = 1.0f;
545 float left_pan = 1.0f;
546 float right_pan = 1.0f;
547 {
548 rtc::CritScope cs(&volume_settings_critsect_);
549 output_gain = _outputGain;
550 left_pan = _panLeft;
551 right_pan = _panRight;
552 }
553
554 // Output volume scaling
555 if (output_gain < 0.99f || output_gain > 1.01f) {
556 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
557 }
558
559 // Scale left and/or right channel(s) if stereo and master balance is
560 // active
561
562 if (left_pan != 1.0f || right_pan != 1.0f) {
563 if (audioFrame->num_channels_ == 1) {
564 // Emulate stereo mode since panning is active.
565 // The mono signal is copied to both left and right channels here.
566 AudioFrameOperations::MonoToStereo(audioFrame);
567 }
568 // For true stereo mode (when we are receiving a stereo signal), no
569 // action is needed.
570
571 // Do the panning operation (the audio frame contains stereo at this
572 // stage)
573 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
574 }
575
576 // Mix decoded PCM output with file if file mixing is enabled
577 if (state.output_file_playing) {
578 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
henrik.lundina89ab962016-05-18 08:52:45 -0700579 muted = false; // We may have added non-zero samples.
kwiberg55b97fe2016-01-28 05:22:45 -0800580 }
581
582 // External media
583 if (_outputExternalMedia) {
584 rtc::CritScope cs(&_callbackCritSect);
585 const bool isStereo = (audioFrame->num_channels_ == 2);
586 if (_outputExternalMediaCallbackPtr) {
587 _outputExternalMediaCallbackPtr->Process(
588 _channelId, kPlaybackPerChannel, (int16_t*)audioFrame->data_,
589 audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
590 isStereo);
591 }
592 }
593
594 // Record playout if enabled
595 {
596 rtc::CritScope cs(&_fileCritSect);
597
598 if (_outputFileRecording && _outputFileRecorderPtr) {
599 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
600 }
601 }
602
603 // Measure audio level (0-9)
henrik.lundina89ab962016-05-18 08:52:45 -0700604 // TODO(henrik.lundin) Use the |muted| information here too.
kwiberg55b97fe2016-01-28 05:22:45 -0800605 _outputAudioLevel.ComputeLevel(*audioFrame);
606
607 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
608 // The first frame with a valid rtp timestamp.
609 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
610 }
611
612 if (capture_start_rtp_time_stamp_ >= 0) {
613 // audioFrame.timestamp_ should be valid from now on.
614
615 // Compute elapsed time.
616 int64_t unwrap_timestamp =
617 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
618 audioFrame->elapsed_time_ms_ =
619 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
620 (GetPlayoutFrequency() / 1000);
621
niklase@google.com470e71d2011-07-07 08:21:25 +0000622 {
kwiberg55b97fe2016-01-28 05:22:45 -0800623 rtc::CritScope lock(&ts_stats_lock_);
624 // Compute ntp time.
625 audioFrame->ntp_time_ms_ =
626 ntp_estimator_.Estimate(audioFrame->timestamp_);
627 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
628 if (audioFrame->ntp_time_ms_ > 0) {
629 // Compute |capture_start_ntp_time_ms_| so that
630 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
631 capture_start_ntp_time_ms_ =
632 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000633 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 }
kwiberg55b97fe2016-01-28 05:22:45 -0800635 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000636
henrik.lundin42dda502016-05-18 05:36:01 -0700637 return muted ? MixerParticipant::AudioFrameInfo::kMuted
638 : MixerParticipant::AudioFrameInfo::kNormal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000639}
640
kwiberg55b97fe2016-01-28 05:22:45 -0800641int32_t Channel::NeededFrequency(int32_t id) const {
642 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
643 "Channel::NeededFrequency(id=%d)", id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000644
kwiberg55b97fe2016-01-28 05:22:45 -0800645 int highestNeeded = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000646
kwiberg55b97fe2016-01-28 05:22:45 -0800647 // Determine highest needed receive frequency
648 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000649
kwiberg55b97fe2016-01-28 05:22:45 -0800650 // Return the bigger of playout and receive frequency in the ACM.
651 if (audio_coding_->PlayoutFrequency() > receiveFrequency) {
652 highestNeeded = audio_coding_->PlayoutFrequency();
653 } else {
654 highestNeeded = receiveFrequency;
655 }
656
657 // Special case, if we're playing a file on the playout side
658 // we take that frequency into consideration as well
659 // This is not needed on sending side, since the codec will
660 // limit the spectrum anyway.
661 if (channel_state_.Get().output_file_playing) {
662 rtc::CritScope cs(&_fileCritSect);
663 if (_outputFilePlayerPtr) {
664 if (_outputFilePlayerPtr->Frequency() > highestNeeded) {
665 highestNeeded = _outputFilePlayerPtr->Frequency();
666 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000667 }
kwiberg55b97fe2016-01-28 05:22:45 -0800668 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000669
kwiberg55b97fe2016-01-28 05:22:45 -0800670 return (highestNeeded);
niklase@google.com470e71d2011-07-07 08:21:25 +0000671}
672
ivocb04965c2015-09-09 00:09:43 -0700673int32_t Channel::CreateChannel(Channel*& channel,
674 int32_t channelId,
675 uint32_t instanceId,
676 RtcEventLog* const event_log,
677 const Config& config) {
ossu5f7cfa52016-05-30 08:11:28 -0700678 return CreateChannel(channel, channelId, instanceId, event_log, config,
679 CreateBuiltinAudioDecoderFactory());
680}
681
682int32_t Channel::CreateChannel(
683 Channel*& channel,
684 int32_t channelId,
685 uint32_t instanceId,
686 RtcEventLog* const event_log,
687 const Config& config,
688 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
kwiberg55b97fe2016-01-28 05:22:45 -0800689 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, channelId),
690 "Channel::CreateChannel(channelId=%d, instanceId=%d)", channelId,
691 instanceId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000692
ossu5f7cfa52016-05-30 08:11:28 -0700693 channel =
694 new Channel(channelId, instanceId, event_log, config, decoder_factory);
kwiberg55b97fe2016-01-28 05:22:45 -0800695 if (channel == NULL) {
696 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, channelId),
697 "Channel::CreateChannel() unable to allocate memory for"
698 " channel");
699 return -1;
700 }
701 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000702}
703
kwiberg55b97fe2016-01-28 05:22:45 -0800704void Channel::PlayNotification(int32_t id, uint32_t durationMs) {
705 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
706 "Channel::PlayNotification(id=%d, durationMs=%d)", id,
707 durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000708
kwiberg55b97fe2016-01-28 05:22:45 -0800709 // Not implement yet
niklase@google.com470e71d2011-07-07 08:21:25 +0000710}
711
kwiberg55b97fe2016-01-28 05:22:45 -0800712void Channel::RecordNotification(int32_t id, uint32_t durationMs) {
713 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
714 "Channel::RecordNotification(id=%d, durationMs=%d)", id,
715 durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000716
kwiberg55b97fe2016-01-28 05:22:45 -0800717 // Not implement yet
niklase@google.com470e71d2011-07-07 08:21:25 +0000718}
719
kwiberg55b97fe2016-01-28 05:22:45 -0800720void Channel::PlayFileEnded(int32_t id) {
721 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
722 "Channel::PlayFileEnded(id=%d)", id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000723
kwiberg55b97fe2016-01-28 05:22:45 -0800724 if (id == _inputFilePlayerId) {
725 channel_state_.SetInputFilePlaying(false);
726 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
727 "Channel::PlayFileEnded() => input file player module is"
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 " shutdown");
kwiberg55b97fe2016-01-28 05:22:45 -0800729 } else if (id == _outputFilePlayerId) {
730 channel_state_.SetOutputFilePlaying(false);
731 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
732 "Channel::PlayFileEnded() => output file player module is"
733 " shutdown");
734 }
735}
736
737void Channel::RecordFileEnded(int32_t id) {
738 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
739 "Channel::RecordFileEnded(id=%d)", id);
740
741 assert(id == _outputFileRecorderId);
742
743 rtc::CritScope cs(&_fileCritSect);
744
745 _outputFileRecording = false;
746 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
747 "Channel::RecordFileEnded() => output file recorder module is"
748 " shutdown");
niklase@google.com470e71d2011-07-07 08:21:25 +0000749}
750
pbos@webrtc.org92135212013-05-14 08:31:39 +0000751Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000752 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700753 RtcEventLog* const event_log,
ossu5f7cfa52016-05-30 08:11:28 -0700754 const Config& config,
755 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory)
tommi31fc21f2016-01-21 10:37:37 -0800756 : _instanceId(instanceId),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100757 _channelId(channelId),
758 event_log_(event_log),
759 rtp_header_parser_(RtpHeaderParser::Create()),
760 rtp_payload_registry_(
761 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
762 rtp_receive_statistics_(
763 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
764 rtp_receiver_(
765 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100766 this,
767 this,
768 rtp_payload_registry_.get())),
769 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
770 _outputAudioLevel(),
771 _externalTransport(false),
772 _inputFilePlayerPtr(NULL),
773 _outputFilePlayerPtr(NULL),
774 _outputFileRecorderPtr(NULL),
775 // Avoid conflict with other channels by adding 1024 - 1026,
776 // won't use as much as 1024 channels.
777 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
778 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
779 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
780 _outputFileRecording(false),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100781 _outputExternalMedia(false),
782 _inputExternalMediaCallbackPtr(NULL),
783 _outputExternalMediaCallbackPtr(NULL),
784 _timeStamp(0), // This is just an offset, RTP module will add it's own
785 // random offset
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100786 ntp_estimator_(Clock::GetRealTimeClock()),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100787 playout_timestamp_rtp_(0),
788 playout_timestamp_rtcp_(0),
789 playout_delay_ms_(0),
790 _numberOfDiscardedPackets(0),
791 send_sequence_number_(0),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100792 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
793 capture_start_rtp_time_stamp_(-1),
794 capture_start_ntp_time_ms_(-1),
795 _engineStatisticsPtr(NULL),
796 _outputMixerPtr(NULL),
797 _transmitMixerPtr(NULL),
798 _moduleProcessThreadPtr(NULL),
799 _audioDeviceModulePtr(NULL),
800 _voiceEngineObserverPtr(NULL),
801 _callbackCritSectPtr(NULL),
802 _transportPtr(NULL),
803 _rxVadObserverPtr(NULL),
804 _oldVadDecision(-1),
805 _sendFrameType(0),
806 _externalMixing(false),
807 _mixFileWithMicrophone(false),
solenberg1c2af8e2016-03-24 10:36:00 -0700808 input_mute_(false),
809 previous_frame_muted_(false),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100810 _panLeft(1.0f),
811 _panRight(1.0f),
812 _outputGain(1.0f),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100813 _lastLocalTimeStamp(0),
814 _lastPayloadType(0),
815 _includeAudioLevelIndication(false),
816 _outputSpeechType(AudioFrame::kNormalSpeech),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100817 _average_jitter_buffer_delay_us(0),
818 _previousTimestamp(0),
819 _recPacketDelayMs(20),
820 _RxVadDetection(false),
821 _rxAgcIsEnabled(false),
822 _rxNsIsEnabled(false),
823 restored_packet_in_use_(false),
824 rtcp_observer_(new VoERtcpObserver(this)),
825 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100826 associate_send_channel_(ChannelOwner(nullptr)),
827 pacing_enabled_(config.Get<VoicePacing>().enabled),
stefanbba9dec2016-02-01 04:39:55 -0800828 feedback_observer_proxy_(new TransportFeedbackProxy()),
829 seq_num_allocator_proxy_(new TransportSequenceNumberProxy()),
ossu29b1a8d2016-06-13 07:34:51 -0700830 rtp_packet_sender_proxy_(new RtpPacketSenderProxy()),
831 decoder_factory_(decoder_factory) {
kwiberg55b97fe2016-01-28 05:22:45 -0800832 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
833 "Channel::Channel() - ctor");
834 AudioCodingModule::Config acm_config;
835 acm_config.id = VoEModuleId(instanceId, channelId);
836 if (config.Get<NetEqCapacityConfig>().enabled) {
837 // Clamping the buffer capacity at 20 packets. While going lower will
838 // probably work, it makes little sense.
839 acm_config.neteq_config.max_packets_in_buffer =
840 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
841 }
842 acm_config.neteq_config.enable_fast_accelerate =
843 config.Get<NetEqFastAccelerate>().enabled;
henrik.lundina89ab962016-05-18 08:52:45 -0700844 acm_config.neteq_config.enable_muted_state = true;
ossu5f7cfa52016-05-30 08:11:28 -0700845 acm_config.decoder_factory = decoder_factory;
kwiberg55b97fe2016-01-28 05:22:45 -0800846 audio_coding_.reset(AudioCodingModule::Create(acm_config));
Henrik Lundin64dad832015-05-11 12:44:23 +0200847
kwiberg55b97fe2016-01-28 05:22:45 -0800848 _outputAudioLevel.Clear();
niklase@google.com470e71d2011-07-07 08:21:25 +0000849
kwiberg55b97fe2016-01-28 05:22:45 -0800850 RtpRtcp::Configuration configuration;
851 configuration.audio = true;
852 configuration.outgoing_transport = this;
kwiberg55b97fe2016-01-28 05:22:45 -0800853 configuration.receive_statistics = rtp_receive_statistics_.get();
854 configuration.bandwidth_callback = rtcp_observer_.get();
stefanbba9dec2016-02-01 04:39:55 -0800855 if (pacing_enabled_) {
856 configuration.paced_sender = rtp_packet_sender_proxy_.get();
857 configuration.transport_sequence_number_allocator =
858 seq_num_allocator_proxy_.get();
859 configuration.transport_feedback_callback = feedback_observer_proxy_.get();
860 }
kwiberg55b97fe2016-01-28 05:22:45 -0800861 configuration.event_log = event_log;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000862
kwiberg55b97fe2016-01-28 05:22:45 -0800863 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100864 _rtpRtcpModule->SetSendingMediaStatus(false);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000865
kwiberg55b97fe2016-01-28 05:22:45 -0800866 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
867 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
868 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000869
kwiberg55b97fe2016-01-28 05:22:45 -0800870 Config audioproc_config;
871 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
872 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000873}
874
kwiberg55b97fe2016-01-28 05:22:45 -0800875Channel::~Channel() {
876 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
877 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
878 "Channel::~Channel() - dtor");
niklase@google.com470e71d2011-07-07 08:21:25 +0000879
kwiberg55b97fe2016-01-28 05:22:45 -0800880 if (_outputExternalMedia) {
881 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
882 }
883 if (channel_state_.Get().input_external_media) {
884 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
885 }
886 StopSend();
887 StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000888
kwiberg55b97fe2016-01-28 05:22:45 -0800889 {
890 rtc::CritScope cs(&_fileCritSect);
891 if (_inputFilePlayerPtr) {
892 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
893 _inputFilePlayerPtr->StopPlayingFile();
894 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
895 _inputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 }
kwiberg55b97fe2016-01-28 05:22:45 -0800897 if (_outputFilePlayerPtr) {
898 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
899 _outputFilePlayerPtr->StopPlayingFile();
900 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
901 _outputFilePlayerPtr = NULL;
902 }
903 if (_outputFileRecorderPtr) {
904 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
905 _outputFileRecorderPtr->StopRecording();
906 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
907 _outputFileRecorderPtr = NULL;
908 }
909 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000910
kwiberg55b97fe2016-01-28 05:22:45 -0800911 // The order to safely shutdown modules in a channel is:
912 // 1. De-register callbacks in modules
913 // 2. De-register modules in process thread
914 // 3. Destroy modules
915 if (audio_coding_->RegisterTransportCallback(NULL) == -1) {
916 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
917 "~Channel() failed to de-register transport callback"
918 " (Audio coding module)");
919 }
920 if (audio_coding_->RegisterVADCallback(NULL) == -1) {
921 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
922 "~Channel() failed to de-register VAD callback"
923 " (Audio coding module)");
924 }
925 // De-register modules in process thread
926 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000927
kwiberg55b97fe2016-01-28 05:22:45 -0800928 // End of modules shutdown
niklase@google.com470e71d2011-07-07 08:21:25 +0000929}
930
kwiberg55b97fe2016-01-28 05:22:45 -0800931int32_t Channel::Init() {
932 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
933 "Channel::Init()");
niklase@google.com470e71d2011-07-07 08:21:25 +0000934
kwiberg55b97fe2016-01-28 05:22:45 -0800935 channel_state_.Reset();
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000936
kwiberg55b97fe2016-01-28 05:22:45 -0800937 // --- Initial sanity
niklase@google.com470e71d2011-07-07 08:21:25 +0000938
kwiberg55b97fe2016-01-28 05:22:45 -0800939 if ((_engineStatisticsPtr == NULL) || (_moduleProcessThreadPtr == NULL)) {
940 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
941 "Channel::Init() must call SetEngineInformation() first");
942 return -1;
943 }
944
945 // --- Add modules to process thread (for periodic schedulation)
946
947 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
948
949 // --- ACM initialization
950
951 if (audio_coding_->InitializeReceiver() == -1) {
952 _engineStatisticsPtr->SetLastError(
953 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
954 "Channel::Init() unable to initialize the ACM - 1");
955 return -1;
956 }
957
958 // --- RTP/RTCP module initialization
959
960 // Ensure that RTCP is enabled by default for the created channel.
961 // Note that, the module will keep generating RTCP until it is explicitly
962 // disabled by the user.
963 // After StopListen (when no sockets exists), RTCP packets will no longer
964 // be transmitted since the Transport object will then be invalid.
965 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
966 // RTCP is enabled by default.
967 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
968 // --- Register all permanent callbacks
969 const bool fail = (audio_coding_->RegisterTransportCallback(this) == -1) ||
970 (audio_coding_->RegisterVADCallback(this) == -1);
971
972 if (fail) {
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;
983 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
984
985 for (int idx = 0; idx < nSupportedCodecs; idx++) {
986 // Open up the RTP/RTCP receiver for all supported codecs
987 if ((audio_coding_->Codec(idx, &codec) == -1) ||
988 (rtp_receiver_->RegisterReceivePayload(
989 codec.plname, codec.pltype, codec.plfreq, codec.channels,
990 (codec.rate < 0) ? 0 : codec.rate) == -1)) {
991 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
992 "Channel::Init() unable to register %s "
993 "(%d/%d/%" PRIuS "/%d) to RTP/RTCP receiver",
994 codec.plname, codec.pltype, codec.plfreq, codec.channels,
995 codec.rate);
996 } else {
997 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
998 "Channel::Init() %s (%d/%d/%" PRIuS
999 "/%d) has been "
1000 "added to the RTP/RTCP receiver",
1001 codec.plname, codec.pltype, codec.plfreq, codec.channels,
1002 codec.rate);
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 }
1004
kwiberg55b97fe2016-01-28 05:22:45 -08001005 // Ensure that PCMU is used as default codec on the sending side
1006 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1)) {
1007 SetSendCodec(codec);
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 }
1009
kwiberg55b97fe2016-01-28 05:22:45 -08001010 // Register default PT for outband 'telephone-event'
1011 if (!STR_CASE_CMP(codec.plname, "telephone-event")) {
kwibergc8d071e2016-04-06 12:22:38 -07001012 if (_rtpRtcpModule->RegisterSendPayload(codec) == -1 ||
1013 !RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, codec)) {
kwiberg55b97fe2016-01-28 05:22:45 -08001014 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1015 "Channel::Init() failed to register outband "
1016 "'telephone-event' (%d/%d) correctly",
1017 codec.pltype, codec.plfreq);
1018 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 }
1020
kwiberg55b97fe2016-01-28 05:22:45 -08001021 if (!STR_CASE_CMP(codec.plname, "CN")) {
kwibergc8d071e2016-04-06 12:22:38 -07001022 if (!codec_manager_.RegisterEncoder(codec) ||
1023 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get()) ||
1024 !RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, codec) ||
1025 _rtpRtcpModule->RegisterSendPayload(codec) == -1) {
kwiberg55b97fe2016-01-28 05:22:45 -08001026 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1027 "Channel::Init() failed to register CN (%d/%d) "
1028 "correctly - 1",
1029 codec.pltype, codec.plfreq);
1030 }
1031 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001032#ifdef WEBRTC_CODEC_RED
kwiberg55b97fe2016-01-28 05:22:45 -08001033 // Register RED to the receiving side of the ACM.
1034 // We will not receive an OnInitializeDecoder() callback for RED.
1035 if (!STR_CASE_CMP(codec.plname, "RED")) {
kwibergc8d071e2016-04-06 12:22:38 -07001036 if (!RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, codec)) {
kwiberg55b97fe2016-01-28 05:22:45 -08001037 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1038 "Channel::Init() failed to register RED (%d/%d) "
1039 "correctly",
1040 codec.pltype, codec.plfreq);
1041 }
1042 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001043#endif
kwiberg55b97fe2016-01-28 05:22:45 -08001044 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001045
kwiberg55b97fe2016-01-28 05:22:45 -08001046 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1047 LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
1048 return -1;
1049 }
1050 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1051 LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
1052 return -1;
1053 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
kwiberg55b97fe2016-01-28 05:22:45 -08001055 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001056}
1057
kwiberg55b97fe2016-01-28 05:22:45 -08001058int32_t Channel::SetEngineInformation(Statistics& engineStatistics,
1059 OutputMixer& outputMixer,
1060 voe::TransmitMixer& transmitMixer,
1061 ProcessThread& moduleProcessThread,
1062 AudioDeviceModule& audioDeviceModule,
1063 VoiceEngineObserver* voiceEngineObserver,
1064 rtc::CriticalSection* callbackCritSect) {
1065 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1066 "Channel::SetEngineInformation()");
1067 _engineStatisticsPtr = &engineStatistics;
1068 _outputMixerPtr = &outputMixer;
1069 _transmitMixerPtr = &transmitMixer,
1070 _moduleProcessThreadPtr = &moduleProcessThread;
1071 _audioDeviceModulePtr = &audioDeviceModule;
1072 _voiceEngineObserverPtr = voiceEngineObserver;
1073 _callbackCritSectPtr = callbackCritSect;
1074 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001075}
1076
kwiberg55b97fe2016-01-28 05:22:45 -08001077int32_t Channel::UpdateLocalTimeStamp() {
1078 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
1079 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001080}
1081
kwibergb7f89d62016-02-17 10:04:18 -08001082void Channel::SetSink(std::unique_ptr<AudioSinkInterface> sink) {
tommi31fc21f2016-01-21 10:37:37 -08001083 rtc::CritScope cs(&_callbackCritSect);
deadbeef2d110be2016-01-13 12:00:26 -08001084 audio_sink_ = std::move(sink);
Tommif888bb52015-12-12 01:37:01 +01001085}
1086
ossu29b1a8d2016-06-13 07:34:51 -07001087const rtc::scoped_refptr<AudioDecoderFactory>&
1088Channel::GetAudioDecoderFactory() const {
1089 return decoder_factory_;
1090}
1091
kwiberg55b97fe2016-01-28 05:22:45 -08001092int32_t Channel::StartPlayout() {
1093 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1094 "Channel::StartPlayout()");
1095 if (channel_state_.Get().playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001096 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001097 }
1098
1099 if (!_externalMixing) {
1100 // Add participant as candidates for mixing.
1101 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0) {
1102 _engineStatisticsPtr->SetLastError(
1103 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1104 "StartPlayout() failed to add participant to mixer");
1105 return -1;
1106 }
1107 }
1108
1109 channel_state_.SetPlaying(true);
1110 if (RegisterFilePlayingToMixer() != 0)
1111 return -1;
1112
1113 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001114}
1115
kwiberg55b97fe2016-01-28 05:22:45 -08001116int32_t Channel::StopPlayout() {
1117 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1118 "Channel::StopPlayout()");
1119 if (!channel_state_.Get().playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001121 }
1122
1123 if (!_externalMixing) {
1124 // Remove participant as candidates for mixing
1125 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0) {
1126 _engineStatisticsPtr->SetLastError(
1127 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1128 "StopPlayout() failed to remove participant from mixer");
1129 return -1;
1130 }
1131 }
1132
1133 channel_state_.SetPlaying(false);
1134 _outputAudioLevel.Clear();
1135
1136 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001137}
1138
kwiberg55b97fe2016-01-28 05:22:45 -08001139int32_t Channel::StartSend() {
1140 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1141 "Channel::StartSend()");
1142 // Resume the previous sequence number which was reset by StopSend().
1143 // This needs to be done before |sending| is set to true.
1144 if (send_sequence_number_)
1145 SetInitSequenceNumber(send_sequence_number_);
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001146
kwiberg55b97fe2016-01-28 05:22:45 -08001147 if (channel_state_.Get().sending) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001149 }
1150 channel_state_.SetSending(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001151
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001152 _rtpRtcpModule->SetSendingMediaStatus(true);
kwiberg55b97fe2016-01-28 05:22:45 -08001153 if (_rtpRtcpModule->SetSendingStatus(true) != 0) {
1154 _engineStatisticsPtr->SetLastError(
1155 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1156 "StartSend() RTP/RTCP failed to start sending");
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001157 _rtpRtcpModule->SetSendingMediaStatus(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001158 rtc::CritScope cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001159 channel_state_.SetSending(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001160 return -1;
1161 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001162
kwiberg55b97fe2016-01-28 05:22:45 -08001163 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001164}
1165
kwiberg55b97fe2016-01-28 05:22:45 -08001166int32_t Channel::StopSend() {
1167 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1168 "Channel::StopSend()");
1169 if (!channel_state_.Get().sending) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001171 }
1172 channel_state_.SetSending(false);
1173
1174 // Store the sequence number to be able to pick up the same sequence for
1175 // the next StartSend(). This is needed for restarting device, otherwise
1176 // it might cause libSRTP to complain about packets being replayed.
1177 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1178 // CL is landed. See issue
1179 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1180 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1181
1182 // Reset sending SSRC and sequence number and triggers direct transmission
1183 // of RTCP BYE
1184 if (_rtpRtcpModule->SetSendingStatus(false) == -1) {
1185 _engineStatisticsPtr->SetLastError(
1186 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1187 "StartSend() RTP/RTCP failed to stop sending");
1188 }
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001189 _rtpRtcpModule->SetSendingMediaStatus(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001190
1191 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001192}
1193
kwiberg55b97fe2016-01-28 05:22:45 -08001194int32_t Channel::StartReceiving() {
1195 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1196 "Channel::StartReceiving()");
1197 if (channel_state_.Get().receiving) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001199 }
1200 channel_state_.SetReceiving(true);
1201 _numberOfDiscardedPackets = 0;
1202 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001203}
1204
kwiberg55b97fe2016-01-28 05:22:45 -08001205int32_t Channel::StopReceiving() {
1206 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1207 "Channel::StopReceiving()");
1208 if (!channel_state_.Get().receiving) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001210 }
1211
1212 channel_state_.SetReceiving(false);
1213 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001214}
1215
kwiberg55b97fe2016-01-28 05:22:45 -08001216int32_t Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
1217 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1218 "Channel::RegisterVoiceEngineObserver()");
1219 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001220
kwiberg55b97fe2016-01-28 05:22:45 -08001221 if (_voiceEngineObserverPtr) {
1222 _engineStatisticsPtr->SetLastError(
1223 VE_INVALID_OPERATION, kTraceError,
1224 "RegisterVoiceEngineObserver() observer already enabled");
1225 return -1;
1226 }
1227 _voiceEngineObserverPtr = &observer;
1228 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001229}
1230
kwiberg55b97fe2016-01-28 05:22:45 -08001231int32_t Channel::DeRegisterVoiceEngineObserver() {
1232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1233 "Channel::DeRegisterVoiceEngineObserver()");
1234 rtc::CritScope cs(&_callbackCritSect);
1235
1236 if (!_voiceEngineObserverPtr) {
1237 _engineStatisticsPtr->SetLastError(
1238 VE_INVALID_OPERATION, kTraceWarning,
1239 "DeRegisterVoiceEngineObserver() observer already disabled");
1240 return 0;
1241 }
1242 _voiceEngineObserverPtr = NULL;
1243 return 0;
1244}
1245
1246int32_t Channel::GetSendCodec(CodecInst& codec) {
kwibergc8d071e2016-04-06 12:22:38 -07001247 auto send_codec = codec_manager_.GetCodecInst();
kwiberg1fd4a4a2015-11-03 11:20:50 -08001248 if (send_codec) {
1249 codec = *send_codec;
1250 return 0;
1251 }
1252 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001253}
1254
kwiberg55b97fe2016-01-28 05:22:45 -08001255int32_t Channel::GetRecCodec(CodecInst& codec) {
1256 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001257}
1258
kwiberg55b97fe2016-01-28 05:22:45 -08001259int32_t Channel::SetSendCodec(const CodecInst& codec) {
1260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1261 "Channel::SetSendCodec()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001262
kwibergc8d071e2016-04-06 12:22:38 -07001263 if (!codec_manager_.RegisterEncoder(codec) ||
1264 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
kwiberg55b97fe2016-01-28 05:22:45 -08001265 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1266 "SetSendCodec() failed to register codec to ACM");
1267 return -1;
1268 }
1269
1270 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1271 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1272 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1273 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1274 "SetSendCodec() failed to register codec to"
1275 " RTP/RTCP module");
1276 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 }
kwiberg55b97fe2016-01-28 05:22:45 -08001278 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001279
kwiberg55b97fe2016-01-28 05:22:45 -08001280 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0) {
1281 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1282 "SetSendCodec() failed to set audio packet size");
1283 return -1;
1284 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001285
kwiberg55b97fe2016-01-28 05:22:45 -08001286 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001287}
1288
Ivo Creusenadf89b72015-04-29 16:03:33 +02001289void Channel::SetBitRate(int bitrate_bps) {
1290 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1291 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1292 audio_coding_->SetBitRate(bitrate_bps);
1293}
1294
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001295void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001296 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001297 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1298
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001299 // Normalizes rate to 0 - 100.
kwiberg55b97fe2016-01-28 05:22:45 -08001300 if (audio_coding_->SetPacketLossRate(100 * average_fraction_loss / 255) !=
1301 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001302 assert(false); // This should not happen.
1303 }
1304}
1305
kwiberg55b97fe2016-01-28 05:22:45 -08001306int32_t Channel::SetVADStatus(bool enableVAD,
1307 ACMVADMode mode,
1308 bool disableDTX) {
1309 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1310 "Channel::SetVADStatus(mode=%d)", mode);
kwibergc8d071e2016-04-06 12:22:38 -07001311 RTC_DCHECK(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
1312 if (!codec_manager_.SetVAD(enableVAD, mode) ||
1313 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
kwiberg55b97fe2016-01-28 05:22:45 -08001314 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1315 kTraceError,
1316 "SetVADStatus() failed to set VAD");
1317 return -1;
1318 }
1319 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001320}
1321
kwiberg55b97fe2016-01-28 05:22:45 -08001322int32_t Channel::GetVADStatus(bool& enabledVAD,
1323 ACMVADMode& mode,
1324 bool& disabledDTX) {
kwibergc8d071e2016-04-06 12:22:38 -07001325 const auto* params = codec_manager_.GetStackParams();
1326 enabledVAD = params->use_cng;
1327 mode = params->vad_mode;
1328 disabledDTX = !params->use_cng;
kwiberg55b97fe2016-01-28 05:22:45 -08001329 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001330}
1331
kwiberg55b97fe2016-01-28 05:22:45 -08001332int32_t Channel::SetRecPayloadType(const CodecInst& codec) {
1333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1334 "Channel::SetRecPayloadType()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001335
kwiberg55b97fe2016-01-28 05:22:45 -08001336 if (channel_state_.Get().playing) {
1337 _engineStatisticsPtr->SetLastError(
1338 VE_ALREADY_PLAYING, kTraceError,
1339 "SetRecPayloadType() unable to set PT while playing");
1340 return -1;
1341 }
1342 if (channel_state_.Get().receiving) {
1343 _engineStatisticsPtr->SetLastError(
1344 VE_ALREADY_LISTENING, kTraceError,
1345 "SetRecPayloadType() unable to set PT while listening");
1346 return -1;
1347 }
1348
1349 if (codec.pltype == -1) {
1350 // De-register the selected codec (RTP/RTCP module and ACM)
1351
1352 int8_t pltype(-1);
1353 CodecInst rxCodec = codec;
1354
1355 // Get payload type for the given codec
1356 rtp_payload_registry_->ReceivePayloadType(
1357 rxCodec.plname, rxCodec.plfreq, rxCodec.channels,
1358 (rxCodec.rate < 0) ? 0 : rxCodec.rate, &pltype);
1359 rxCodec.pltype = pltype;
1360
1361 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0) {
1362 _engineStatisticsPtr->SetLastError(
1363 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1364 "SetRecPayloadType() RTP/RTCP-module deregistration "
1365 "failed");
1366 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 }
kwiberg55b97fe2016-01-28 05:22:45 -08001368 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0) {
1369 _engineStatisticsPtr->SetLastError(
1370 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1371 "SetRecPayloadType() ACM deregistration failed - 1");
1372 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 }
kwiberg55b97fe2016-01-28 05:22:45 -08001374 return 0;
1375 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001376
kwiberg55b97fe2016-01-28 05:22:45 -08001377 if (rtp_receiver_->RegisterReceivePayload(
1378 codec.plname, codec.pltype, codec.plfreq, codec.channels,
1379 (codec.rate < 0) ? 0 : codec.rate) != 0) {
1380 // First attempt to register failed => de-register and try again
kwibergc8d071e2016-04-06 12:22:38 -07001381 // TODO(kwiberg): Retrying is probably not necessary, since
1382 // AcmReceiver::AddCodec also retries.
kwiberg55b97fe2016-01-28 05:22:45 -08001383 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001384 if (rtp_receiver_->RegisterReceivePayload(
kwiberg55b97fe2016-01-28 05:22:45 -08001385 codec.plname, codec.pltype, codec.plfreq, codec.channels,
1386 (codec.rate < 0) ? 0 : codec.rate) != 0) {
1387 _engineStatisticsPtr->SetLastError(
1388 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1389 "SetRecPayloadType() RTP/RTCP-module registration failed");
1390 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 }
kwiberg55b97fe2016-01-28 05:22:45 -08001392 }
kwibergc8d071e2016-04-06 12:22:38 -07001393 if (!RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, codec)) {
kwiberg55b97fe2016-01-28 05:22:45 -08001394 audio_coding_->UnregisterReceiveCodec(codec.pltype);
kwibergc8d071e2016-04-06 12:22:38 -07001395 if (!RegisterReceiveCodec(&audio_coding_, &rent_a_codec_, codec)) {
kwiberg55b97fe2016-01-28 05:22:45 -08001396 _engineStatisticsPtr->SetLastError(
1397 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1398 "SetRecPayloadType() ACM registration failed - 1");
1399 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001400 }
kwiberg55b97fe2016-01-28 05:22:45 -08001401 }
1402 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001403}
1404
kwiberg55b97fe2016-01-28 05:22:45 -08001405int32_t Channel::GetRecPayloadType(CodecInst& codec) {
1406 int8_t payloadType(-1);
1407 if (rtp_payload_registry_->ReceivePayloadType(
1408 codec.plname, codec.plfreq, codec.channels,
1409 (codec.rate < 0) ? 0 : codec.rate, &payloadType) != 0) {
1410 _engineStatisticsPtr->SetLastError(
1411 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1412 "GetRecPayloadType() failed to retrieve RX payload type");
1413 return -1;
1414 }
1415 codec.pltype = payloadType;
1416 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001417}
1418
kwiberg55b97fe2016-01-28 05:22:45 -08001419int32_t Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency) {
1420 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1421 "Channel::SetSendCNPayloadType()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001422
kwiberg55b97fe2016-01-28 05:22:45 -08001423 CodecInst codec;
1424 int32_t samplingFreqHz(-1);
1425 const size_t kMono = 1;
1426 if (frequency == kFreq32000Hz)
1427 samplingFreqHz = 32000;
1428 else if (frequency == kFreq16000Hz)
1429 samplingFreqHz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001430
kwiberg55b97fe2016-01-28 05:22:45 -08001431 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1) {
1432 _engineStatisticsPtr->SetLastError(
1433 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1434 "SetSendCNPayloadType() failed to retrieve default CN codec "
1435 "settings");
1436 return -1;
1437 }
1438
1439 // Modify the payload type (must be set to dynamic range)
1440 codec.pltype = type;
1441
kwibergc8d071e2016-04-06 12:22:38 -07001442 if (!codec_manager_.RegisterEncoder(codec) ||
1443 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
kwiberg55b97fe2016-01-28 05:22:45 -08001444 _engineStatisticsPtr->SetLastError(
1445 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1446 "SetSendCNPayloadType() failed to register CN to ACM");
1447 return -1;
1448 }
1449
1450 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1451 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1452 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1453 _engineStatisticsPtr->SetLastError(
1454 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1455 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1456 "module");
1457 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001458 }
kwiberg55b97fe2016-01-28 05:22:45 -08001459 }
1460 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001461}
1462
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001463int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001464 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001465 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001466
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001467 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001468 _engineStatisticsPtr->SetLastError(
1469 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001470 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001471 return -1;
1472 }
1473 return 0;
1474}
1475
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001476int Channel::SetOpusDtx(bool enable_dtx) {
1477 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1478 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001479 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001480 : audio_coding_->DisableOpusDtx();
1481 if (ret != 0) {
kwiberg55b97fe2016-01-28 05:22:45 -08001482 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1483 kTraceError, "SetOpusDtx() failed");
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001484 return -1;
1485 }
1486 return 0;
1487}
1488
mflodman3d7db262016-04-29 00:57:13 -07001489int32_t Channel::RegisterExternalTransport(Transport* transport) {
kwiberg55b97fe2016-01-28 05:22:45 -08001490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00001491 "Channel::RegisterExternalTransport()");
1492
kwiberg55b97fe2016-01-28 05:22:45 -08001493 rtc::CritScope cs(&_callbackCritSect);
kwiberg55b97fe2016-01-28 05:22:45 -08001494 if (_externalTransport) {
1495 _engineStatisticsPtr->SetLastError(
1496 VE_INVALID_OPERATION, kTraceError,
1497 "RegisterExternalTransport() external transport already enabled");
1498 return -1;
1499 }
1500 _externalTransport = true;
mflodman3d7db262016-04-29 00:57:13 -07001501 _transportPtr = transport;
kwiberg55b97fe2016-01-28 05:22:45 -08001502 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001503}
1504
kwiberg55b97fe2016-01-28 05:22:45 -08001505int32_t Channel::DeRegisterExternalTransport() {
1506 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1507 "Channel::DeRegisterExternalTransport()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001508
kwiberg55b97fe2016-01-28 05:22:45 -08001509 rtc::CritScope cs(&_callbackCritSect);
mflodman3d7db262016-04-29 00:57:13 -07001510 if (_transportPtr) {
1511 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1512 "DeRegisterExternalTransport() all transport is disabled");
1513 } else {
kwiberg55b97fe2016-01-28 05:22:45 -08001514 _engineStatisticsPtr->SetLastError(
1515 VE_INVALID_OPERATION, kTraceWarning,
1516 "DeRegisterExternalTransport() external transport already "
1517 "disabled");
kwiberg55b97fe2016-01-28 05:22:45 -08001518 }
1519 _externalTransport = false;
1520 _transportPtr = NULL;
kwiberg55b97fe2016-01-28 05:22:45 -08001521 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001522}
1523
mflodman3d7db262016-04-29 00:57:13 -07001524int32_t Channel::ReceivedRTPPacket(const uint8_t* received_packet,
kwiberg55b97fe2016-01-28 05:22:45 -08001525 size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001526 const PacketTime& packet_time) {
kwiberg55b97fe2016-01-28 05:22:45 -08001527 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001528 "Channel::ReceivedRTPPacket()");
1529
1530 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001531 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001532
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001533 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001534 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1535 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1536 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001537 return -1;
1538 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001539 header.payload_type_frequency =
1540 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001541 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001542 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001543 bool in_order = IsPacketInOrder(header);
kwiberg55b97fe2016-01-28 05:22:45 -08001544 rtp_receive_statistics_->IncomingPacket(
1545 header, length, IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001546 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001547
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001548 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001549}
1550
1551bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001552 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001553 const RTPHeader& header,
1554 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001555 if (rtp_payload_registry_->IsRtx(header)) {
1556 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001557 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001558 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001559 assert(packet_length >= header.headerLength);
1560 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001561 PayloadUnion payload_specific;
1562 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001563 &payload_specific)) {
1564 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001565 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001566 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1567 payload_specific, in_order);
1568}
1569
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001570bool Channel::HandleRtxPacket(const uint8_t* packet,
1571 size_t packet_length,
1572 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001573 if (!rtp_payload_registry_->IsRtx(header))
1574 return false;
1575
1576 // Remove the RTX header and parse the original RTP header.
1577 if (packet_length < header.headerLength)
1578 return false;
1579 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1580 return false;
1581 if (restored_packet_in_use_) {
1582 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1583 "Multiple RTX headers detected, dropping packet");
1584 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001585 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001586 if (!rtp_payload_registry_->RestoreOriginalPacket(
noahric65220a72015-10-14 11:29:49 -07001587 restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
1588 header)) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001589 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1590 "Incoming RTX packet: invalid RTP header");
1591 return false;
1592 }
1593 restored_packet_in_use_ = true;
noahric65220a72015-10-14 11:29:49 -07001594 bool ret = OnRecoveredPacket(restored_packet_, packet_length);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001595 restored_packet_in_use_ = false;
1596 return ret;
1597}
1598
1599bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1600 StreamStatistician* statistician =
1601 rtp_receive_statistics_->GetStatistician(header.ssrc);
1602 if (!statistician)
1603 return false;
1604 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001605}
1606
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001607bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1608 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001609 // Retransmissions are handled separately if RTX is enabled.
1610 if (rtp_payload_registry_->RtxEnabled())
1611 return false;
1612 StreamStatistician* statistician =
1613 rtp_receive_statistics_->GetStatistician(header.ssrc);
1614 if (!statistician)
1615 return false;
1616 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001617 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001618 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
kwiberg55b97fe2016-01-28 05:22:45 -08001619 return !in_order && statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001620}
1621
mflodman3d7db262016-04-29 00:57:13 -07001622int32_t Channel::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
kwiberg55b97fe2016-01-28 05:22:45 -08001623 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001624 "Channel::ReceivedRTCPPacket()");
1625 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001626 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001627
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001628 // Deliver RTCP packet to RTP/RTCP module for parsing
mflodman3d7db262016-04-29 00:57:13 -07001629 if (_rtpRtcpModule->IncomingRtcpPacket(data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001630 _engineStatisticsPtr->SetLastError(
1631 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1632 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1633 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001634
Minyue2013aec2015-05-13 14:14:42 +02001635 int64_t rtt = GetRTT(true);
1636 if (rtt == 0) {
1637 // Waiting for valid RTT.
1638 return 0;
1639 }
1640 uint32_t ntp_secs = 0;
1641 uint32_t ntp_frac = 0;
1642 uint32_t rtp_timestamp = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001643 if (0 !=
1644 _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1645 &rtp_timestamp)) {
Minyue2013aec2015-05-13 14:14:42 +02001646 // Waiting for RTCP.
1647 return 0;
1648 }
1649
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001650 {
tommi31fc21f2016-01-21 10:37:37 -08001651 rtc::CritScope lock(&ts_stats_lock_);
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001652 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001653 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001654 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001655}
1656
niklase@google.com470e71d2011-07-07 08:21:25 +00001657int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001658 bool loop,
1659 FileFormats format,
1660 int startPosition,
1661 float volumeScaling,
1662 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001663 const CodecInst* codecInst) {
1664 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1665 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1666 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1667 "stopPosition=%d)",
1668 fileName, loop, format, volumeScaling, startPosition,
1669 stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001670
kwiberg55b97fe2016-01-28 05:22:45 -08001671 if (channel_state_.Get().output_file_playing) {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_ALREADY_PLAYING, kTraceError,
1674 "StartPlayingFileLocally() is already playing");
1675 return -1;
1676 }
1677
1678 {
1679 rtc::CritScope cs(&_fileCritSect);
1680
1681 if (_outputFilePlayerPtr) {
1682 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1683 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1684 _outputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +00001685 }
1686
kwiberg55b97fe2016-01-28 05:22:45 -08001687 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1688 _outputFilePlayerId, (const FileFormats)format);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001689
kwiberg55b97fe2016-01-28 05:22:45 -08001690 if (_outputFilePlayerPtr == NULL) {
1691 _engineStatisticsPtr->SetLastError(
1692 VE_INVALID_ARGUMENT, kTraceError,
1693 "StartPlayingFileLocally() filePlayer format is not correct");
1694 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001695 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001696
kwiberg55b97fe2016-01-28 05:22:45 -08001697 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001698
kwiberg55b97fe2016-01-28 05:22:45 -08001699 if (_outputFilePlayerPtr->StartPlayingFile(
1700 fileName, loop, startPosition, volumeScaling, notificationTime,
1701 stopPosition, (const CodecInst*)codecInst) != 0) {
1702 _engineStatisticsPtr->SetLastError(
1703 VE_BAD_FILE, kTraceError,
1704 "StartPlayingFile() failed to start file playout");
1705 _outputFilePlayerPtr->StopPlayingFile();
1706 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1707 _outputFilePlayerPtr = NULL;
1708 return -1;
1709 }
1710 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1711 channel_state_.SetOutputFilePlaying(true);
1712 }
1713
1714 if (RegisterFilePlayingToMixer() != 0)
1715 return -1;
1716
1717 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001718}
1719
1720int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001721 FileFormats format,
1722 int startPosition,
1723 float volumeScaling,
1724 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001725 const CodecInst* codecInst) {
1726 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1727 "Channel::StartPlayingFileLocally(format=%d,"
1728 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1729 format, volumeScaling, startPosition, stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001730
kwiberg55b97fe2016-01-28 05:22:45 -08001731 if (stream == NULL) {
1732 _engineStatisticsPtr->SetLastError(
1733 VE_BAD_FILE, kTraceError,
1734 "StartPlayingFileLocally() NULL as input stream");
1735 return -1;
1736 }
1737
1738 if (channel_state_.Get().output_file_playing) {
1739 _engineStatisticsPtr->SetLastError(
1740 VE_ALREADY_PLAYING, kTraceError,
1741 "StartPlayingFileLocally() is already playing");
1742 return -1;
1743 }
1744
1745 {
1746 rtc::CritScope cs(&_fileCritSect);
1747
1748 // Destroy the old instance
1749 if (_outputFilePlayerPtr) {
1750 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1751 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1752 _outputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +00001753 }
1754
kwiberg55b97fe2016-01-28 05:22:45 -08001755 // Create the instance
1756 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1757 _outputFilePlayerId, (const FileFormats)format);
niklase@google.com470e71d2011-07-07 08:21:25 +00001758
kwiberg55b97fe2016-01-28 05:22:45 -08001759 if (_outputFilePlayerPtr == NULL) {
1760 _engineStatisticsPtr->SetLastError(
1761 VE_INVALID_ARGUMENT, kTraceError,
1762 "StartPlayingFileLocally() filePlayer format isnot correct");
1763 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001764 }
1765
kwiberg55b97fe2016-01-28 05:22:45 -08001766 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001767
kwiberg55b97fe2016-01-28 05:22:45 -08001768 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1769 volumeScaling, notificationTime,
1770 stopPosition, codecInst) != 0) {
1771 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1772 "StartPlayingFile() failed to "
1773 "start file playout");
1774 _outputFilePlayerPtr->StopPlayingFile();
1775 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1776 _outputFilePlayerPtr = NULL;
1777 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001778 }
kwiberg55b97fe2016-01-28 05:22:45 -08001779 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1780 channel_state_.SetOutputFilePlaying(true);
1781 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001782
kwiberg55b97fe2016-01-28 05:22:45 -08001783 if (RegisterFilePlayingToMixer() != 0)
1784 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001785
kwiberg55b97fe2016-01-28 05:22:45 -08001786 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001787}
1788
kwiberg55b97fe2016-01-28 05:22:45 -08001789int Channel::StopPlayingFileLocally() {
1790 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1791 "Channel::StopPlayingFileLocally()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001792
kwiberg55b97fe2016-01-28 05:22:45 -08001793 if (!channel_state_.Get().output_file_playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001794 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001795 }
1796
1797 {
1798 rtc::CritScope cs(&_fileCritSect);
1799
1800 if (_outputFilePlayerPtr->StopPlayingFile() != 0) {
1801 _engineStatisticsPtr->SetLastError(
1802 VE_STOP_RECORDING_FAILED, kTraceError,
1803 "StopPlayingFile() could not stop playing");
1804 return -1;
1805 }
1806 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1807 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1808 _outputFilePlayerPtr = NULL;
1809 channel_state_.SetOutputFilePlaying(false);
1810 }
1811 // _fileCritSect cannot be taken while calling
1812 // SetAnonymousMixibilityStatus. Refer to comments in
1813 // StartPlayingFileLocally(const char* ...) for more details.
1814 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0) {
1815 _engineStatisticsPtr->SetLastError(
1816 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1817 "StopPlayingFile() failed to stop participant from playing as"
1818 "file in the mixer");
1819 return -1;
1820 }
1821
1822 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001823}
1824
kwiberg55b97fe2016-01-28 05:22:45 -08001825int Channel::IsPlayingFileLocally() const {
1826 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001827}
1828
kwiberg55b97fe2016-01-28 05:22:45 -08001829int Channel::RegisterFilePlayingToMixer() {
1830 // Return success for not registering for file playing to mixer if:
1831 // 1. playing file before playout is started on that channel.
1832 // 2. starting playout without file playing on that channel.
1833 if (!channel_state_.Get().playing ||
1834 !channel_state_.Get().output_file_playing) {
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001835 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001836 }
1837
1838 // |_fileCritSect| cannot be taken while calling
1839 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1840 // frames can be pulled by the mixer. Since the frames are generated from
1841 // the file, _fileCritSect will be taken. This would result in a deadlock.
1842 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0) {
1843 channel_state_.SetOutputFilePlaying(false);
1844 rtc::CritScope cs(&_fileCritSect);
1845 _engineStatisticsPtr->SetLastError(
1846 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1847 "StartPlayingFile() failed to add participant as file to mixer");
1848 _outputFilePlayerPtr->StopPlayingFile();
1849 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1850 _outputFilePlayerPtr = NULL;
1851 return -1;
1852 }
1853
1854 return 0;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001855}
1856
niklase@google.com470e71d2011-07-07 08:21:25 +00001857int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001858 bool loop,
1859 FileFormats format,
1860 int startPosition,
1861 float volumeScaling,
1862 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001863 const CodecInst* codecInst) {
1864 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1865 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1866 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1867 "stopPosition=%d)",
1868 fileName, loop, format, volumeScaling, startPosition,
1869 stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001870
kwiberg55b97fe2016-01-28 05:22:45 -08001871 rtc::CritScope cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001872
kwiberg55b97fe2016-01-28 05:22:45 -08001873 if (channel_state_.Get().input_file_playing) {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_ALREADY_PLAYING, kTraceWarning,
1876 "StartPlayingFileAsMicrophone() filePlayer is playing");
niklase@google.com470e71d2011-07-07 08:21:25 +00001877 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001878 }
1879
1880 // Destroy the old instance
1881 if (_inputFilePlayerPtr) {
1882 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1883 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1884 _inputFilePlayerPtr = NULL;
1885 }
1886
1887 // Create the instance
1888 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
1889 (const FileFormats)format);
1890
1891 if (_inputFilePlayerPtr == NULL) {
1892 _engineStatisticsPtr->SetLastError(
1893 VE_INVALID_ARGUMENT, kTraceError,
1894 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
1895 return -1;
1896 }
1897
1898 const uint32_t notificationTime(0);
1899
1900 if (_inputFilePlayerPtr->StartPlayingFile(
1901 fileName, loop, startPosition, volumeScaling, notificationTime,
1902 stopPosition, (const CodecInst*)codecInst) != 0) {
1903 _engineStatisticsPtr->SetLastError(
1904 VE_BAD_FILE, kTraceError,
1905 "StartPlayingFile() failed to start file playout");
1906 _inputFilePlayerPtr->StopPlayingFile();
1907 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1908 _inputFilePlayerPtr = NULL;
1909 return -1;
1910 }
1911 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
1912 channel_state_.SetInputFilePlaying(true);
1913
1914 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001915}
1916
1917int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001918 FileFormats format,
1919 int startPosition,
1920 float volumeScaling,
1921 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001922 const CodecInst* codecInst) {
1923 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1924 "Channel::StartPlayingFileAsMicrophone(format=%d, "
1925 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1926 format, volumeScaling, startPosition, stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001927
kwiberg55b97fe2016-01-28 05:22:45 -08001928 if (stream == NULL) {
1929 _engineStatisticsPtr->SetLastError(
1930 VE_BAD_FILE, kTraceError,
1931 "StartPlayingFileAsMicrophone NULL as input stream");
1932 return -1;
1933 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001934
kwiberg55b97fe2016-01-28 05:22:45 -08001935 rtc::CritScope cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001936
kwiberg55b97fe2016-01-28 05:22:45 -08001937 if (channel_state_.Get().input_file_playing) {
1938 _engineStatisticsPtr->SetLastError(
1939 VE_ALREADY_PLAYING, kTraceWarning,
1940 "StartPlayingFileAsMicrophone() is playing");
niklase@google.com470e71d2011-07-07 08:21:25 +00001941 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001942 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001943
kwiberg55b97fe2016-01-28 05:22:45 -08001944 // Destroy the old instance
1945 if (_inputFilePlayerPtr) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001946 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1947 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1948 _inputFilePlayerPtr = NULL;
kwiberg55b97fe2016-01-28 05:22:45 -08001949 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001950
kwiberg55b97fe2016-01-28 05:22:45 -08001951 // Create the instance
1952 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
1953 (const FileFormats)format);
1954
1955 if (_inputFilePlayerPtr == NULL) {
1956 _engineStatisticsPtr->SetLastError(
1957 VE_INVALID_ARGUMENT, kTraceError,
1958 "StartPlayingInputFile() filePlayer format isnot correct");
1959 return -1;
1960 }
1961
1962 const uint32_t notificationTime(0);
1963
1964 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1965 volumeScaling, notificationTime,
1966 stopPosition, codecInst) != 0) {
1967 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1968 "StartPlayingFile() failed to start "
1969 "file playout");
1970 _inputFilePlayerPtr->StopPlayingFile();
1971 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1972 _inputFilePlayerPtr = NULL;
1973 return -1;
1974 }
1975
1976 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
1977 channel_state_.SetInputFilePlaying(true);
1978
1979 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001980}
1981
kwiberg55b97fe2016-01-28 05:22:45 -08001982int Channel::StopPlayingFileAsMicrophone() {
1983 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1984 "Channel::StopPlayingFileAsMicrophone()");
1985
1986 rtc::CritScope cs(&_fileCritSect);
1987
1988 if (!channel_state_.Get().input_file_playing) {
1989 return 0;
1990 }
1991
1992 if (_inputFilePlayerPtr->StopPlayingFile() != 0) {
1993 _engineStatisticsPtr->SetLastError(
1994 VE_STOP_RECORDING_FAILED, kTraceError,
1995 "StopPlayingFile() could not stop playing");
1996 return -1;
1997 }
1998 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1999 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2000 _inputFilePlayerPtr = NULL;
2001 channel_state_.SetInputFilePlaying(false);
2002
2003 return 0;
2004}
2005
2006int Channel::IsPlayingFileAsMicrophone() const {
2007 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002008}
2009
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002010int Channel::StartRecordingPlayout(const char* fileName,
kwiberg55b97fe2016-01-28 05:22:45 -08002011 const CodecInst* codecInst) {
2012 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2013 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
niklase@google.com470e71d2011-07-07 08:21:25 +00002014
kwiberg55b97fe2016-01-28 05:22:45 -08002015 if (_outputFileRecording) {
2016 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
2017 "StartRecordingPlayout() is already recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00002018 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002019 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002020
kwiberg55b97fe2016-01-28 05:22:45 -08002021 FileFormats format;
2022 const uint32_t notificationTime(0); // Not supported in VoE
2023 CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
niklase@google.com470e71d2011-07-07 08:21:25 +00002024
kwiberg55b97fe2016-01-28 05:22:45 -08002025 if ((codecInst != NULL) &&
2026 ((codecInst->channels < 1) || (codecInst->channels > 2))) {
2027 _engineStatisticsPtr->SetLastError(
2028 VE_BAD_ARGUMENT, kTraceError,
2029 "StartRecordingPlayout() invalid compression");
2030 return (-1);
2031 }
2032 if (codecInst == NULL) {
2033 format = kFileFormatPcm16kHzFile;
2034 codecInst = &dummyCodec;
2035 } else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
2036 (STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
2037 (STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
2038 format = kFileFormatWavFile;
2039 } else {
2040 format = kFileFormatCompressedFile;
2041 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002042
kwiberg55b97fe2016-01-28 05:22:45 -08002043 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002044
kwiberg55b97fe2016-01-28 05:22:45 -08002045 // Destroy the old instance
2046 if (_outputFileRecorderPtr) {
niklase@google.com470e71d2011-07-07 08:21:25 +00002047 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2048 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2049 _outputFileRecorderPtr = NULL;
kwiberg55b97fe2016-01-28 05:22:45 -08002050 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002051
kwiberg55b97fe2016-01-28 05:22:45 -08002052 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2053 _outputFileRecorderId, (const FileFormats)format);
2054 if (_outputFileRecorderPtr == NULL) {
2055 _engineStatisticsPtr->SetLastError(
2056 VE_INVALID_ARGUMENT, kTraceError,
2057 "StartRecordingPlayout() fileRecorder format isnot correct");
2058 return -1;
2059 }
2060
2061 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2062 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
2063 _engineStatisticsPtr->SetLastError(
2064 VE_BAD_FILE, kTraceError,
2065 "StartRecordingAudioFile() failed to start file recording");
2066 _outputFileRecorderPtr->StopRecording();
2067 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2068 _outputFileRecorderPtr = NULL;
2069 return -1;
2070 }
2071 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2072 _outputFileRecording = true;
2073
2074 return 0;
2075}
2076
2077int Channel::StartRecordingPlayout(OutStream* stream,
2078 const CodecInst* codecInst) {
2079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2080 "Channel::StartRecordingPlayout()");
2081
2082 if (_outputFileRecording) {
2083 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
2084 "StartRecordingPlayout() is already recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00002085 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002086 }
2087
2088 FileFormats format;
2089 const uint32_t notificationTime(0); // Not supported in VoE
2090 CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
2091
2092 if (codecInst != NULL && codecInst->channels != 1) {
2093 _engineStatisticsPtr->SetLastError(
2094 VE_BAD_ARGUMENT, kTraceError,
2095 "StartRecordingPlayout() invalid compression");
2096 return (-1);
2097 }
2098 if (codecInst == NULL) {
2099 format = kFileFormatPcm16kHzFile;
2100 codecInst = &dummyCodec;
2101 } else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
2102 (STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
2103 (STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
2104 format = kFileFormatWavFile;
2105 } else {
2106 format = kFileFormatCompressedFile;
2107 }
2108
2109 rtc::CritScope cs(&_fileCritSect);
2110
2111 // Destroy the old instance
2112 if (_outputFileRecorderPtr) {
2113 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2114 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2115 _outputFileRecorderPtr = NULL;
2116 }
2117
2118 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2119 _outputFileRecorderId, (const FileFormats)format);
2120 if (_outputFileRecorderPtr == NULL) {
2121 _engineStatisticsPtr->SetLastError(
2122 VE_INVALID_ARGUMENT, kTraceError,
2123 "StartRecordingPlayout() fileRecorder format isnot correct");
2124 return -1;
2125 }
2126
2127 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2128 notificationTime) != 0) {
2129 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2130 "StartRecordingPlayout() failed to "
2131 "start file recording");
2132 _outputFileRecorderPtr->StopRecording();
2133 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2134 _outputFileRecorderPtr = NULL;
2135 return -1;
2136 }
2137
2138 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2139 _outputFileRecording = true;
2140
2141 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002142}
2143
kwiberg55b97fe2016-01-28 05:22:45 -08002144int Channel::StopRecordingPlayout() {
2145 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
2146 "Channel::StopRecordingPlayout()");
2147
2148 if (!_outputFileRecording) {
2149 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
2150 "StopRecordingPlayout() isnot recording");
2151 return -1;
2152 }
2153
2154 rtc::CritScope cs(&_fileCritSect);
2155
2156 if (_outputFileRecorderPtr->StopRecording() != 0) {
2157 _engineStatisticsPtr->SetLastError(
2158 VE_STOP_RECORDING_FAILED, kTraceError,
2159 "StopRecording() could not stop recording");
2160 return (-1);
2161 }
2162 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2163 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2164 _outputFileRecorderPtr = NULL;
2165 _outputFileRecording = false;
2166
2167 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002168}
2169
kwiberg55b97fe2016-01-28 05:22:45 -08002170void Channel::SetMixWithMicStatus(bool mix) {
2171 rtc::CritScope cs(&_fileCritSect);
2172 _mixFileWithMicrophone = mix;
niklase@google.com470e71d2011-07-07 08:21:25 +00002173}
2174
kwiberg55b97fe2016-01-28 05:22:45 -08002175int Channel::GetSpeechOutputLevel(uint32_t& level) const {
2176 int8_t currentLevel = _outputAudioLevel.Level();
2177 level = static_cast<int32_t>(currentLevel);
2178 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002179}
2180
kwiberg55b97fe2016-01-28 05:22:45 -08002181int Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const {
2182 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2183 level = static_cast<int32_t>(currentLevel);
2184 return 0;
2185}
2186
solenberg1c2af8e2016-03-24 10:36:00 -07002187int Channel::SetInputMute(bool enable) {
kwiberg55b97fe2016-01-28 05:22:45 -08002188 rtc::CritScope cs(&volume_settings_critsect_);
2189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002190 "Channel::SetMute(enable=%d)", enable);
solenberg1c2af8e2016-03-24 10:36:00 -07002191 input_mute_ = enable;
kwiberg55b97fe2016-01-28 05:22:45 -08002192 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002193}
2194
solenberg1c2af8e2016-03-24 10:36:00 -07002195bool Channel::InputMute() const {
kwiberg55b97fe2016-01-28 05:22:45 -08002196 rtc::CritScope cs(&volume_settings_critsect_);
solenberg1c2af8e2016-03-24 10:36:00 -07002197 return input_mute_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002198}
2199
kwiberg55b97fe2016-01-28 05:22:45 -08002200int Channel::SetOutputVolumePan(float left, float right) {
2201 rtc::CritScope cs(&volume_settings_critsect_);
2202 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002203 "Channel::SetOutputVolumePan()");
kwiberg55b97fe2016-01-28 05:22:45 -08002204 _panLeft = left;
2205 _panRight = right;
2206 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002207}
2208
kwiberg55b97fe2016-01-28 05:22:45 -08002209int Channel::GetOutputVolumePan(float& left, float& right) const {
2210 rtc::CritScope cs(&volume_settings_critsect_);
2211 left = _panLeft;
2212 right = _panRight;
2213 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002214}
2215
kwiberg55b97fe2016-01-28 05:22:45 -08002216int Channel::SetChannelOutputVolumeScaling(float scaling) {
2217 rtc::CritScope cs(&volume_settings_critsect_);
2218 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002219 "Channel::SetChannelOutputVolumeScaling()");
kwiberg55b97fe2016-01-28 05:22:45 -08002220 _outputGain = scaling;
2221 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002222}
2223
kwiberg55b97fe2016-01-28 05:22:45 -08002224int Channel::GetChannelOutputVolumeScaling(float& scaling) const {
2225 rtc::CritScope cs(&volume_settings_critsect_);
2226 scaling = _outputGain;
2227 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002228}
2229
solenberg8842c3e2016-03-11 03:06:41 -08002230int Channel::SendTelephoneEventOutband(int event, int duration_ms) {
kwiberg55b97fe2016-01-28 05:22:45 -08002231 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
solenberg8842c3e2016-03-11 03:06:41 -08002232 "Channel::SendTelephoneEventOutband(...)");
2233 RTC_DCHECK_LE(0, event);
2234 RTC_DCHECK_GE(255, event);
2235 RTC_DCHECK_LE(0, duration_ms);
2236 RTC_DCHECK_GE(65535, duration_ms);
kwiberg55b97fe2016-01-28 05:22:45 -08002237 if (!Sending()) {
2238 return -1;
2239 }
solenberg8842c3e2016-03-11 03:06:41 -08002240 if (_rtpRtcpModule->SendTelephoneEventOutband(
2241 event, duration_ms, kTelephoneEventAttenuationdB) != 0) {
kwiberg55b97fe2016-01-28 05:22:45 -08002242 _engineStatisticsPtr->SetLastError(
2243 VE_SEND_DTMF_FAILED, kTraceWarning,
2244 "SendTelephoneEventOutband() failed to send event");
2245 return -1;
2246 }
2247 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002248}
2249
solenberg31642aa2016-03-14 08:00:37 -07002250int Channel::SetSendTelephoneEventPayloadType(int payload_type) {
kwiberg55b97fe2016-01-28 05:22:45 -08002251 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002252 "Channel::SetSendTelephoneEventPayloadType()");
solenberg31642aa2016-03-14 08:00:37 -07002253 RTC_DCHECK_LE(0, payload_type);
2254 RTC_DCHECK_GE(127, payload_type);
2255 CodecInst codec = {0};
kwiberg55b97fe2016-01-28 05:22:45 -08002256 codec.plfreq = 8000;
solenberg31642aa2016-03-14 08:00:37 -07002257 codec.pltype = payload_type;
kwiberg55b97fe2016-01-28 05:22:45 -08002258 memcpy(codec.plname, "telephone-event", 16);
2259 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2260 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2261 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2262 _engineStatisticsPtr->SetLastError(
2263 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2264 "SetSendTelephoneEventPayloadType() failed to register send"
2265 "payload type");
2266 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002267 }
kwiberg55b97fe2016-01-28 05:22:45 -08002268 }
kwiberg55b97fe2016-01-28 05:22:45 -08002269 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002270}
2271
kwiberg55b97fe2016-01-28 05:22:45 -08002272int Channel::UpdateRxVadDetection(AudioFrame& audioFrame) {
2273 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2274 "Channel::UpdateRxVadDetection()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002275
kwiberg55b97fe2016-01-28 05:22:45 -08002276 int vadDecision = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002277
kwiberg55b97fe2016-01-28 05:22:45 -08002278 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive) ? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002279
kwiberg55b97fe2016-01-28 05:22:45 -08002280 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr) {
2281 OnRxVadDetected(vadDecision);
2282 _oldVadDecision = vadDecision;
2283 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002284
kwiberg55b97fe2016-01-28 05:22:45 -08002285 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2286 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2287 vadDecision);
2288 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002289}
2290
kwiberg55b97fe2016-01-28 05:22:45 -08002291int Channel::RegisterRxVadObserver(VoERxVadCallback& observer) {
2292 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2293 "Channel::RegisterRxVadObserver()");
2294 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002295
kwiberg55b97fe2016-01-28 05:22:45 -08002296 if (_rxVadObserverPtr) {
2297 _engineStatisticsPtr->SetLastError(
2298 VE_INVALID_OPERATION, kTraceError,
2299 "RegisterRxVadObserver() observer already enabled");
2300 return -1;
2301 }
2302 _rxVadObserverPtr = &observer;
2303 _RxVadDetection = true;
2304 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002305}
2306
kwiberg55b97fe2016-01-28 05:22:45 -08002307int Channel::DeRegisterRxVadObserver() {
2308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2309 "Channel::DeRegisterRxVadObserver()");
2310 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002311
kwiberg55b97fe2016-01-28 05:22:45 -08002312 if (!_rxVadObserverPtr) {
2313 _engineStatisticsPtr->SetLastError(
2314 VE_INVALID_OPERATION, kTraceWarning,
2315 "DeRegisterRxVadObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002316 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002317 }
2318 _rxVadObserverPtr = NULL;
2319 _RxVadDetection = false;
2320 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002321}
2322
kwiberg55b97fe2016-01-28 05:22:45 -08002323int Channel::VoiceActivityIndicator(int& activity) {
2324 activity = _sendFrameType;
2325 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002326}
2327
2328#ifdef WEBRTC_VOICE_ENGINE_AGC
2329
kwiberg55b97fe2016-01-28 05:22:45 -08002330int Channel::SetRxAgcStatus(bool enable, AgcModes mode) {
2331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2332 "Channel::SetRxAgcStatus(enable=%d, mode=%d)", (int)enable,
2333 (int)mode);
niklase@google.com470e71d2011-07-07 08:21:25 +00002334
kwiberg55b97fe2016-01-28 05:22:45 -08002335 GainControl::Mode agcMode = kDefaultRxAgcMode;
2336 switch (mode) {
2337 case kAgcDefault:
2338 break;
2339 case kAgcUnchanged:
2340 agcMode = rx_audioproc_->gain_control()->mode();
2341 break;
2342 case kAgcFixedDigital:
2343 agcMode = GainControl::kFixedDigital;
2344 break;
2345 case kAgcAdaptiveDigital:
2346 agcMode = GainControl::kAdaptiveDigital;
2347 break;
2348 default:
2349 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
2350 "SetRxAgcStatus() invalid Agc mode");
2351 return -1;
2352 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002353
kwiberg55b97fe2016-01-28 05:22:45 -08002354 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0) {
2355 _engineStatisticsPtr->SetLastError(
2356 VE_APM_ERROR, kTraceError, "SetRxAgcStatus() failed to set Agc mode");
2357 return -1;
2358 }
2359 if (rx_audioproc_->gain_control()->Enable(enable) != 0) {
2360 _engineStatisticsPtr->SetLastError(
2361 VE_APM_ERROR, kTraceError, "SetRxAgcStatus() failed to set Agc state");
2362 return -1;
2363 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002364
kwiberg55b97fe2016-01-28 05:22:45 -08002365 _rxAgcIsEnabled = enable;
2366 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002367
kwiberg55b97fe2016-01-28 05:22:45 -08002368 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002369}
2370
kwiberg55b97fe2016-01-28 05:22:45 -08002371int Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode) {
2372 bool enable = rx_audioproc_->gain_control()->is_enabled();
2373 GainControl::Mode agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002374
kwiberg55b97fe2016-01-28 05:22:45 -08002375 enabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00002376
kwiberg55b97fe2016-01-28 05:22:45 -08002377 switch (agcMode) {
2378 case GainControl::kFixedDigital:
2379 mode = kAgcFixedDigital;
2380 break;
2381 case GainControl::kAdaptiveDigital:
2382 mode = kAgcAdaptiveDigital;
2383 break;
2384 default:
2385 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
2386 "GetRxAgcStatus() invalid Agc mode");
2387 return -1;
2388 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002389
kwiberg55b97fe2016-01-28 05:22:45 -08002390 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002391}
2392
kwiberg55b97fe2016-01-28 05:22:45 -08002393int Channel::SetRxAgcConfig(AgcConfig config) {
2394 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2395 "Channel::SetRxAgcConfig()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002396
kwiberg55b97fe2016-01-28 05:22:45 -08002397 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
2398 config.targetLeveldBOv) != 0) {
2399 _engineStatisticsPtr->SetLastError(
2400 VE_APM_ERROR, kTraceError,
2401 "SetRxAgcConfig() failed to set target peak |level|"
2402 "(or envelope) of the Agc");
2403 return -1;
2404 }
2405 if (rx_audioproc_->gain_control()->set_compression_gain_db(
2406 config.digitalCompressionGaindB) != 0) {
2407 _engineStatisticsPtr->SetLastError(
2408 VE_APM_ERROR, kTraceError,
2409 "SetRxAgcConfig() failed to set the range in |gain| the"
2410 " digital compression stage may apply");
2411 return -1;
2412 }
2413 if (rx_audioproc_->gain_control()->enable_limiter(config.limiterEnable) !=
2414 0) {
2415 _engineStatisticsPtr->SetLastError(
2416 VE_APM_ERROR, kTraceError,
2417 "SetRxAgcConfig() failed to set hard limiter to the signal");
2418 return -1;
2419 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002420
kwiberg55b97fe2016-01-28 05:22:45 -08002421 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002422}
2423
kwiberg55b97fe2016-01-28 05:22:45 -08002424int Channel::GetRxAgcConfig(AgcConfig& config) {
2425 config.targetLeveldBOv = rx_audioproc_->gain_control()->target_level_dbfs();
2426 config.digitalCompressionGaindB =
2427 rx_audioproc_->gain_control()->compression_gain_db();
2428 config.limiterEnable = rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002429
kwiberg55b97fe2016-01-28 05:22:45 -08002430 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002431}
2432
kwiberg55b97fe2016-01-28 05:22:45 -08002433#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
niklase@google.com470e71d2011-07-07 08:21:25 +00002434
2435#ifdef WEBRTC_VOICE_ENGINE_NR
2436
kwiberg55b97fe2016-01-28 05:22:45 -08002437int Channel::SetRxNsStatus(bool enable, NsModes mode) {
2438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2439 "Channel::SetRxNsStatus(enable=%d, mode=%d)", (int)enable,
2440 (int)mode);
niklase@google.com470e71d2011-07-07 08:21:25 +00002441
kwiberg55b97fe2016-01-28 05:22:45 -08002442 NoiseSuppression::Level nsLevel = kDefaultNsMode;
2443 switch (mode) {
2444 case kNsDefault:
2445 break;
2446 case kNsUnchanged:
2447 nsLevel = rx_audioproc_->noise_suppression()->level();
2448 break;
2449 case kNsConference:
2450 nsLevel = NoiseSuppression::kHigh;
2451 break;
2452 case kNsLowSuppression:
2453 nsLevel = NoiseSuppression::kLow;
2454 break;
2455 case kNsModerateSuppression:
2456 nsLevel = NoiseSuppression::kModerate;
2457 break;
2458 case kNsHighSuppression:
2459 nsLevel = NoiseSuppression::kHigh;
2460 break;
2461 case kNsVeryHighSuppression:
2462 nsLevel = NoiseSuppression::kVeryHigh;
2463 break;
2464 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002465
kwiberg55b97fe2016-01-28 05:22:45 -08002466 if (rx_audioproc_->noise_suppression()->set_level(nsLevel) != 0) {
2467 _engineStatisticsPtr->SetLastError(
2468 VE_APM_ERROR, kTraceError, "SetRxNsStatus() failed to set NS level");
2469 return -1;
2470 }
2471 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0) {
2472 _engineStatisticsPtr->SetLastError(
2473 VE_APM_ERROR, kTraceError, "SetRxNsStatus() failed to set NS state");
2474 return -1;
2475 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002476
kwiberg55b97fe2016-01-28 05:22:45 -08002477 _rxNsIsEnabled = enable;
2478 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002479
kwiberg55b97fe2016-01-28 05:22:45 -08002480 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002481}
2482
kwiberg55b97fe2016-01-28 05:22:45 -08002483int Channel::GetRxNsStatus(bool& enabled, NsModes& mode) {
2484 bool enable = rx_audioproc_->noise_suppression()->is_enabled();
2485 NoiseSuppression::Level ncLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002486
kwiberg55b97fe2016-01-28 05:22:45 -08002487 enabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00002488
kwiberg55b97fe2016-01-28 05:22:45 -08002489 switch (ncLevel) {
2490 case NoiseSuppression::kLow:
2491 mode = kNsLowSuppression;
2492 break;
2493 case NoiseSuppression::kModerate:
2494 mode = kNsModerateSuppression;
2495 break;
2496 case NoiseSuppression::kHigh:
2497 mode = kNsHighSuppression;
2498 break;
2499 case NoiseSuppression::kVeryHigh:
2500 mode = kNsVeryHighSuppression;
2501 break;
2502 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002503
kwiberg55b97fe2016-01-28 05:22:45 -08002504 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002505}
2506
kwiberg55b97fe2016-01-28 05:22:45 -08002507#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
niklase@google.com470e71d2011-07-07 08:21:25 +00002508
kwiberg55b97fe2016-01-28 05:22:45 -08002509int Channel::SetLocalSSRC(unsigned int ssrc) {
2510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2511 "Channel::SetLocalSSRC()");
2512 if (channel_state_.Get().sending) {
2513 _engineStatisticsPtr->SetLastError(VE_ALREADY_SENDING, kTraceError,
2514 "SetLocalSSRC() already sending");
2515 return -1;
2516 }
2517 _rtpRtcpModule->SetSSRC(ssrc);
2518 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002519}
2520
kwiberg55b97fe2016-01-28 05:22:45 -08002521int Channel::GetLocalSSRC(unsigned int& ssrc) {
2522 ssrc = _rtpRtcpModule->SSRC();
2523 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002524}
2525
kwiberg55b97fe2016-01-28 05:22:45 -08002526int Channel::GetRemoteSSRC(unsigned int& ssrc) {
2527 ssrc = rtp_receiver_->SSRC();
2528 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002529}
2530
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002531int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002532 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002533 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002534}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002535
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002536int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2537 unsigned char id) {
kwiberg55b97fe2016-01-28 05:22:45 -08002538 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
2539 if (enable &&
2540 !rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
2541 id)) {
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002542 return -1;
2543 }
2544 return 0;
2545}
2546
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002547int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2548 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2549}
2550
2551int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2552 rtp_header_parser_->DeregisterRtpHeaderExtension(
2553 kRtpExtensionAbsoluteSendTime);
kwiberg55b97fe2016-01-28 05:22:45 -08002554 if (enable &&
2555 !rtp_header_parser_->RegisterRtpHeaderExtension(
2556 kRtpExtensionAbsoluteSendTime, id)) {
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002557 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002558 }
2559 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002560}
2561
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002562void Channel::EnableSendTransportSequenceNumber(int id) {
2563 int ret =
2564 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2565 RTC_DCHECK_EQ(0, ret);
2566}
2567
stefan3313ec92016-01-21 06:32:43 -08002568void Channel::EnableReceiveTransportSequenceNumber(int id) {
2569 rtp_header_parser_->DeregisterRtpHeaderExtension(
2570 kRtpExtensionTransportSequenceNumber);
2571 bool ret = rtp_header_parser_->RegisterRtpHeaderExtension(
2572 kRtpExtensionTransportSequenceNumber, id);
2573 RTC_DCHECK(ret);
2574}
2575
stefanbba9dec2016-02-01 04:39:55 -08002576void Channel::RegisterSenderCongestionControlObjects(
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002577 RtpPacketSender* rtp_packet_sender,
2578 TransportFeedbackObserver* transport_feedback_observer,
2579 PacketRouter* packet_router) {
stefanbba9dec2016-02-01 04:39:55 -08002580 RTC_DCHECK(rtp_packet_sender);
2581 RTC_DCHECK(transport_feedback_observer);
2582 RTC_DCHECK(packet_router && !packet_router_);
2583 feedback_observer_proxy_->SetTransportFeedbackObserver(
2584 transport_feedback_observer);
2585 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2586 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2587 _rtpRtcpModule->SetStorePacketsStatus(true, 600);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002588 packet_router->AddRtpModule(_rtpRtcpModule.get());
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002589 packet_router_ = packet_router;
2590}
2591
stefanbba9dec2016-02-01 04:39:55 -08002592void Channel::RegisterReceiverCongestionControlObjects(
2593 PacketRouter* packet_router) {
2594 RTC_DCHECK(packet_router && !packet_router_);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002595 packet_router->AddRtpModule(_rtpRtcpModule.get());
stefanbba9dec2016-02-01 04:39:55 -08002596 packet_router_ = packet_router;
2597}
2598
2599void Channel::ResetCongestionControlObjects() {
2600 RTC_DCHECK(packet_router_);
2601 _rtpRtcpModule->SetStorePacketsStatus(false, 600);
2602 feedback_observer_proxy_->SetTransportFeedbackObserver(nullptr);
2603 seq_num_allocator_proxy_->SetSequenceNumberAllocator(nullptr);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002604 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
stefanbba9dec2016-02-01 04:39:55 -08002605 packet_router_ = nullptr;
2606 rtp_packet_sender_proxy_->SetPacketSender(nullptr);
2607}
2608
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002609void Channel::SetRTCPStatus(bool enable) {
2610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2611 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002612 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002613}
2614
kwiberg55b97fe2016-01-28 05:22:45 -08002615int Channel::GetRTCPStatus(bool& enabled) {
pbosda903ea2015-10-02 02:36:56 -07002616 RtcpMode method = _rtpRtcpModule->RTCP();
2617 enabled = (method != RtcpMode::kOff);
kwiberg55b97fe2016-01-28 05:22:45 -08002618 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002619}
2620
kwiberg55b97fe2016-01-28 05:22:45 -08002621int Channel::SetRTCP_CNAME(const char cName[256]) {
2622 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2623 "Channel::SetRTCP_CNAME()");
2624 if (_rtpRtcpModule->SetCNAME(cName) != 0) {
2625 _engineStatisticsPtr->SetLastError(
2626 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2627 "SetRTCP_CNAME() failed to set RTCP CNAME");
2628 return -1;
2629 }
2630 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002631}
2632
kwiberg55b97fe2016-01-28 05:22:45 -08002633int Channel::GetRemoteRTCP_CNAME(char cName[256]) {
2634 if (cName == NULL) {
2635 _engineStatisticsPtr->SetLastError(
2636 VE_INVALID_ARGUMENT, kTraceError,
2637 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2638 return -1;
2639 }
2640 char cname[RTCP_CNAME_SIZE];
2641 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
2642 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0) {
2643 _engineStatisticsPtr->SetLastError(
2644 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2645 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2646 return -1;
2647 }
2648 strcpy(cName, cname);
2649 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002650}
2651
kwiberg55b97fe2016-01-28 05:22:45 -08002652int Channel::GetRemoteRTCPData(unsigned int& NTPHigh,
2653 unsigned int& NTPLow,
2654 unsigned int& timestamp,
2655 unsigned int& playoutTimestamp,
2656 unsigned int* jitter,
2657 unsigned short* fractionLost) {
2658 // --- Information from sender info in received Sender Reports
niklase@google.com470e71d2011-07-07 08:21:25 +00002659
kwiberg55b97fe2016-01-28 05:22:45 -08002660 RTCPSenderInfo senderInfo;
2661 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0) {
2662 _engineStatisticsPtr->SetLastError(
2663 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2664 "GetRemoteRTCPData() failed to retrieve sender info for remote "
2665 "side");
2666 return -1;
2667 }
2668
2669 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2670 // and octet count)
2671 NTPHigh = senderInfo.NTPseconds;
2672 NTPLow = senderInfo.NTPfraction;
2673 timestamp = senderInfo.RTPtimeStamp;
2674
2675 // --- Locally derived information
2676
2677 // This value is updated on each incoming RTCP packet (0 when no packet
2678 // has been received)
2679 playoutTimestamp = playout_timestamp_rtcp_;
2680
2681 if (NULL != jitter || NULL != fractionLost) {
2682 // Get all RTCP receiver report blocks that have been received on this
2683 // channel. If we receive RTP packets from a remote source we know the
2684 // remote SSRC and use the report block from him.
2685 // Otherwise use the first report block.
2686 std::vector<RTCPReportBlock> remote_stats;
2687 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
2688 remote_stats.empty()) {
2689 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
2690 "GetRemoteRTCPData() failed to measure statistics due"
2691 " to lack of received RTP and/or RTCP packets");
2692 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002693 }
2694
kwiberg55b97fe2016-01-28 05:22:45 -08002695 uint32_t remoteSSRC = rtp_receiver_->SSRC();
2696 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2697 for (; it != remote_stats.end(); ++it) {
2698 if (it->remoteSSRC == remoteSSRC)
2699 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002700 }
kwiberg55b97fe2016-01-28 05:22:45 -08002701
2702 if (it == remote_stats.end()) {
2703 // If we have not received any RTCP packets from this SSRC it probably
2704 // means that we have not received any RTP packets.
2705 // Use the first received report block instead.
2706 it = remote_stats.begin();
2707 remoteSSRC = it->remoteSSRC;
2708 }
2709
2710 if (jitter) {
2711 *jitter = it->jitter;
2712 }
2713
2714 if (fractionLost) {
2715 *fractionLost = it->fractionLost;
2716 }
2717 }
2718 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002719}
2720
kwiberg55b97fe2016-01-28 05:22:45 -08002721int Channel::SendApplicationDefinedRTCPPacket(
2722 unsigned char subType,
2723 unsigned int name,
2724 const char* data,
2725 unsigned short dataLengthInBytes) {
2726 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2727 "Channel::SendApplicationDefinedRTCPPacket()");
2728 if (!channel_state_.Get().sending) {
2729 _engineStatisticsPtr->SetLastError(
2730 VE_NOT_SENDING, kTraceError,
2731 "SendApplicationDefinedRTCPPacket() not sending");
2732 return -1;
2733 }
2734 if (NULL == data) {
2735 _engineStatisticsPtr->SetLastError(
2736 VE_INVALID_ARGUMENT, kTraceError,
2737 "SendApplicationDefinedRTCPPacket() invalid data value");
2738 return -1;
2739 }
2740 if (dataLengthInBytes % 4 != 0) {
2741 _engineStatisticsPtr->SetLastError(
2742 VE_INVALID_ARGUMENT, kTraceError,
2743 "SendApplicationDefinedRTCPPacket() invalid length value");
2744 return -1;
2745 }
2746 RtcpMode status = _rtpRtcpModule->RTCP();
2747 if (status == RtcpMode::kOff) {
2748 _engineStatisticsPtr->SetLastError(
2749 VE_RTCP_ERROR, kTraceError,
2750 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
2751 return -1;
2752 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002753
kwiberg55b97fe2016-01-28 05:22:45 -08002754 // Create and schedule the RTCP APP packet for transmission
2755 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
2756 subType, name, (const unsigned char*)data, dataLengthInBytes) != 0) {
2757 _engineStatisticsPtr->SetLastError(
2758 VE_SEND_ERROR, kTraceError,
2759 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
2760 return -1;
2761 }
2762 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002763}
2764
kwiberg55b97fe2016-01-28 05:22:45 -08002765int Channel::GetRTPStatistics(unsigned int& averageJitterMs,
2766 unsigned int& maxJitterMs,
2767 unsigned int& discardedPackets) {
2768 // The jitter statistics is updated for each received RTP packet and is
2769 // based on received packets.
2770 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
2771 // If RTCP is off, there is no timed thread in the RTCP module regularly
2772 // generating new stats, trigger the update manually here instead.
2773 StreamStatistician* statistician =
2774 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
2775 if (statistician) {
2776 // Don't use returned statistics, use data from proxy instead so that
2777 // max jitter can be fetched atomically.
2778 RtcpStatistics s;
2779 statistician->GetStatistics(&s, true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002780 }
kwiberg55b97fe2016-01-28 05:22:45 -08002781 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002782
kwiberg55b97fe2016-01-28 05:22:45 -08002783 ChannelStatistics stats = statistics_proxy_->GetStats();
2784 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
2785 if (playoutFrequency > 0) {
2786 // Scale RTP statistics given the current playout frequency
2787 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
2788 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
2789 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002790
kwiberg55b97fe2016-01-28 05:22:45 -08002791 discardedPackets = _numberOfDiscardedPackets;
niklase@google.com470e71d2011-07-07 08:21:25 +00002792
kwiberg55b97fe2016-01-28 05:22:45 -08002793 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002794}
2795
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002796int Channel::GetRemoteRTCPReportBlocks(
2797 std::vector<ReportBlock>* report_blocks) {
2798 if (report_blocks == NULL) {
kwiberg55b97fe2016-01-28 05:22:45 -08002799 _engineStatisticsPtr->SetLastError(
2800 VE_INVALID_ARGUMENT, kTraceError,
2801 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002802 return -1;
2803 }
2804
2805 // Get the report blocks from the latest received RTCP Sender or Receiver
2806 // Report. Each element in the vector contains the sender's SSRC and a
2807 // report block according to RFC 3550.
2808 std::vector<RTCPReportBlock> rtcp_report_blocks;
2809 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002810 return -1;
2811 }
2812
2813 if (rtcp_report_blocks.empty())
2814 return 0;
2815
2816 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
2817 for (; it != rtcp_report_blocks.end(); ++it) {
2818 ReportBlock report_block;
2819 report_block.sender_SSRC = it->remoteSSRC;
2820 report_block.source_SSRC = it->sourceSSRC;
2821 report_block.fraction_lost = it->fractionLost;
2822 report_block.cumulative_num_packets_lost = it->cumulativeLost;
2823 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
2824 report_block.interarrival_jitter = it->jitter;
2825 report_block.last_SR_timestamp = it->lastSR;
2826 report_block.delay_since_last_SR = it->delaySinceLastSR;
2827 report_blocks->push_back(report_block);
2828 }
2829 return 0;
2830}
2831
kwiberg55b97fe2016-01-28 05:22:45 -08002832int Channel::GetRTPStatistics(CallStatistics& stats) {
2833 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00002834
kwiberg55b97fe2016-01-28 05:22:45 -08002835 // The jitter statistics is updated for each received RTP packet and is
2836 // based on received packets.
2837 RtcpStatistics statistics;
2838 StreamStatistician* statistician =
2839 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
Peter Boström59013bc2016-02-12 11:35:08 +01002840 if (statistician) {
2841 statistician->GetStatistics(&statistics,
2842 _rtpRtcpModule->RTCP() == RtcpMode::kOff);
kwiberg55b97fe2016-01-28 05:22:45 -08002843 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002844
kwiberg55b97fe2016-01-28 05:22:45 -08002845 stats.fractionLost = statistics.fraction_lost;
2846 stats.cumulativeLost = statistics.cumulative_lost;
2847 stats.extendedMax = statistics.extended_max_sequence_number;
2848 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00002849
kwiberg55b97fe2016-01-28 05:22:45 -08002850 // --- RTT
2851 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002852
kwiberg55b97fe2016-01-28 05:22:45 -08002853 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00002854
kwiberg55b97fe2016-01-28 05:22:45 -08002855 size_t bytesSent(0);
2856 uint32_t packetsSent(0);
2857 size_t bytesReceived(0);
2858 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002859
kwiberg55b97fe2016-01-28 05:22:45 -08002860 if (statistician) {
2861 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
2862 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002863
kwiberg55b97fe2016-01-28 05:22:45 -08002864 if (_rtpRtcpModule->DataCountersRTP(&bytesSent, &packetsSent) != 0) {
2865 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
2866 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
2867 " output will not be complete");
2868 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002869
kwiberg55b97fe2016-01-28 05:22:45 -08002870 stats.bytesSent = bytesSent;
2871 stats.packetsSent = packetsSent;
2872 stats.bytesReceived = bytesReceived;
2873 stats.packetsReceived = packetsReceived;
niklase@google.com470e71d2011-07-07 08:21:25 +00002874
kwiberg55b97fe2016-01-28 05:22:45 -08002875 // --- Timestamps
2876 {
2877 rtc::CritScope lock(&ts_stats_lock_);
2878 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
2879 }
2880 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002881}
2882
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002883int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002884 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002885 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002886
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00002887 if (enable) {
2888 if (redPayloadtype < 0 || redPayloadtype > 127) {
2889 _engineStatisticsPtr->SetLastError(
2890 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002891 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00002892 return -1;
2893 }
2894
2895 if (SetRedPayloadType(redPayloadtype) < 0) {
2896 _engineStatisticsPtr->SetLastError(
2897 VE_CODEC_ERROR, kTraceError,
2898 "SetSecondarySendCodec() Failed to register RED ACM");
2899 return -1;
2900 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002901 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002902
kwibergc8d071e2016-04-06 12:22:38 -07002903 if (!codec_manager_.SetCopyRed(enable) ||
2904 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002905 _engineStatisticsPtr->SetLastError(
2906 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00002907 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002908 return -1;
2909 }
2910 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002911}
2912
kwiberg55b97fe2016-01-28 05:22:45 -08002913int Channel::GetREDStatus(bool& enabled, int& redPayloadtype) {
kwibergc8d071e2016-04-06 12:22:38 -07002914 enabled = codec_manager_.GetStackParams()->use_red;
kwiberg55b97fe2016-01-28 05:22:45 -08002915 if (enabled) {
2916 int8_t payloadType = 0;
2917 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
2918 _engineStatisticsPtr->SetLastError(
2919 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2920 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
2921 "module");
2922 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002923 }
kwiberg55b97fe2016-01-28 05:22:45 -08002924 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002925 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002926 }
2927 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002928}
2929
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002930int Channel::SetCodecFECStatus(bool enable) {
2931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2932 "Channel::SetCodecFECStatus()");
2933
kwibergc8d071e2016-04-06 12:22:38 -07002934 if (!codec_manager_.SetCodecFEC(enable) ||
2935 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002936 _engineStatisticsPtr->SetLastError(
2937 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2938 "SetCodecFECStatus() failed to set FEC state");
2939 return -1;
2940 }
2941 return 0;
2942}
2943
2944bool Channel::GetCodecFECStatus() {
kwibergc8d071e2016-04-06 12:22:38 -07002945 return codec_manager_.GetStackParams()->use_codec_fec;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002946}
2947
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002948void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
2949 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002950 // If pacing is enabled we always store packets.
2951 if (!pacing_enabled_)
2952 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002953 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002954 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002955 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002956 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002957 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002958}
2959
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002960// Called when we are missing one or more packets.
2961int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002962 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
2963}
2964
kwiberg55b97fe2016-01-28 05:22:45 -08002965uint32_t Channel::Demultiplex(const AudioFrame& audioFrame) {
2966 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2967 "Channel::Demultiplex()");
2968 _audioFrame.CopyFrom(audioFrame);
2969 _audioFrame.id_ = _channelId;
2970 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002971}
2972
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002973void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00002974 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07002975 size_t number_of_frames,
Peter Kasting69558702016-01-12 16:26:35 -08002976 size_t number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002977 CodecInst codec;
2978 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002979
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07002980 // Never upsample or upmix the capture signal here. This should be done at the
2981 // end of the send chain.
2982 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
2983 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
2984 RemixAndResample(audio_data, number_of_frames, number_of_channels,
2985 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002986}
2987
kwiberg55b97fe2016-01-28 05:22:45 -08002988uint32_t Channel::PrepareEncodeAndSend(int mixingFrequency) {
2989 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2990 "Channel::PrepareEncodeAndSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002991
kwiberg55b97fe2016-01-28 05:22:45 -08002992 if (_audioFrame.samples_per_channel_ == 0) {
2993 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
2994 "Channel::PrepareEncodeAndSend() invalid audio frame");
2995 return 0xFFFFFFFF;
2996 }
2997
2998 if (channel_state_.Get().input_file_playing) {
2999 MixOrReplaceAudioWithFile(mixingFrequency);
3000 }
3001
solenberg1c2af8e2016-03-24 10:36:00 -07003002 bool is_muted = InputMute(); // Cache locally as InputMute() takes a lock.
3003 AudioFrameOperations::Mute(&_audioFrame, previous_frame_muted_, is_muted);
kwiberg55b97fe2016-01-28 05:22:45 -08003004
3005 if (channel_state_.Get().input_external_media) {
3006 rtc::CritScope cs(&_callbackCritSect);
3007 const bool isStereo = (_audioFrame.num_channels_ == 2);
3008 if (_inputExternalMediaCallbackPtr) {
3009 _inputExternalMediaCallbackPtr->Process(
3010 _channelId, kRecordingPerChannel, (int16_t*)_audioFrame.data_,
3011 _audioFrame.samples_per_channel_, _audioFrame.sample_rate_hz_,
3012 isStereo);
niklase@google.com470e71d2011-07-07 08:21:25 +00003013 }
kwiberg55b97fe2016-01-28 05:22:45 -08003014 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003015
kwiberg55b97fe2016-01-28 05:22:45 -08003016 if (_includeAudioLevelIndication) {
3017 size_t length =
3018 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
Tommi60c4e0a2016-05-26 21:35:27 +02003019 RTC_CHECK_LE(length, sizeof(_audioFrame.data_));
solenberg1c2af8e2016-03-24 10:36:00 -07003020 if (is_muted && previous_frame_muted_) {
kwiberg55b97fe2016-01-28 05:22:45 -08003021 rms_level_.ProcessMuted(length);
3022 } else {
3023 rms_level_.Process(_audioFrame.data_, length);
niklase@google.com470e71d2011-07-07 08:21:25 +00003024 }
kwiberg55b97fe2016-01-28 05:22:45 -08003025 }
solenberg1c2af8e2016-03-24 10:36:00 -07003026 previous_frame_muted_ = is_muted;
niklase@google.com470e71d2011-07-07 08:21:25 +00003027
kwiberg55b97fe2016-01-28 05:22:45 -08003028 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003029}
3030
kwiberg55b97fe2016-01-28 05:22:45 -08003031uint32_t Channel::EncodeAndSend() {
3032 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
3033 "Channel::EncodeAndSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003034
kwiberg55b97fe2016-01-28 05:22:45 -08003035 assert(_audioFrame.num_channels_ <= 2);
3036 if (_audioFrame.samples_per_channel_ == 0) {
3037 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3038 "Channel::EncodeAndSend() invalid audio frame");
3039 return 0xFFFFFFFF;
3040 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003041
kwiberg55b97fe2016-01-28 05:22:45 -08003042 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003043
kwiberg55b97fe2016-01-28 05:22:45 -08003044 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
niklase@google.com470e71d2011-07-07 08:21:25 +00003045
kwiberg55b97fe2016-01-28 05:22:45 -08003046 // The ACM resamples internally.
3047 _audioFrame.timestamp_ = _timeStamp;
3048 // This call will trigger AudioPacketizationCallback::SendData if encoding
3049 // is done and payload is ready for packetization and transmission.
3050 // Otherwise, it will return without invoking the callback.
3051 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0) {
3052 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
3053 "Channel::EncodeAndSend() ACM encoding failed");
3054 return 0xFFFFFFFF;
3055 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003056
kwiberg55b97fe2016-01-28 05:22:45 -08003057 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
3058 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003059}
3060
Minyue2013aec2015-05-13 14:14:42 +02003061void Channel::DisassociateSendChannel(int channel_id) {
tommi31fc21f2016-01-21 10:37:37 -08003062 rtc::CritScope lock(&assoc_send_channel_lock_);
Minyue2013aec2015-05-13 14:14:42 +02003063 Channel* channel = associate_send_channel_.channel();
3064 if (channel && channel->ChannelId() == channel_id) {
3065 // If this channel is associated with a send channel of the specified
3066 // Channel ID, disassociate with it.
3067 ChannelOwner ref(NULL);
3068 associate_send_channel_ = ref;
3069 }
3070}
3071
kwiberg55b97fe2016-01-28 05:22:45 -08003072int Channel::RegisterExternalMediaProcessing(ProcessingTypes type,
3073 VoEMediaProcess& processObject) {
3074 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3075 "Channel::RegisterExternalMediaProcessing()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003076
kwiberg55b97fe2016-01-28 05:22:45 -08003077 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003078
kwiberg55b97fe2016-01-28 05:22:45 -08003079 if (kPlaybackPerChannel == type) {
3080 if (_outputExternalMediaCallbackPtr) {
3081 _engineStatisticsPtr->SetLastError(
3082 VE_INVALID_OPERATION, kTraceError,
3083 "Channel::RegisterExternalMediaProcessing() "
3084 "output external media already enabled");
3085 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003086 }
kwiberg55b97fe2016-01-28 05:22:45 -08003087 _outputExternalMediaCallbackPtr = &processObject;
3088 _outputExternalMedia = true;
3089 } else if (kRecordingPerChannel == type) {
3090 if (_inputExternalMediaCallbackPtr) {
3091 _engineStatisticsPtr->SetLastError(
3092 VE_INVALID_OPERATION, kTraceError,
3093 "Channel::RegisterExternalMediaProcessing() "
3094 "output external media already enabled");
3095 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003096 }
kwiberg55b97fe2016-01-28 05:22:45 -08003097 _inputExternalMediaCallbackPtr = &processObject;
3098 channel_state_.SetInputExternalMedia(true);
3099 }
3100 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003101}
3102
kwiberg55b97fe2016-01-28 05:22:45 -08003103int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
3104 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3105 "Channel::DeRegisterExternalMediaProcessing()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003106
kwiberg55b97fe2016-01-28 05:22:45 -08003107 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003108
kwiberg55b97fe2016-01-28 05:22:45 -08003109 if (kPlaybackPerChannel == type) {
3110 if (!_outputExternalMediaCallbackPtr) {
3111 _engineStatisticsPtr->SetLastError(
3112 VE_INVALID_OPERATION, kTraceWarning,
3113 "Channel::DeRegisterExternalMediaProcessing() "
3114 "output external media already disabled");
3115 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003116 }
kwiberg55b97fe2016-01-28 05:22:45 -08003117 _outputExternalMedia = false;
3118 _outputExternalMediaCallbackPtr = NULL;
3119 } else if (kRecordingPerChannel == type) {
3120 if (!_inputExternalMediaCallbackPtr) {
3121 _engineStatisticsPtr->SetLastError(
3122 VE_INVALID_OPERATION, kTraceWarning,
3123 "Channel::DeRegisterExternalMediaProcessing() "
3124 "input external media already disabled");
3125 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003126 }
kwiberg55b97fe2016-01-28 05:22:45 -08003127 channel_state_.SetInputExternalMedia(false);
3128 _inputExternalMediaCallbackPtr = NULL;
3129 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003130
kwiberg55b97fe2016-01-28 05:22:45 -08003131 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003132}
3133
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003134int Channel::SetExternalMixing(bool enabled) {
kwiberg55b97fe2016-01-28 05:22:45 -08003135 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3136 "Channel::SetExternalMixing(enabled=%d)", enabled);
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003137
kwiberg55b97fe2016-01-28 05:22:45 -08003138 if (channel_state_.Get().playing) {
3139 _engineStatisticsPtr->SetLastError(
3140 VE_INVALID_OPERATION, kTraceError,
3141 "Channel::SetExternalMixing() "
3142 "external mixing cannot be changed while playing.");
3143 return -1;
3144 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003145
kwiberg55b97fe2016-01-28 05:22:45 -08003146 _externalMixing = enabled;
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003147
kwiberg55b97fe2016-01-28 05:22:45 -08003148 return 0;
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003149}
3150
kwiberg55b97fe2016-01-28 05:22:45 -08003151int Channel::GetNetworkStatistics(NetworkStatistics& stats) {
3152 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003153}
3154
wu@webrtc.org24301a62013-12-13 19:17:43 +00003155void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3156 audio_coding_->GetDecodingCallStatistics(stats);
3157}
3158
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003159bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3160 int* playout_buffer_delay_ms) const {
tommi31fc21f2016-01-21 10:37:37 -08003161 rtc::CritScope lock(&video_sync_lock_);
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003162 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003163 return false;
3164 }
kwiberg55b97fe2016-01-28 05:22:45 -08003165 *jitter_buffer_delay_ms =
3166 (_average_jitter_buffer_delay_us + 500) / 1000 + _recPacketDelayMs;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003167 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003168 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003169}
3170
solenberg358057b2015-11-27 10:46:42 -08003171uint32_t Channel::GetDelayEstimate() const {
3172 int jitter_buffer_delay_ms = 0;
3173 int playout_buffer_delay_ms = 0;
3174 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3175 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3176}
3177
deadbeef74375882015-08-13 12:09:10 -07003178int Channel::LeastRequiredDelayMs() const {
3179 return audio_coding_->LeastRequiredDelayMs();
3180}
3181
kwiberg55b97fe2016-01-28 05:22:45 -08003182int Channel::SetMinimumPlayoutDelay(int delayMs) {
3183 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3184 "Channel::SetMinimumPlayoutDelay()");
3185 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3186 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs)) {
3187 _engineStatisticsPtr->SetLastError(
3188 VE_INVALID_ARGUMENT, kTraceError,
3189 "SetMinimumPlayoutDelay() invalid min delay");
3190 return -1;
3191 }
3192 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0) {
3193 _engineStatisticsPtr->SetLastError(
3194 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3195 "SetMinimumPlayoutDelay() failed to set min playout delay");
3196 return -1;
3197 }
3198 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003199}
3200
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003201int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003202 uint32_t playout_timestamp_rtp = 0;
3203 {
tommi31fc21f2016-01-21 10:37:37 -08003204 rtc::CritScope lock(&video_sync_lock_);
deadbeef74375882015-08-13 12:09:10 -07003205 playout_timestamp_rtp = playout_timestamp_rtp_;
3206 }
kwiberg55b97fe2016-01-28 05:22:45 -08003207 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003208 _engineStatisticsPtr->SetLastError(
3209 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3210 "GetPlayoutTimestamp() failed to retrieve timestamp");
3211 return -1;
3212 }
deadbeef74375882015-08-13 12:09:10 -07003213 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003214 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003215}
3216
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003217int Channel::SetInitTimestamp(unsigned int timestamp) {
3218 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003219 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003220 if (channel_state_.Get().sending) {
3221 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3222 "SetInitTimestamp() already sending");
3223 return -1;
3224 }
3225 _rtpRtcpModule->SetStartTimestamp(timestamp);
3226 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003227}
3228
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003229int Channel::SetInitSequenceNumber(short sequenceNumber) {
3230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3231 "Channel::SetInitSequenceNumber()");
3232 if (channel_state_.Get().sending) {
3233 _engineStatisticsPtr->SetLastError(
3234 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3235 return -1;
3236 }
3237 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3238 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003239}
3240
kwiberg55b97fe2016-01-28 05:22:45 -08003241int Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule,
3242 RtpReceiver** rtp_receiver) const {
3243 *rtpRtcpModule = _rtpRtcpModule.get();
3244 *rtp_receiver = rtp_receiver_.get();
3245 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003246}
3247
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003248// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3249// a shared helper.
kwiberg55b97fe2016-01-28 05:22:45 -08003250int32_t Channel::MixOrReplaceAudioWithFile(int mixingFrequency) {
kwibergb7f89d62016-02-17 10:04:18 -08003251 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
kwiberg55b97fe2016-01-28 05:22:45 -08003252 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003253
kwiberg55b97fe2016-01-28 05:22:45 -08003254 {
3255 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003256
kwiberg55b97fe2016-01-28 05:22:45 -08003257 if (_inputFilePlayerPtr == NULL) {
3258 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3259 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3260 " doesnt exist");
3261 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003262 }
3263
kwiberg55b97fe2016-01-28 05:22:45 -08003264 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(), fileSamples,
3265 mixingFrequency) == -1) {
3266 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3267 "Channel::MixOrReplaceAudioWithFile() file mixing "
3268 "failed");
3269 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 }
kwiberg55b97fe2016-01-28 05:22:45 -08003271 if (fileSamples == 0) {
3272 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3273 "Channel::MixOrReplaceAudioWithFile() file is ended");
3274 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003275 }
kwiberg55b97fe2016-01-28 05:22:45 -08003276 }
3277
3278 assert(_audioFrame.samples_per_channel_ == fileSamples);
3279
3280 if (_mixFileWithMicrophone) {
3281 // Currently file stream is always mono.
3282 // TODO(xians): Change the code when FilePlayer supports real stereo.
3283 MixWithSat(_audioFrame.data_, _audioFrame.num_channels_, fileBuffer.get(),
3284 1, fileSamples);
3285 } else {
3286 // Replace ACM audio with file.
3287 // Currently file stream is always mono.
3288 // TODO(xians): Change the code when FilePlayer supports real stereo.
3289 _audioFrame.UpdateFrame(
3290 _channelId, 0xFFFFFFFF, fileBuffer.get(), fileSamples, mixingFrequency,
3291 AudioFrame::kNormalSpeech, AudioFrame::kVadUnknown, 1);
3292 }
3293 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003294}
3295
kwiberg55b97fe2016-01-28 05:22:45 -08003296int32_t Channel::MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency) {
3297 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003298
kwibergb7f89d62016-02-17 10:04:18 -08003299 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[960]);
kwiberg55b97fe2016-01-28 05:22:45 -08003300 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003301
kwiberg55b97fe2016-01-28 05:22:45 -08003302 {
3303 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003304
kwiberg55b97fe2016-01-28 05:22:45 -08003305 if (_outputFilePlayerPtr == NULL) {
3306 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3307 "Channel::MixAudioWithFile() file mixing failed");
3308 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003309 }
3310
kwiberg55b97fe2016-01-28 05:22:45 -08003311 // We should get the frequency we ask for.
3312 if (_outputFilePlayerPtr->Get10msAudioFromFile(
3313 fileBuffer.get(), fileSamples, mixingFrequency) == -1) {
3314 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3315 "Channel::MixAudioWithFile() file mixing failed");
3316 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003317 }
kwiberg55b97fe2016-01-28 05:22:45 -08003318 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003319
kwiberg55b97fe2016-01-28 05:22:45 -08003320 if (audioFrame.samples_per_channel_ == fileSamples) {
3321 // Currently file stream is always mono.
3322 // TODO(xians): Change the code when FilePlayer supports real stereo.
3323 MixWithSat(audioFrame.data_, audioFrame.num_channels_, fileBuffer.get(), 1,
3324 fileSamples);
3325 } else {
3326 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3327 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS
3328 ") != "
3329 "fileSamples(%" PRIuS ")",
3330 audioFrame.samples_per_channel_, fileSamples);
3331 return -1;
3332 }
3333
3334 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003335}
3336
deadbeef74375882015-08-13 12:09:10 -07003337void Channel::UpdatePlayoutTimestamp(bool rtcp) {
henrik.lundin96bd5022016-04-06 04:13:56 -07003338 jitter_buffer_playout_timestamp_ = audio_coding_->PlayoutTimestamp();
deadbeef74375882015-08-13 12:09:10 -07003339
henrik.lundin96bd5022016-04-06 04:13:56 -07003340 if (!jitter_buffer_playout_timestamp_) {
3341 // This can happen if this channel has not received any RTP packets. In
3342 // this case, NetEq is not capable of computing a playout timestamp.
deadbeef74375882015-08-13 12:09:10 -07003343 return;
3344 }
3345
3346 uint16_t delay_ms = 0;
3347 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
kwiberg55b97fe2016-01-28 05:22:45 -08003348 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
deadbeef74375882015-08-13 12:09:10 -07003349 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3350 " delay from the ADM");
3351 _engineStatisticsPtr->SetLastError(
3352 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3353 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3354 return;
3355 }
3356
henrik.lundin96bd5022016-04-06 04:13:56 -07003357 RTC_DCHECK(jitter_buffer_playout_timestamp_);
3358 uint32_t playout_timestamp = *jitter_buffer_playout_timestamp_;
deadbeef74375882015-08-13 12:09:10 -07003359
3360 // Remove the playout delay.
henrik.lundin96bd5022016-04-06 04:13:56 -07003361 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
deadbeef74375882015-08-13 12:09:10 -07003362
kwiberg55b97fe2016-01-28 05:22:45 -08003363 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
deadbeef74375882015-08-13 12:09:10 -07003364 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
henrik.lundin96bd5022016-04-06 04:13:56 -07003365 playout_timestamp);
deadbeef74375882015-08-13 12:09:10 -07003366
3367 {
tommi31fc21f2016-01-21 10:37:37 -08003368 rtc::CritScope lock(&video_sync_lock_);
deadbeef74375882015-08-13 12:09:10 -07003369 if (rtcp) {
henrik.lundin96bd5022016-04-06 04:13:56 -07003370 playout_timestamp_rtcp_ = playout_timestamp;
deadbeef74375882015-08-13 12:09:10 -07003371 } else {
henrik.lundin96bd5022016-04-06 04:13:56 -07003372 playout_timestamp_rtp_ = playout_timestamp;
deadbeef74375882015-08-13 12:09:10 -07003373 }
3374 playout_delay_ms_ = delay_ms;
3375 }
3376}
3377
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003378// Called for incoming RTP packets after successful RTP header parsing.
3379void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3380 uint16_t sequence_number) {
kwiberg55b97fe2016-01-28 05:22:45 -08003381 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003382 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3383 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003384
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003385 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003386 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003387
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003388 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
henrik.lundin96bd5022016-04-06 04:13:56 -07003389 // every incoming packet. May be empty if no valid playout timestamp is
3390 // available.
3391 // If |rtp_timestamp| is newer than |jitter_buffer_playout_timestamp_|, the
3392 // resulting difference is positive and will be used. When the inverse is
3393 // true (can happen when a network glitch causes a packet to arrive late,
3394 // and during long comfort noise periods with clock drift), or when
3395 // |jitter_buffer_playout_timestamp_| has no value, the difference is not
3396 // changed from the initial 0.
3397 uint32_t timestamp_diff_ms = 0;
3398 if (jitter_buffer_playout_timestamp_ &&
3399 IsNewerTimestamp(rtp_timestamp, *jitter_buffer_playout_timestamp_)) {
3400 timestamp_diff_ms = (rtp_timestamp - *jitter_buffer_playout_timestamp_) /
3401 (rtp_receive_frequency / 1000);
3402 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3403 // Diff is too large; set it to zero instead.
3404 timestamp_diff_ms = 0;
3405 }
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003406 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003407
kwiberg55b97fe2016-01-28 05:22:45 -08003408 uint16_t packet_delay_ms =
3409 (rtp_timestamp - _previousTimestamp) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003410
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003411 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003412
kwiberg55b97fe2016-01-28 05:22:45 -08003413 if (timestamp_diff_ms == 0)
3414 return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003415
deadbeef74375882015-08-13 12:09:10 -07003416 {
tommi31fc21f2016-01-21 10:37:37 -08003417 rtc::CritScope lock(&video_sync_lock_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003418
deadbeef74375882015-08-13 12:09:10 -07003419 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3420 _recPacketDelayMs = packet_delay_ms;
3421 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003422
deadbeef74375882015-08-13 12:09:10 -07003423 if (_average_jitter_buffer_delay_us == 0) {
3424 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3425 return;
3426 }
3427
3428 // Filter average delay value using exponential filter (alpha is
3429 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3430 // risk of rounding error) and compensate for it in GetDelayEstimate()
3431 // later.
kwiberg55b97fe2016-01-28 05:22:45 -08003432 _average_jitter_buffer_delay_us =
3433 (_average_jitter_buffer_delay_us * 7 + 1000 * timestamp_diff_ms + 500) /
3434 8;
deadbeef74375882015-08-13 12:09:10 -07003435 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003436}
3437
kwiberg55b97fe2016-01-28 05:22:45 -08003438void Channel::RegisterReceiveCodecsToRTPModule() {
3439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3440 "Channel::RegisterReceiveCodecsToRTPModule()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003441
kwiberg55b97fe2016-01-28 05:22:45 -08003442 CodecInst codec;
3443 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003444
kwiberg55b97fe2016-01-28 05:22:45 -08003445 for (int idx = 0; idx < nSupportedCodecs; idx++) {
3446 // Open up the RTP/RTCP receiver for all supported codecs
3447 if ((audio_coding_->Codec(idx, &codec) == -1) ||
3448 (rtp_receiver_->RegisterReceivePayload(
3449 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3450 (codec.rate < 0) ? 0 : codec.rate) == -1)) {
3451 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3452 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3453 " to register %s (%d/%d/%" PRIuS
3454 "/%d) to RTP/RTCP "
3455 "receiver",
3456 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3457 codec.rate);
3458 } else {
3459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3460 "Channel::RegisterReceiveCodecsToRTPModule() %s "
3461 "(%d/%d/%" PRIuS
3462 "/%d) has been added to the RTP/RTCP "
3463 "receiver",
3464 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3465 codec.rate);
niklase@google.com470e71d2011-07-07 08:21:25 +00003466 }
kwiberg55b97fe2016-01-28 05:22:45 -08003467 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003468}
3469
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003470// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003471int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003472 CodecInst codec;
3473 bool found_red = false;
3474
3475 // Get default RED settings from the ACM database
3476 const int num_codecs = AudioCodingModule::NumberOfCodecs();
3477 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003478 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003479 if (!STR_CASE_CMP(codec.plname, "RED")) {
3480 found_red = true;
3481 break;
3482 }
3483 }
3484
3485 if (!found_red) {
3486 _engineStatisticsPtr->SetLastError(
3487 VE_CODEC_ERROR, kTraceError,
3488 "SetRedPayloadType() RED is not supported");
3489 return -1;
3490 }
3491
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00003492 codec.pltype = red_payload_type;
kwibergc8d071e2016-04-06 12:22:38 -07003493 if (!codec_manager_.RegisterEncoder(codec) ||
3494 !codec_manager_.MakeEncoder(&rent_a_codec_, audio_coding_.get())) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003495 _engineStatisticsPtr->SetLastError(
3496 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3497 "SetRedPayloadType() RED registration in ACM module failed");
3498 return -1;
3499 }
3500
3501 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
3502 _engineStatisticsPtr->SetLastError(
3503 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3504 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
3505 return -1;
3506 }
3507 return 0;
3508}
3509
kwiberg55b97fe2016-01-28 05:22:45 -08003510int Channel::SetSendRtpHeaderExtension(bool enable,
3511 RTPExtensionType type,
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003512 unsigned char id) {
3513 int error = 0;
3514 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
3515 if (enable) {
3516 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
3517 }
3518 return error;
3519}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003520
wu@webrtc.org94454b72014-06-05 20:34:08 +00003521int32_t Channel::GetPlayoutFrequency() {
3522 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
3523 CodecInst current_recive_codec;
3524 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
3525 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3526 // Even though the actual sampling rate for G.722 audio is
3527 // 16,000 Hz, the RTP clock rate for the G722 payload format is
3528 // 8,000 Hz because that value was erroneously assigned in
3529 // RFC 1890 and must remain unchanged for backward compatibility.
3530 playout_frequency = 8000;
3531 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3532 // We are resampling Opus internally to 32,000 Hz until all our
3533 // DSP routines can operate at 48,000 Hz, but the RTP clock
3534 // rate for the Opus payload format is standardized to 48,000 Hz,
3535 // because that is the maximum supported decoding sampling rate.
3536 playout_frequency = 48000;
3537 }
3538 }
3539 return playout_frequency;
3540}
3541
Minyue2013aec2015-05-13 14:14:42 +02003542int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07003543 RtcpMode method = _rtpRtcpModule->RTCP();
3544 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003545 return 0;
3546 }
3547 std::vector<RTCPReportBlock> report_blocks;
3548 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02003549
3550 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003551 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02003552 if (allow_associate_channel) {
tommi31fc21f2016-01-21 10:37:37 -08003553 rtc::CritScope lock(&assoc_send_channel_lock_);
Minyue2013aec2015-05-13 14:14:42 +02003554 Channel* channel = associate_send_channel_.channel();
3555 // Tries to get RTT from an associated channel. This is important for
3556 // receive-only channels.
3557 if (channel) {
3558 // To prevent infinite recursion and deadlock, calling GetRTT of
3559 // associate channel should always use "false" for argument:
3560 // |allow_associate_channel|.
3561 rtt = channel->GetRTT(false);
3562 }
3563 }
3564 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003565 }
3566
3567 uint32_t remoteSSRC = rtp_receiver_->SSRC();
3568 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
3569 for (; it != report_blocks.end(); ++it) {
3570 if (it->remoteSSRC == remoteSSRC)
3571 break;
3572 }
3573 if (it == report_blocks.end()) {
3574 // We have not received packets with SSRC matching the report blocks.
3575 // To calculate RTT we try with the SSRC of the first report block.
3576 // This is very important for send-only channels where we don't know
3577 // the SSRC of the other end.
3578 remoteSSRC = report_blocks[0].remoteSSRC;
3579 }
Minyue2013aec2015-05-13 14:14:42 +02003580
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003581 int64_t avg_rtt = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08003582 int64_t max_rtt = 0;
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003583 int64_t min_rtt = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08003584 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt) !=
3585 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003586 return 0;
3587 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003588 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003589}
3590
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00003591} // namespace voe
3592} // namespace webrtc