blob: 11af45edc837fb8f94eb9da43edf9ba2be86dde9 [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"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000024#include "webrtc/modules/audio_device/include/audio_device.h"
25#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010026#include "webrtc/modules/include/module_common_types.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010027#include "webrtc/modules/pacing/packet_router.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010028#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
29#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
30#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000031#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010032#include "webrtc/modules/utility/include/audio_frame_operations.h"
33#include "webrtc/modules/utility/include/process_thread.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010034#include "webrtc/system_wrappers/include/trace.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000035#include "webrtc/voice_engine/include/voe_base.h"
36#include "webrtc/voice_engine/include/voe_external_media.h"
37#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
38#include "webrtc/voice_engine/output_mixer.h"
39#include "webrtc/voice_engine/statistics.h"
40#include "webrtc/voice_engine/transmit_mixer.h"
41#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000042
43#if defined(_WIN32)
44#include <Qos.h>
45#endif
46
andrew@webrtc.org50419b02012-11-14 19:07:54 +000047namespace webrtc {
48namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000049
Stefan Holmerb86d4e42015-12-07 10:26:18 +010050class TransportFeedbackProxy : public TransportFeedbackObserver {
51 public:
52 TransportFeedbackProxy() : feedback_observer_(nullptr) {
53 pacer_thread_.DetachFromThread();
54 network_thread_.DetachFromThread();
55 }
56
57 void SetTransportFeedbackObserver(
58 TransportFeedbackObserver* feedback_observer) {
59 RTC_DCHECK(thread_checker_.CalledOnValidThread());
60 rtc::CritScope lock(&crit_);
61 feedback_observer_ = feedback_observer;
62 }
63
64 // Implements TransportFeedbackObserver.
65 void AddPacket(uint16_t sequence_number,
66 size_t length,
67 bool was_paced) override {
68 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
69 rtc::CritScope lock(&crit_);
70 if (feedback_observer_)
71 feedback_observer_->AddPacket(sequence_number, length, was_paced);
72 }
73 void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
74 RTC_DCHECK(network_thread_.CalledOnValidThread());
75 rtc::CritScope lock(&crit_);
76 if (feedback_observer_)
77 feedback_observer_->OnTransportFeedback(feedback);
78 }
79
80 private:
81 rtc::CriticalSection crit_;
82 rtc::ThreadChecker thread_checker_;
83 rtc::ThreadChecker pacer_thread_;
84 rtc::ThreadChecker network_thread_;
85 TransportFeedbackObserver* feedback_observer_ GUARDED_BY(&crit_);
86};
87
88class TransportSequenceNumberProxy : public TransportSequenceNumberAllocator {
89 public:
90 TransportSequenceNumberProxy() : seq_num_allocator_(nullptr) {
91 pacer_thread_.DetachFromThread();
92 }
93
94 void SetSequenceNumberAllocator(
95 TransportSequenceNumberAllocator* seq_num_allocator) {
96 RTC_DCHECK(thread_checker_.CalledOnValidThread());
97 rtc::CritScope lock(&crit_);
98 seq_num_allocator_ = seq_num_allocator;
99 }
100
101 // Implements TransportSequenceNumberAllocator.
102 uint16_t AllocateSequenceNumber() override {
103 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
104 rtc::CritScope lock(&crit_);
105 if (!seq_num_allocator_)
106 return 0;
107 return seq_num_allocator_->AllocateSequenceNumber();
108 }
109
110 private:
111 rtc::CriticalSection crit_;
112 rtc::ThreadChecker thread_checker_;
113 rtc::ThreadChecker pacer_thread_;
114 TransportSequenceNumberAllocator* seq_num_allocator_ GUARDED_BY(&crit_);
115};
116
117class RtpPacketSenderProxy : public RtpPacketSender {
118 public:
kwiberg55b97fe2016-01-28 05:22:45 -0800119 RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {}
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100120
121 void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
122 RTC_DCHECK(thread_checker_.CalledOnValidThread());
123 rtc::CritScope lock(&crit_);
124 rtp_packet_sender_ = rtp_packet_sender;
125 }
126
127 // Implements RtpPacketSender.
128 void InsertPacket(Priority priority,
129 uint32_t ssrc,
130 uint16_t sequence_number,
131 int64_t capture_time_ms,
132 size_t bytes,
133 bool retransmission) override {
134 rtc::CritScope lock(&crit_);
135 if (rtp_packet_sender_) {
136 rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
137 capture_time_ms, bytes, retransmission);
138 }
139 }
140
141 private:
142 rtc::ThreadChecker thread_checker_;
143 rtc::CriticalSection crit_;
144 RtpPacketSender* rtp_packet_sender_ GUARDED_BY(&crit_);
145};
146
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000147// Extend the default RTCP statistics struct with max_jitter, defined as the
148// maximum jitter value seen in an RTCP report block.
149struct ChannelStatistics : public RtcpStatistics {
150 ChannelStatistics() : rtcp(), max_jitter(0) {}
151
152 RtcpStatistics rtcp;
153 uint32_t max_jitter;
154};
155
156// Statistics callback, called at each generation of a new RTCP report block.
157class StatisticsProxy : public RtcpStatisticsCallback {
158 public:
tommi31fc21f2016-01-21 10:37:37 -0800159 StatisticsProxy(uint32_t ssrc) : ssrc_(ssrc) {}
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000160 virtual ~StatisticsProxy() {}
161
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000162 void StatisticsUpdated(const RtcpStatistics& statistics,
163 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000164 if (ssrc != ssrc_)
165 return;
166
tommi31fc21f2016-01-21 10:37:37 -0800167 rtc::CritScope cs(&stats_lock_);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000168 stats_.rtcp = statistics;
169 if (statistics.jitter > stats_.max_jitter) {
170 stats_.max_jitter = statistics.jitter;
171 }
172 }
173
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000174 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000175
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000176 ChannelStatistics GetStats() {
tommi31fc21f2016-01-21 10:37:37 -0800177 rtc::CritScope cs(&stats_lock_);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000178 return stats_;
179 }
180
181 private:
182 // StatisticsUpdated calls are triggered from threads in the RTP module,
183 // while GetStats calls can be triggered from the public voice engine API,
184 // hence synchronization is needed.
tommi31fc21f2016-01-21 10:37:37 -0800185 rtc::CriticalSection stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000186 const uint32_t ssrc_;
187 ChannelStatistics stats_;
188};
189
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000190class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000191 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000192 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
193 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000194
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000195 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
196 // Not used for Voice Engine.
197 }
198
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000199 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
200 int64_t rtt,
201 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000202 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
203 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
204 // report for VoiceEngine?
205 if (report_blocks.empty())
206 return;
207
208 int fraction_lost_aggregate = 0;
209 int total_number_of_packets = 0;
210
211 // If receiving multiple report blocks, calculate the weighted average based
212 // on the number of packets a report refers to.
213 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
214 block_it != report_blocks.end(); ++block_it) {
215 // Find the previous extended high sequence number for this remote SSRC,
216 // to calculate the number of RTP packets this report refers to. Ignore if
217 // we haven't seen this SSRC before.
218 std::map<uint32_t, uint32_t>::iterator seq_num_it =
219 extended_max_sequence_number_.find(block_it->sourceSSRC);
220 int number_of_packets = 0;
221 if (seq_num_it != extended_max_sequence_number_.end()) {
222 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
223 }
224 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
225 total_number_of_packets += number_of_packets;
226
227 extended_max_sequence_number_[block_it->sourceSSRC] =
228 block_it->extendedHighSeqNum;
229 }
230 int weighted_fraction_lost = 0;
231 if (total_number_of_packets > 0) {
kwiberg55b97fe2016-01-28 05:22:45 -0800232 weighted_fraction_lost =
233 (fraction_lost_aggregate + total_number_of_packets / 2) /
234 total_number_of_packets;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000235 }
236 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000237 }
238
239 private:
240 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000241 // Maps remote side ssrc to extended highest sequence number received.
242 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000243};
244
kwiberg55b97fe2016-01-28 05:22:45 -0800245int32_t Channel::SendData(FrameType frameType,
246 uint8_t payloadType,
247 uint32_t timeStamp,
248 const uint8_t* payloadData,
249 size_t payloadSize,
250 const RTPFragmentationHeader* fragmentation) {
251 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
252 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
253 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
254 frameType, payloadType, timeStamp, payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000255
kwiberg55b97fe2016-01-28 05:22:45 -0800256 if (_includeAudioLevelIndication) {
257 // Store current audio level in the RTP/RTCP module.
258 // The level will be used in combination with voice-activity state
259 // (frameType) to add an RTP header extension
260 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
261 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000262
kwiberg55b97fe2016-01-28 05:22:45 -0800263 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
264 // packetization.
265 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
266 if (_rtpRtcpModule->SendOutgoingData(
267 (FrameType&)frameType, payloadType, timeStamp,
268 // Leaving the time when this frame was
269 // received from the capture device as
270 // undefined for voice for now.
271 -1, payloadData, payloadSize, fragmentation) == -1) {
272 _engineStatisticsPtr->SetLastError(
273 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
274 "Channel::SendData() failed to send data to RTP/RTCP module");
275 return -1;
276 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000277
kwiberg55b97fe2016-01-28 05:22:45 -0800278 _lastLocalTimeStamp = timeStamp;
279 _lastPayloadType = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000280
kwiberg55b97fe2016-01-28 05:22:45 -0800281 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000282}
283
kwiberg55b97fe2016-01-28 05:22:45 -0800284int32_t Channel::InFrameType(FrameType frame_type) {
285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
286 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000287
kwiberg55b97fe2016-01-28 05:22:45 -0800288 rtc::CritScope cs(&_callbackCritSect);
289 _sendFrameType = (frame_type == kAudioFrameSpeech);
290 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000291}
292
kwiberg55b97fe2016-01-28 05:22:45 -0800293int32_t Channel::OnRxVadDetected(int vadDecision) {
294 rtc::CritScope cs(&_callbackCritSect);
295 if (_rxVadObserverPtr) {
296 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
297 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
kwiberg55b97fe2016-01-28 05:22:45 -0800299 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000300}
301
stefan1d8a5062015-10-02 03:39:33 -0700302bool Channel::SendRtp(const uint8_t* data,
303 size_t len,
304 const PacketOptions& options) {
kwiberg55b97fe2016-01-28 05:22:45 -0800305 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
306 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307
kwiberg55b97fe2016-01-28 05:22:45 -0800308 rtc::CritScope cs(&_callbackCritSect);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000309
kwiberg55b97fe2016-01-28 05:22:45 -0800310 if (_transportPtr == NULL) {
311 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
312 "Channel::SendPacket() failed to send RTP packet due to"
313 " invalid transport object");
314 return false;
315 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000316
kwiberg55b97fe2016-01-28 05:22:45 -0800317 uint8_t* bufferToSendPtr = (uint8_t*)data;
318 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000319
kwiberg55b97fe2016-01-28 05:22:45 -0800320 if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
321 std::string transport_name =
322 _externalTransport ? "external transport" : "WebRtc sockets";
323 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
324 "Channel::SendPacket() RTP transmission using %s failed",
325 transport_name.c_str());
326 return false;
327 }
328 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000329}
330
kwiberg55b97fe2016-01-28 05:22:45 -0800331bool Channel::SendRtcp(const uint8_t* data, size_t len) {
332 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
333 "Channel::SendRtcp(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000334
kwiberg55b97fe2016-01-28 05:22:45 -0800335 rtc::CritScope cs(&_callbackCritSect);
336 if (_transportPtr == NULL) {
337 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
338 "Channel::SendRtcp() failed to send RTCP packet"
339 " due to invalid transport object");
340 return false;
341 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000342
kwiberg55b97fe2016-01-28 05:22:45 -0800343 uint8_t* bufferToSendPtr = (uint8_t*)data;
344 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000345
kwiberg55b97fe2016-01-28 05:22:45 -0800346 int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength);
347 if (n < 0) {
348 std::string transport_name =
349 _externalTransport ? "external transport" : "WebRtc sockets";
350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
351 "Channel::SendRtcp() transmission using %s failed",
352 transport_name.c_str());
353 return false;
354 }
355 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000356}
357
Peter Boströmac547a62015-09-17 23:03:57 +0200358void Channel::OnPlayTelephoneEvent(uint8_t event,
359 uint16_t lengthMs,
360 uint8_t volume) {
kwiberg55b97fe2016-01-28 05:22:45 -0800361 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
362 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
363 " volume=%u)",
364 event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365
kwiberg55b97fe2016-01-28 05:22:45 -0800366 if (!_playOutbandDtmfEvent || (event > 15)) {
367 // Ignore callback since feedback is disabled or event is not a
368 // Dtmf tone event.
369 return;
370 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
kwiberg55b97fe2016-01-28 05:22:45 -0800372 assert(_outputMixerPtr != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000373
kwiberg55b97fe2016-01-28 05:22:45 -0800374 // Start playing out the Dtmf tone (if playout is enabled).
375 // Reduce length of tone with 80ms to the reduce risk of echo.
376 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000377}
378
kwiberg55b97fe2016-01-28 05:22:45 -0800379void Channel::OnIncomingSSRCChanged(uint32_t ssrc) {
380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
381 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382
kwiberg55b97fe2016-01-28 05:22:45 -0800383 // Update ssrc so that NTP for AV sync can be updated.
384 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000385}
386
Peter Boströmac547a62015-09-17 23:03:57 +0200387void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
388 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
389 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
390 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000391}
392
Peter Boströmac547a62015-09-17 23:03:57 +0200393int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000394 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000395 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000396 int frequency,
Peter Kasting69558702016-01-12 16:26:35 -0800397 size_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200398 uint32_t rate) {
kwiberg55b97fe2016-01-28 05:22:45 -0800399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
400 "Channel::OnInitializeDecoder(payloadType=%d, "
401 "payloadName=%s, frequency=%u, channels=%" PRIuS ", rate=%u)",
402 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000403
kwiberg55b97fe2016-01-28 05:22:45 -0800404 CodecInst receiveCodec = {0};
405 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000406
kwiberg55b97fe2016-01-28 05:22:45 -0800407 receiveCodec.pltype = payloadType;
408 receiveCodec.plfreq = frequency;
409 receiveCodec.channels = channels;
410 receiveCodec.rate = rate;
411 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000412
kwiberg55b97fe2016-01-28 05:22:45 -0800413 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
414 receiveCodec.pacsize = dummyCodec.pacsize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
kwiberg55b97fe2016-01-28 05:22:45 -0800416 // Register the new codec to the ACM
417 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1) {
418 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
419 "Channel::OnInitializeDecoder() invalid codec ("
420 "pt=%d, name=%s) received - 1",
421 payloadType, payloadName);
422 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
423 return -1;
424 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000425
kwiberg55b97fe2016-01-28 05:22:45 -0800426 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000427}
428
kwiberg55b97fe2016-01-28 05:22:45 -0800429int32_t Channel::OnReceivedPayloadData(const uint8_t* payloadData,
430 size_t payloadSize,
431 const WebRtcRTPHeader* rtpHeader) {
432 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
433 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS
434 ","
435 " payloadType=%u, audioChannel=%" PRIuS ")",
436 payloadSize, rtpHeader->header.payloadType,
437 rtpHeader->type.Audio.channel);
niklase@google.com470e71d2011-07-07 08:21:25 +0000438
kwiberg55b97fe2016-01-28 05:22:45 -0800439 if (!channel_state_.Get().playing) {
440 // Avoid inserting into NetEQ when we are not playing. Count the
441 // packet as discarded.
442 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
443 "received packet is discarded since playing is not"
444 " activated");
445 _numberOfDiscardedPackets++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -0800447 }
448
449 // Push the incoming payload (parsed and ready for decoding) into the ACM
450 if (audio_coding_->IncomingPacket(payloadData, payloadSize, *rtpHeader) !=
451 0) {
452 _engineStatisticsPtr->SetLastError(
453 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
454 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
455 return -1;
456 }
457
458 // Update the packet delay.
459 UpdatePacketDelay(rtpHeader->header.timestamp,
460 rtpHeader->header.sequenceNumber);
461
462 int64_t round_trip_time = 0;
463 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time, NULL, NULL,
464 NULL);
465
466 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(round_trip_time);
467 if (!nack_list.empty()) {
468 // Can't use nack_list.data() since it's not supported by all
469 // compilers.
470 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
471 }
472 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000473}
474
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000475bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000476 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000477 RTPHeader header;
478 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
479 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
480 "IncomingPacket invalid RTP header");
481 return false;
482 }
483 header.payload_type_frequency =
484 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
485 if (header.payload_type_frequency < 0)
486 return false;
487 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
488}
489
kwiberg55b97fe2016-01-28 05:22:45 -0800490int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame) {
491 if (event_log_) {
492 unsigned int ssrc;
493 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
494 event_log_->LogAudioPlayout(ssrc);
495 }
496 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
497 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_, audioFrame) ==
498 -1) {
499 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
500 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
501 // In all likelihood, the audio in this frame is garbage. We return an
502 // error so that the audio mixer module doesn't add it to the mix. As
503 // a result, it won't be played out and the actions skipped here are
504 // irrelevant.
505 return -1;
506 }
507
508 if (_RxVadDetection) {
509 UpdateRxVadDetection(*audioFrame);
510 }
511
512 // Convert module ID to internal VoE channel ID
513 audioFrame->id_ = VoEChannelId(audioFrame->id_);
514 // Store speech type for dead-or-alive detection
515 _outputSpeechType = audioFrame->speech_type_;
516
517 ChannelState::State state = channel_state_.Get();
518
519 if (state.rx_apm_is_enabled) {
520 int err = rx_audioproc_->ProcessStream(audioFrame);
521 if (err) {
522 LOG(LS_ERROR) << "ProcessStream() error: " << err;
523 assert(false);
Ivo Creusenae856f22015-09-17 16:30:16 +0200524 }
kwiberg55b97fe2016-01-28 05:22:45 -0800525 }
526
527 {
528 // Pass the audio buffers to an optional sink callback, before applying
529 // scaling/panning, as that applies to the mix operation.
530 // External recipients of the audio (e.g. via AudioTrack), will do their
531 // own mixing/dynamic processing.
532 rtc::CritScope cs(&_callbackCritSect);
533 if (audio_sink_) {
534 AudioSinkInterface::Data data(
535 &audioFrame->data_[0], audioFrame->samples_per_channel_,
536 audioFrame->sample_rate_hz_, audioFrame->num_channels_,
537 audioFrame->timestamp_);
538 audio_sink_->OnData(data);
539 }
540 }
541
542 float output_gain = 1.0f;
543 float left_pan = 1.0f;
544 float right_pan = 1.0f;
545 {
546 rtc::CritScope cs(&volume_settings_critsect_);
547 output_gain = _outputGain;
548 left_pan = _panLeft;
549 right_pan = _panRight;
550 }
551
552 // Output volume scaling
553 if (output_gain < 0.99f || output_gain > 1.01f) {
554 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
555 }
556
557 // Scale left and/or right channel(s) if stereo and master balance is
558 // active
559
560 if (left_pan != 1.0f || right_pan != 1.0f) {
561 if (audioFrame->num_channels_ == 1) {
562 // Emulate stereo mode since panning is active.
563 // The mono signal is copied to both left and right channels here.
564 AudioFrameOperations::MonoToStereo(audioFrame);
565 }
566 // For true stereo mode (when we are receiving a stereo signal), no
567 // action is needed.
568
569 // Do the panning operation (the audio frame contains stereo at this
570 // stage)
571 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
572 }
573
574 // Mix decoded PCM output with file if file mixing is enabled
575 if (state.output_file_playing) {
576 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
577 }
578
579 // External media
580 if (_outputExternalMedia) {
581 rtc::CritScope cs(&_callbackCritSect);
582 const bool isStereo = (audioFrame->num_channels_ == 2);
583 if (_outputExternalMediaCallbackPtr) {
584 _outputExternalMediaCallbackPtr->Process(
585 _channelId, kPlaybackPerChannel, (int16_t*)audioFrame->data_,
586 audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
587 isStereo);
588 }
589 }
590
591 // Record playout if enabled
592 {
593 rtc::CritScope cs(&_fileCritSect);
594
595 if (_outputFileRecording && _outputFileRecorderPtr) {
596 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
597 }
598 }
599
600 // Measure audio level (0-9)
601 _outputAudioLevel.ComputeLevel(*audioFrame);
602
603 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
604 // The first frame with a valid rtp timestamp.
605 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
606 }
607
608 if (capture_start_rtp_time_stamp_ >= 0) {
609 // audioFrame.timestamp_ should be valid from now on.
610
611 // Compute elapsed time.
612 int64_t unwrap_timestamp =
613 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
614 audioFrame->elapsed_time_ms_ =
615 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
616 (GetPlayoutFrequency() / 1000);
617
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
kwiberg55b97fe2016-01-28 05:22:45 -0800619 rtc::CritScope lock(&ts_stats_lock_);
620 // Compute ntp time.
621 audioFrame->ntp_time_ms_ =
622 ntp_estimator_.Estimate(audioFrame->timestamp_);
623 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
624 if (audioFrame->ntp_time_ms_ > 0) {
625 // Compute |capture_start_ntp_time_ms_| so that
626 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
627 capture_start_ntp_time_ms_ =
628 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000629 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 }
kwiberg55b97fe2016-01-28 05:22:45 -0800631 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000632
kwiberg55b97fe2016-01-28 05:22:45 -0800633 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000634}
635
kwiberg55b97fe2016-01-28 05:22:45 -0800636int32_t Channel::NeededFrequency(int32_t id) const {
637 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
638 "Channel::NeededFrequency(id=%d)", id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
kwiberg55b97fe2016-01-28 05:22:45 -0800640 int highestNeeded = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000641
kwiberg55b97fe2016-01-28 05:22:45 -0800642 // Determine highest needed receive frequency
643 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000644
kwiberg55b97fe2016-01-28 05:22:45 -0800645 // Return the bigger of playout and receive frequency in the ACM.
646 if (audio_coding_->PlayoutFrequency() > receiveFrequency) {
647 highestNeeded = audio_coding_->PlayoutFrequency();
648 } else {
649 highestNeeded = receiveFrequency;
650 }
651
652 // Special case, if we're playing a file on the playout side
653 // we take that frequency into consideration as well
654 // This is not needed on sending side, since the codec will
655 // limit the spectrum anyway.
656 if (channel_state_.Get().output_file_playing) {
657 rtc::CritScope cs(&_fileCritSect);
658 if (_outputFilePlayerPtr) {
659 if (_outputFilePlayerPtr->Frequency() > highestNeeded) {
660 highestNeeded = _outputFilePlayerPtr->Frequency();
661 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 }
kwiberg55b97fe2016-01-28 05:22:45 -0800663 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
kwiberg55b97fe2016-01-28 05:22:45 -0800665 return (highestNeeded);
niklase@google.com470e71d2011-07-07 08:21:25 +0000666}
667
ivocb04965c2015-09-09 00:09:43 -0700668int32_t Channel::CreateChannel(Channel*& channel,
669 int32_t channelId,
670 uint32_t instanceId,
671 RtcEventLog* const event_log,
672 const Config& config) {
kwiberg55b97fe2016-01-28 05:22:45 -0800673 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, channelId),
674 "Channel::CreateChannel(channelId=%d, instanceId=%d)", channelId,
675 instanceId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000676
kwiberg55b97fe2016-01-28 05:22:45 -0800677 channel = new Channel(channelId, instanceId, event_log, config);
678 if (channel == NULL) {
679 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId, channelId),
680 "Channel::CreateChannel() unable to allocate memory for"
681 " channel");
682 return -1;
683 }
684 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000685}
686
kwiberg55b97fe2016-01-28 05:22:45 -0800687void Channel::PlayNotification(int32_t id, uint32_t durationMs) {
688 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
689 "Channel::PlayNotification(id=%d, durationMs=%d)", id,
690 durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000691
kwiberg55b97fe2016-01-28 05:22:45 -0800692 // Not implement yet
niklase@google.com470e71d2011-07-07 08:21:25 +0000693}
694
kwiberg55b97fe2016-01-28 05:22:45 -0800695void Channel::RecordNotification(int32_t id, uint32_t durationMs) {
696 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
697 "Channel::RecordNotification(id=%d, durationMs=%d)", id,
698 durationMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000699
kwiberg55b97fe2016-01-28 05:22:45 -0800700 // Not implement yet
niklase@google.com470e71d2011-07-07 08:21:25 +0000701}
702
kwiberg55b97fe2016-01-28 05:22:45 -0800703void Channel::PlayFileEnded(int32_t id) {
704 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
705 "Channel::PlayFileEnded(id=%d)", id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000706
kwiberg55b97fe2016-01-28 05:22:45 -0800707 if (id == _inputFilePlayerId) {
708 channel_state_.SetInputFilePlaying(false);
709 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
710 "Channel::PlayFileEnded() => input file player module is"
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 " shutdown");
kwiberg55b97fe2016-01-28 05:22:45 -0800712 } else if (id == _outputFilePlayerId) {
713 channel_state_.SetOutputFilePlaying(false);
714 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
715 "Channel::PlayFileEnded() => output file player module is"
716 " shutdown");
717 }
718}
719
720void Channel::RecordFileEnded(int32_t id) {
721 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
722 "Channel::RecordFileEnded(id=%d)", id);
723
724 assert(id == _outputFileRecorderId);
725
726 rtc::CritScope cs(&_fileCritSect);
727
728 _outputFileRecording = false;
729 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
730 "Channel::RecordFileEnded() => output file recorder module is"
731 " shutdown");
niklase@google.com470e71d2011-07-07 08:21:25 +0000732}
733
pbos@webrtc.org92135212013-05-14 08:31:39 +0000734Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000735 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700736 RtcEventLog* const event_log,
737 const Config& config)
tommi31fc21f2016-01-21 10:37:37 -0800738 : _instanceId(instanceId),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100739 _channelId(channelId),
740 event_log_(event_log),
741 rtp_header_parser_(RtpHeaderParser::Create()),
742 rtp_payload_registry_(
743 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
744 rtp_receive_statistics_(
745 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
746 rtp_receiver_(
747 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
748 this,
749 this,
750 this,
751 rtp_payload_registry_.get())),
752 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
753 _outputAudioLevel(),
754 _externalTransport(false),
755 _inputFilePlayerPtr(NULL),
756 _outputFilePlayerPtr(NULL),
757 _outputFileRecorderPtr(NULL),
758 // Avoid conflict with other channels by adding 1024 - 1026,
759 // won't use as much as 1024 channels.
760 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
761 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
762 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
763 _outputFileRecording(false),
764 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
765 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
766 _outputExternalMedia(false),
767 _inputExternalMediaCallbackPtr(NULL),
768 _outputExternalMediaCallbackPtr(NULL),
769 _timeStamp(0), // This is just an offset, RTP module will add it's own
770 // random offset
771 _sendTelephoneEventPayloadType(106),
772 ntp_estimator_(Clock::GetRealTimeClock()),
773 jitter_buffer_playout_timestamp_(0),
774 playout_timestamp_rtp_(0),
775 playout_timestamp_rtcp_(0),
776 playout_delay_ms_(0),
777 _numberOfDiscardedPackets(0),
778 send_sequence_number_(0),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100779 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
780 capture_start_rtp_time_stamp_(-1),
781 capture_start_ntp_time_ms_(-1),
782 _engineStatisticsPtr(NULL),
783 _outputMixerPtr(NULL),
784 _transmitMixerPtr(NULL),
785 _moduleProcessThreadPtr(NULL),
786 _audioDeviceModulePtr(NULL),
787 _voiceEngineObserverPtr(NULL),
788 _callbackCritSectPtr(NULL),
789 _transportPtr(NULL),
790 _rxVadObserverPtr(NULL),
791 _oldVadDecision(-1),
792 _sendFrameType(0),
793 _externalMixing(false),
794 _mixFileWithMicrophone(false),
795 _mute(false),
796 _panLeft(1.0f),
797 _panRight(1.0f),
798 _outputGain(1.0f),
799 _playOutbandDtmfEvent(false),
800 _playInbandDtmfEvent(false),
801 _lastLocalTimeStamp(0),
802 _lastPayloadType(0),
803 _includeAudioLevelIndication(false),
804 _outputSpeechType(AudioFrame::kNormalSpeech),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100805 _average_jitter_buffer_delay_us(0),
806 _previousTimestamp(0),
807 _recPacketDelayMs(20),
808 _RxVadDetection(false),
809 _rxAgcIsEnabled(false),
810 _rxNsIsEnabled(false),
811 restored_packet_in_use_(false),
812 rtcp_observer_(new VoERtcpObserver(this)),
813 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100814 associate_send_channel_(ChannelOwner(nullptr)),
815 pacing_enabled_(config.Get<VoicePacing>().enabled),
stefanbba9dec2016-02-01 04:39:55 -0800816 feedback_observer_proxy_(new TransportFeedbackProxy()),
817 seq_num_allocator_proxy_(new TransportSequenceNumberProxy()),
818 rtp_packet_sender_proxy_(new RtpPacketSenderProxy()) {
kwiberg55b97fe2016-01-28 05:22:45 -0800819 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
820 "Channel::Channel() - ctor");
821 AudioCodingModule::Config acm_config;
822 acm_config.id = VoEModuleId(instanceId, channelId);
823 if (config.Get<NetEqCapacityConfig>().enabled) {
824 // Clamping the buffer capacity at 20 packets. While going lower will
825 // probably work, it makes little sense.
826 acm_config.neteq_config.max_packets_in_buffer =
827 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
828 }
829 acm_config.neteq_config.enable_fast_accelerate =
830 config.Get<NetEqFastAccelerate>().enabled;
831 audio_coding_.reset(AudioCodingModule::Create(acm_config));
Henrik Lundin64dad832015-05-11 12:44:23 +0200832
kwiberg55b97fe2016-01-28 05:22:45 -0800833 _inbandDtmfQueue.ResetDtmf();
834 _inbandDtmfGenerator.Init();
835 _outputAudioLevel.Clear();
niklase@google.com470e71d2011-07-07 08:21:25 +0000836
kwiberg55b97fe2016-01-28 05:22:45 -0800837 RtpRtcp::Configuration configuration;
838 configuration.audio = true;
839 configuration.outgoing_transport = this;
840 configuration.audio_messages = this;
841 configuration.receive_statistics = rtp_receive_statistics_.get();
842 configuration.bandwidth_callback = rtcp_observer_.get();
stefanbba9dec2016-02-01 04:39:55 -0800843 if (pacing_enabled_) {
844 configuration.paced_sender = rtp_packet_sender_proxy_.get();
845 configuration.transport_sequence_number_allocator =
846 seq_num_allocator_proxy_.get();
847 configuration.transport_feedback_callback = feedback_observer_proxy_.get();
848 }
kwiberg55b97fe2016-01-28 05:22:45 -0800849 configuration.event_log = event_log;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000850
kwiberg55b97fe2016-01-28 05:22:45 -0800851 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
Peter Boström3dd5d1d2016-02-25 16:56:48 +0100852 _rtpRtcpModule->SetSendingMediaStatus(false);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000853
kwiberg55b97fe2016-01-28 05:22:45 -0800854 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
855 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
856 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000857
kwiberg55b97fe2016-01-28 05:22:45 -0800858 Config audioproc_config;
859 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
860 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000861}
862
kwiberg55b97fe2016-01-28 05:22:45 -0800863Channel::~Channel() {
864 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
865 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
866 "Channel::~Channel() - dtor");
niklase@google.com470e71d2011-07-07 08:21:25 +0000867
kwiberg55b97fe2016-01-28 05:22:45 -0800868 if (_outputExternalMedia) {
869 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
870 }
871 if (channel_state_.Get().input_external_media) {
872 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
873 }
874 StopSend();
875 StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000876
kwiberg55b97fe2016-01-28 05:22:45 -0800877 {
878 rtc::CritScope cs(&_fileCritSect);
879 if (_inputFilePlayerPtr) {
880 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
881 _inputFilePlayerPtr->StopPlayingFile();
882 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
883 _inputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 }
kwiberg55b97fe2016-01-28 05:22:45 -0800885 if (_outputFilePlayerPtr) {
886 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
887 _outputFilePlayerPtr->StopPlayingFile();
888 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
889 _outputFilePlayerPtr = NULL;
890 }
891 if (_outputFileRecorderPtr) {
892 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
893 _outputFileRecorderPtr->StopRecording();
894 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
895 _outputFileRecorderPtr = NULL;
896 }
897 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000898
kwiberg55b97fe2016-01-28 05:22:45 -0800899 // The order to safely shutdown modules in a channel is:
900 // 1. De-register callbacks in modules
901 // 2. De-register modules in process thread
902 // 3. Destroy modules
903 if (audio_coding_->RegisterTransportCallback(NULL) == -1) {
904 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
905 "~Channel() failed to de-register transport callback"
906 " (Audio coding module)");
907 }
908 if (audio_coding_->RegisterVADCallback(NULL) == -1) {
909 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
910 "~Channel() failed to de-register VAD callback"
911 " (Audio coding module)");
912 }
913 // De-register modules in process thread
914 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000915
kwiberg55b97fe2016-01-28 05:22:45 -0800916 // End of modules shutdown
niklase@google.com470e71d2011-07-07 08:21:25 +0000917}
918
kwiberg55b97fe2016-01-28 05:22:45 -0800919int32_t Channel::Init() {
920 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
921 "Channel::Init()");
niklase@google.com470e71d2011-07-07 08:21:25 +0000922
kwiberg55b97fe2016-01-28 05:22:45 -0800923 channel_state_.Reset();
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000924
kwiberg55b97fe2016-01-28 05:22:45 -0800925 // --- Initial sanity
niklase@google.com470e71d2011-07-07 08:21:25 +0000926
kwiberg55b97fe2016-01-28 05:22:45 -0800927 if ((_engineStatisticsPtr == NULL) || (_moduleProcessThreadPtr == NULL)) {
928 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
929 "Channel::Init() must call SetEngineInformation() first");
930 return -1;
931 }
932
933 // --- Add modules to process thread (for periodic schedulation)
934
935 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
936
937 // --- ACM initialization
938
939 if (audio_coding_->InitializeReceiver() == -1) {
940 _engineStatisticsPtr->SetLastError(
941 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
942 "Channel::Init() unable to initialize the ACM - 1");
943 return -1;
944 }
945
946 // --- RTP/RTCP module initialization
947
948 // Ensure that RTCP is enabled by default for the created channel.
949 // Note that, the module will keep generating RTCP until it is explicitly
950 // disabled by the user.
951 // After StopListen (when no sockets exists), RTCP packets will no longer
952 // be transmitted since the Transport object will then be invalid.
953 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
954 // RTCP is enabled by default.
955 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
956 // --- Register all permanent callbacks
957 const bool fail = (audio_coding_->RegisterTransportCallback(this) == -1) ||
958 (audio_coding_->RegisterVADCallback(this) == -1);
959
960 if (fail) {
961 _engineStatisticsPtr->SetLastError(
962 VE_CANNOT_INIT_CHANNEL, kTraceError,
963 "Channel::Init() callbacks not registered");
964 return -1;
965 }
966
967 // --- Register all supported codecs to the receiving side of the
968 // RTP/RTCP module
969
970 CodecInst codec;
971 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
972
973 for (int idx = 0; idx < nSupportedCodecs; idx++) {
974 // Open up the RTP/RTCP receiver for all supported codecs
975 if ((audio_coding_->Codec(idx, &codec) == -1) ||
976 (rtp_receiver_->RegisterReceivePayload(
977 codec.plname, codec.pltype, codec.plfreq, codec.channels,
978 (codec.rate < 0) ? 0 : codec.rate) == -1)) {
979 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
980 "Channel::Init() unable to register %s "
981 "(%d/%d/%" PRIuS "/%d) to RTP/RTCP receiver",
982 codec.plname, codec.pltype, codec.plfreq, codec.channels,
983 codec.rate);
984 } else {
985 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
986 "Channel::Init() %s (%d/%d/%" PRIuS
987 "/%d) has been "
988 "added to the RTP/RTCP receiver",
989 codec.plname, codec.pltype, codec.plfreq, codec.channels,
990 codec.rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 }
992
kwiberg55b97fe2016-01-28 05:22:45 -0800993 // Ensure that PCMU is used as default codec on the sending side
994 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1)) {
995 SetSendCodec(codec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 }
997
kwiberg55b97fe2016-01-28 05:22:45 -0800998 // Register default PT for outband 'telephone-event'
999 if (!STR_CASE_CMP(codec.plname, "telephone-event")) {
1000 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
1001 (audio_coding_->RegisterReceiveCodec(codec) == -1)) {
1002 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1003 "Channel::Init() failed to register outband "
1004 "'telephone-event' (%d/%d) correctly",
1005 codec.pltype, codec.plfreq);
1006 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 }
1008
kwiberg55b97fe2016-01-28 05:22:45 -08001009 if (!STR_CASE_CMP(codec.plname, "CN")) {
1010 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1011 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
1012 (_rtpRtcpModule->RegisterSendPayload(codec) == -1)) {
1013 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1014 "Channel::Init() failed to register CN (%d/%d) "
1015 "correctly - 1",
1016 codec.pltype, codec.plfreq);
1017 }
1018 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001019#ifdef WEBRTC_CODEC_RED
kwiberg55b97fe2016-01-28 05:22:45 -08001020 // Register RED to the receiving side of the ACM.
1021 // We will not receive an OnInitializeDecoder() callback for RED.
1022 if (!STR_CASE_CMP(codec.plname, "RED")) {
1023 if (audio_coding_->RegisterReceiveCodec(codec) == -1) {
1024 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
1025 "Channel::Init() failed to register RED (%d/%d) "
1026 "correctly",
1027 codec.pltype, codec.plfreq);
1028 }
1029 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001030#endif
kwiberg55b97fe2016-01-28 05:22:45 -08001031 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001032
kwiberg55b97fe2016-01-28 05:22:45 -08001033 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1034 LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
1035 return -1;
1036 }
1037 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1038 LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
1039 return -1;
1040 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001041
kwiberg55b97fe2016-01-28 05:22:45 -08001042 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001043}
1044
kwiberg55b97fe2016-01-28 05:22:45 -08001045int32_t Channel::SetEngineInformation(Statistics& engineStatistics,
1046 OutputMixer& outputMixer,
1047 voe::TransmitMixer& transmitMixer,
1048 ProcessThread& moduleProcessThread,
1049 AudioDeviceModule& audioDeviceModule,
1050 VoiceEngineObserver* voiceEngineObserver,
1051 rtc::CriticalSection* callbackCritSect) {
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1053 "Channel::SetEngineInformation()");
1054 _engineStatisticsPtr = &engineStatistics;
1055 _outputMixerPtr = &outputMixer;
1056 _transmitMixerPtr = &transmitMixer,
1057 _moduleProcessThreadPtr = &moduleProcessThread;
1058 _audioDeviceModulePtr = &audioDeviceModule;
1059 _voiceEngineObserverPtr = voiceEngineObserver;
1060 _callbackCritSectPtr = callbackCritSect;
1061 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001062}
1063
kwiberg55b97fe2016-01-28 05:22:45 -08001064int32_t Channel::UpdateLocalTimeStamp() {
1065 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
1066 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001067}
1068
kwibergb7f89d62016-02-17 10:04:18 -08001069void Channel::SetSink(std::unique_ptr<AudioSinkInterface> sink) {
tommi31fc21f2016-01-21 10:37:37 -08001070 rtc::CritScope cs(&_callbackCritSect);
deadbeef2d110be2016-01-13 12:00:26 -08001071 audio_sink_ = std::move(sink);
Tommif888bb52015-12-12 01:37:01 +01001072}
1073
kwiberg55b97fe2016-01-28 05:22:45 -08001074int32_t Channel::StartPlayout() {
1075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1076 "Channel::StartPlayout()");
1077 if (channel_state_.Get().playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001079 }
1080
1081 if (!_externalMixing) {
1082 // Add participant as candidates for mixing.
1083 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0) {
1084 _engineStatisticsPtr->SetLastError(
1085 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1086 "StartPlayout() failed to add participant to mixer");
1087 return -1;
1088 }
1089 }
1090
1091 channel_state_.SetPlaying(true);
1092 if (RegisterFilePlayingToMixer() != 0)
1093 return -1;
1094
1095 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001096}
1097
kwiberg55b97fe2016-01-28 05:22:45 -08001098int32_t Channel::StopPlayout() {
1099 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1100 "Channel::StopPlayout()");
1101 if (!channel_state_.Get().playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001102 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001103 }
1104
1105 if (!_externalMixing) {
1106 // Remove participant as candidates for mixing
1107 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0) {
1108 _engineStatisticsPtr->SetLastError(
1109 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1110 "StopPlayout() failed to remove participant from mixer");
1111 return -1;
1112 }
1113 }
1114
1115 channel_state_.SetPlaying(false);
1116 _outputAudioLevel.Clear();
1117
1118 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001119}
1120
kwiberg55b97fe2016-01-28 05:22:45 -08001121int32_t Channel::StartSend() {
1122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1123 "Channel::StartSend()");
1124 // Resume the previous sequence number which was reset by StopSend().
1125 // This needs to be done before |sending| is set to true.
1126 if (send_sequence_number_)
1127 SetInitSequenceNumber(send_sequence_number_);
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001128
kwiberg55b97fe2016-01-28 05:22:45 -08001129 if (channel_state_.Get().sending) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001131 }
1132 channel_state_.SetSending(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001133
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001134 _rtpRtcpModule->SetSendingMediaStatus(true);
kwiberg55b97fe2016-01-28 05:22:45 -08001135 if (_rtpRtcpModule->SetSendingStatus(true) != 0) {
1136 _engineStatisticsPtr->SetLastError(
1137 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1138 "StartSend() RTP/RTCP failed to start sending");
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001139 _rtpRtcpModule->SetSendingMediaStatus(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001140 rtc::CritScope cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001141 channel_state_.SetSending(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001142 return -1;
1143 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001144
kwiberg55b97fe2016-01-28 05:22:45 -08001145 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001146}
1147
kwiberg55b97fe2016-01-28 05:22:45 -08001148int32_t Channel::StopSend() {
1149 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1150 "Channel::StopSend()");
1151 if (!channel_state_.Get().sending) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001152 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001153 }
1154 channel_state_.SetSending(false);
1155
1156 // Store the sequence number to be able to pick up the same sequence for
1157 // the next StartSend(). This is needed for restarting device, otherwise
1158 // it might cause libSRTP to complain about packets being replayed.
1159 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1160 // CL is landed. See issue
1161 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1162 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1163
1164 // Reset sending SSRC and sequence number and triggers direct transmission
1165 // of RTCP BYE
1166 if (_rtpRtcpModule->SetSendingStatus(false) == -1) {
1167 _engineStatisticsPtr->SetLastError(
1168 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1169 "StartSend() RTP/RTCP failed to stop sending");
1170 }
Peter Boström3dd5d1d2016-02-25 16:56:48 +01001171 _rtpRtcpModule->SetSendingMediaStatus(false);
kwiberg55b97fe2016-01-28 05:22:45 -08001172
1173 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001174}
1175
kwiberg55b97fe2016-01-28 05:22:45 -08001176int32_t Channel::StartReceiving() {
1177 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1178 "Channel::StartReceiving()");
1179 if (channel_state_.Get().receiving) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001180 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001181 }
1182 channel_state_.SetReceiving(true);
1183 _numberOfDiscardedPackets = 0;
1184 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001185}
1186
kwiberg55b97fe2016-01-28 05:22:45 -08001187int32_t Channel::StopReceiving() {
1188 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1189 "Channel::StopReceiving()");
1190 if (!channel_state_.Get().receiving) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001192 }
1193
1194 channel_state_.SetReceiving(false);
1195 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001196}
1197
kwiberg55b97fe2016-01-28 05:22:45 -08001198int32_t Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
1199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1200 "Channel::RegisterVoiceEngineObserver()");
1201 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001202
kwiberg55b97fe2016-01-28 05:22:45 -08001203 if (_voiceEngineObserverPtr) {
1204 _engineStatisticsPtr->SetLastError(
1205 VE_INVALID_OPERATION, kTraceError,
1206 "RegisterVoiceEngineObserver() observer already enabled");
1207 return -1;
1208 }
1209 _voiceEngineObserverPtr = &observer;
1210 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001211}
1212
kwiberg55b97fe2016-01-28 05:22:45 -08001213int32_t Channel::DeRegisterVoiceEngineObserver() {
1214 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1215 "Channel::DeRegisterVoiceEngineObserver()");
1216 rtc::CritScope cs(&_callbackCritSect);
1217
1218 if (!_voiceEngineObserverPtr) {
1219 _engineStatisticsPtr->SetLastError(
1220 VE_INVALID_OPERATION, kTraceWarning,
1221 "DeRegisterVoiceEngineObserver() observer already disabled");
1222 return 0;
1223 }
1224 _voiceEngineObserverPtr = NULL;
1225 return 0;
1226}
1227
1228int32_t Channel::GetSendCodec(CodecInst& codec) {
kwiberg1fd4a4a2015-11-03 11:20:50 -08001229 auto send_codec = audio_coding_->SendCodec();
1230 if (send_codec) {
1231 codec = *send_codec;
1232 return 0;
1233 }
1234 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001235}
1236
kwiberg55b97fe2016-01-28 05:22:45 -08001237int32_t Channel::GetRecCodec(CodecInst& codec) {
1238 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001239}
1240
kwiberg55b97fe2016-01-28 05:22:45 -08001241int32_t Channel::SetSendCodec(const CodecInst& codec) {
1242 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1243 "Channel::SetSendCodec()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001244
kwiberg55b97fe2016-01-28 05:22:45 -08001245 if (audio_coding_->RegisterSendCodec(codec) != 0) {
1246 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1247 "SetSendCodec() failed to register codec to ACM");
1248 return -1;
1249 }
1250
1251 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1252 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1253 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1254 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1255 "SetSendCodec() failed to register codec to"
1256 " RTP/RTCP module");
1257 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 }
kwiberg55b97fe2016-01-28 05:22:45 -08001259 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001260
kwiberg55b97fe2016-01-28 05:22:45 -08001261 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0) {
1262 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
1263 "SetSendCodec() failed to set audio packet size");
1264 return -1;
1265 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001266
kwiberg55b97fe2016-01-28 05:22:45 -08001267 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001268}
1269
Ivo Creusenadf89b72015-04-29 16:03:33 +02001270void Channel::SetBitRate(int bitrate_bps) {
1271 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1272 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1273 audio_coding_->SetBitRate(bitrate_bps);
1274}
1275
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001276void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001277 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001278 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1279
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001280 // Normalizes rate to 0 - 100.
kwiberg55b97fe2016-01-28 05:22:45 -08001281 if (audio_coding_->SetPacketLossRate(100 * average_fraction_loss / 255) !=
1282 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001283 assert(false); // This should not happen.
1284 }
1285}
1286
kwiberg55b97fe2016-01-28 05:22:45 -08001287int32_t Channel::SetVADStatus(bool enableVAD,
1288 ACMVADMode mode,
1289 bool disableDTX) {
1290 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1291 "Channel::SetVADStatus(mode=%d)", mode);
1292 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
1293 // To disable VAD, DTX must be disabled too
1294 disableDTX = ((enableVAD == false) ? true : disableDTX);
1295 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0) {
1296 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1297 kTraceError,
1298 "SetVADStatus() failed to set VAD");
1299 return -1;
1300 }
1301 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001302}
1303
kwiberg55b97fe2016-01-28 05:22:45 -08001304int32_t Channel::GetVADStatus(bool& enabledVAD,
1305 ACMVADMode& mode,
1306 bool& disabledDTX) {
1307 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0) {
1308 _engineStatisticsPtr->SetLastError(
1309 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1310 "GetVADStatus() failed to get VAD status");
1311 return -1;
1312 }
1313 disabledDTX = !disabledDTX;
1314 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001315}
1316
kwiberg55b97fe2016-01-28 05:22:45 -08001317int32_t Channel::SetRecPayloadType(const CodecInst& codec) {
1318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1319 "Channel::SetRecPayloadType()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001320
kwiberg55b97fe2016-01-28 05:22:45 -08001321 if (channel_state_.Get().playing) {
1322 _engineStatisticsPtr->SetLastError(
1323 VE_ALREADY_PLAYING, kTraceError,
1324 "SetRecPayloadType() unable to set PT while playing");
1325 return -1;
1326 }
1327 if (channel_state_.Get().receiving) {
1328 _engineStatisticsPtr->SetLastError(
1329 VE_ALREADY_LISTENING, kTraceError,
1330 "SetRecPayloadType() unable to set PT while listening");
1331 return -1;
1332 }
1333
1334 if (codec.pltype == -1) {
1335 // De-register the selected codec (RTP/RTCP module and ACM)
1336
1337 int8_t pltype(-1);
1338 CodecInst rxCodec = codec;
1339
1340 // Get payload type for the given codec
1341 rtp_payload_registry_->ReceivePayloadType(
1342 rxCodec.plname, rxCodec.plfreq, rxCodec.channels,
1343 (rxCodec.rate < 0) ? 0 : rxCodec.rate, &pltype);
1344 rxCodec.pltype = pltype;
1345
1346 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0) {
1347 _engineStatisticsPtr->SetLastError(
1348 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1349 "SetRecPayloadType() RTP/RTCP-module deregistration "
1350 "failed");
1351 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 }
kwiberg55b97fe2016-01-28 05:22:45 -08001353 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0) {
1354 _engineStatisticsPtr->SetLastError(
1355 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1356 "SetRecPayloadType() ACM deregistration failed - 1");
1357 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001358 }
kwiberg55b97fe2016-01-28 05:22:45 -08001359 return 0;
1360 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001361
kwiberg55b97fe2016-01-28 05:22:45 -08001362 if (rtp_receiver_->RegisterReceivePayload(
1363 codec.plname, codec.pltype, codec.plfreq, codec.channels,
1364 (codec.rate < 0) ? 0 : codec.rate) != 0) {
1365 // First attempt to register failed => de-register and try again
1366 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001367 if (rtp_receiver_->RegisterReceivePayload(
kwiberg55b97fe2016-01-28 05:22:45 -08001368 codec.plname, codec.pltype, codec.plfreq, codec.channels,
1369 (codec.rate < 0) ? 0 : codec.rate) != 0) {
1370 _engineStatisticsPtr->SetLastError(
1371 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1372 "SetRecPayloadType() RTP/RTCP-module registration failed");
1373 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 }
kwiberg55b97fe2016-01-28 05:22:45 -08001375 }
1376 if (audio_coding_->RegisterReceiveCodec(codec) != 0) {
1377 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1378 if (audio_coding_->RegisterReceiveCodec(codec) != 0) {
1379 _engineStatisticsPtr->SetLastError(
1380 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1381 "SetRecPayloadType() ACM registration failed - 1");
1382 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 }
kwiberg55b97fe2016-01-28 05:22:45 -08001384 }
1385 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001386}
1387
kwiberg55b97fe2016-01-28 05:22:45 -08001388int32_t Channel::GetRecPayloadType(CodecInst& codec) {
1389 int8_t payloadType(-1);
1390 if (rtp_payload_registry_->ReceivePayloadType(
1391 codec.plname, codec.plfreq, codec.channels,
1392 (codec.rate < 0) ? 0 : codec.rate, &payloadType) != 0) {
1393 _engineStatisticsPtr->SetLastError(
1394 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1395 "GetRecPayloadType() failed to retrieve RX payload type");
1396 return -1;
1397 }
1398 codec.pltype = payloadType;
1399 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001400}
1401
kwiberg55b97fe2016-01-28 05:22:45 -08001402int32_t Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency) {
1403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1404 "Channel::SetSendCNPayloadType()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001405
kwiberg55b97fe2016-01-28 05:22:45 -08001406 CodecInst codec;
1407 int32_t samplingFreqHz(-1);
1408 const size_t kMono = 1;
1409 if (frequency == kFreq32000Hz)
1410 samplingFreqHz = 32000;
1411 else if (frequency == kFreq16000Hz)
1412 samplingFreqHz = 16000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001413
kwiberg55b97fe2016-01-28 05:22:45 -08001414 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1) {
1415 _engineStatisticsPtr->SetLastError(
1416 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1417 "SetSendCNPayloadType() failed to retrieve default CN codec "
1418 "settings");
1419 return -1;
1420 }
1421
1422 // Modify the payload type (must be set to dynamic range)
1423 codec.pltype = type;
1424
1425 if (audio_coding_->RegisterSendCodec(codec) != 0) {
1426 _engineStatisticsPtr->SetLastError(
1427 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1428 "SetSendCNPayloadType() failed to register CN to ACM");
1429 return -1;
1430 }
1431
1432 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1433 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1434 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
1435 _engineStatisticsPtr->SetLastError(
1436 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1437 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1438 "module");
1439 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 }
kwiberg55b97fe2016-01-28 05:22:45 -08001441 }
1442 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001443}
1444
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001445int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001447 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001448
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001449 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001450 _engineStatisticsPtr->SetLastError(
1451 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001452 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001453 return -1;
1454 }
1455 return 0;
1456}
1457
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001458int Channel::SetOpusDtx(bool enable_dtx) {
1459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1460 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001461 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001462 : audio_coding_->DisableOpusDtx();
1463 if (ret != 0) {
kwiberg55b97fe2016-01-28 05:22:45 -08001464 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1465 kTraceError, "SetOpusDtx() failed");
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001466 return -1;
1467 }
1468 return 0;
1469}
1470
kwiberg55b97fe2016-01-28 05:22:45 -08001471int32_t Channel::RegisterExternalTransport(Transport& transport) {
1472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 "Channel::RegisterExternalTransport()");
1474
kwiberg55b97fe2016-01-28 05:22:45 -08001475 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001476
kwiberg55b97fe2016-01-28 05:22:45 -08001477 if (_externalTransport) {
1478 _engineStatisticsPtr->SetLastError(
1479 VE_INVALID_OPERATION, kTraceError,
1480 "RegisterExternalTransport() external transport already enabled");
1481 return -1;
1482 }
1483 _externalTransport = true;
1484 _transportPtr = &transport;
1485 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001486}
1487
kwiberg55b97fe2016-01-28 05:22:45 -08001488int32_t Channel::DeRegisterExternalTransport() {
1489 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1490 "Channel::DeRegisterExternalTransport()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001491
kwiberg55b97fe2016-01-28 05:22:45 -08001492 rtc::CritScope cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001493
kwiberg55b97fe2016-01-28 05:22:45 -08001494 if (!_transportPtr) {
1495 _engineStatisticsPtr->SetLastError(
1496 VE_INVALID_OPERATION, kTraceWarning,
1497 "DeRegisterExternalTransport() external transport already "
1498 "disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001500 }
1501 _externalTransport = false;
1502 _transportPtr = NULL;
1503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1504 "DeRegisterExternalTransport() all transport is disabled");
1505 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001506}
1507
kwiberg55b97fe2016-01-28 05:22:45 -08001508int32_t Channel::ReceivedRTPPacket(const int8_t* data,
1509 size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001510 const PacketTime& packet_time) {
kwiberg55b97fe2016-01-28 05:22:45 -08001511 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001512 "Channel::ReceivedRTPPacket()");
1513
1514 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001515 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001516
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001517 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001518 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001519 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1520 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1521 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001522 return -1;
1523 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001524 header.payload_type_frequency =
1525 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001526 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001527 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001528 bool in_order = IsPacketInOrder(header);
kwiberg55b97fe2016-01-28 05:22:45 -08001529 rtp_receive_statistics_->IncomingPacket(
1530 header, length, IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001531 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001532
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001533 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001534}
1535
1536bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001537 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001538 const RTPHeader& header,
1539 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001540 if (rtp_payload_registry_->IsRtx(header)) {
1541 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001542 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001543 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001544 assert(packet_length >= header.headerLength);
1545 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001546 PayloadUnion payload_specific;
1547 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001548 &payload_specific)) {
1549 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001550 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001551 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1552 payload_specific, in_order);
1553}
1554
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001555bool Channel::HandleRtxPacket(const uint8_t* packet,
1556 size_t packet_length,
1557 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001558 if (!rtp_payload_registry_->IsRtx(header))
1559 return false;
1560
1561 // Remove the RTX header and parse the original RTP header.
1562 if (packet_length < header.headerLength)
1563 return false;
1564 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1565 return false;
1566 if (restored_packet_in_use_) {
1567 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1568 "Multiple RTX headers detected, dropping packet");
1569 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001570 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001571 if (!rtp_payload_registry_->RestoreOriginalPacket(
noahric65220a72015-10-14 11:29:49 -07001572 restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
1573 header)) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001574 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1575 "Incoming RTX packet: invalid RTP header");
1576 return false;
1577 }
1578 restored_packet_in_use_ = true;
noahric65220a72015-10-14 11:29:49 -07001579 bool ret = OnRecoveredPacket(restored_packet_, packet_length);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001580 restored_packet_in_use_ = false;
1581 return ret;
1582}
1583
1584bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1585 StreamStatistician* statistician =
1586 rtp_receive_statistics_->GetStatistician(header.ssrc);
1587 if (!statistician)
1588 return false;
1589 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001590}
1591
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001592bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1593 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001594 // Retransmissions are handled separately if RTX is enabled.
1595 if (rtp_payload_registry_->RtxEnabled())
1596 return false;
1597 StreamStatistician* statistician =
1598 rtp_receive_statistics_->GetStatistician(header.ssrc);
1599 if (!statistician)
1600 return false;
1601 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001602 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001603 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
kwiberg55b97fe2016-01-28 05:22:45 -08001604 return !in_order && statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001605}
1606
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001607int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
kwiberg55b97fe2016-01-28 05:22:45 -08001608 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001609 "Channel::ReceivedRTCPPacket()");
1610 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001611 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001612
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001613 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001614 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001615 _engineStatisticsPtr->SetLastError(
1616 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1617 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1618 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001619
Minyue2013aec2015-05-13 14:14:42 +02001620 int64_t rtt = GetRTT(true);
1621 if (rtt == 0) {
1622 // Waiting for valid RTT.
1623 return 0;
1624 }
1625 uint32_t ntp_secs = 0;
1626 uint32_t ntp_frac = 0;
1627 uint32_t rtp_timestamp = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001628 if (0 !=
1629 _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1630 &rtp_timestamp)) {
Minyue2013aec2015-05-13 14:14:42 +02001631 // Waiting for RTCP.
1632 return 0;
1633 }
1634
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001635 {
tommi31fc21f2016-01-21 10:37:37 -08001636 rtc::CritScope lock(&ts_stats_lock_);
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001637 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001638 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001639 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001640}
1641
niklase@google.com470e71d2011-07-07 08:21:25 +00001642int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001643 bool loop,
1644 FileFormats format,
1645 int startPosition,
1646 float volumeScaling,
1647 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001648 const CodecInst* codecInst) {
1649 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1650 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1651 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1652 "stopPosition=%d)",
1653 fileName, loop, format, volumeScaling, startPosition,
1654 stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001655
kwiberg55b97fe2016-01-28 05:22:45 -08001656 if (channel_state_.Get().output_file_playing) {
1657 _engineStatisticsPtr->SetLastError(
1658 VE_ALREADY_PLAYING, kTraceError,
1659 "StartPlayingFileLocally() is already playing");
1660 return -1;
1661 }
1662
1663 {
1664 rtc::CritScope cs(&_fileCritSect);
1665
1666 if (_outputFilePlayerPtr) {
1667 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1668 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1669 _outputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 }
1671
kwiberg55b97fe2016-01-28 05:22:45 -08001672 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1673 _outputFilePlayerId, (const FileFormats)format);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001674
kwiberg55b97fe2016-01-28 05:22:45 -08001675 if (_outputFilePlayerPtr == NULL) {
1676 _engineStatisticsPtr->SetLastError(
1677 VE_INVALID_ARGUMENT, kTraceError,
1678 "StartPlayingFileLocally() filePlayer format is not correct");
1679 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001680 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001681
kwiberg55b97fe2016-01-28 05:22:45 -08001682 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001683
kwiberg55b97fe2016-01-28 05:22:45 -08001684 if (_outputFilePlayerPtr->StartPlayingFile(
1685 fileName, loop, startPosition, volumeScaling, notificationTime,
1686 stopPosition, (const CodecInst*)codecInst) != 0) {
1687 _engineStatisticsPtr->SetLastError(
1688 VE_BAD_FILE, kTraceError,
1689 "StartPlayingFile() failed to start file playout");
1690 _outputFilePlayerPtr->StopPlayingFile();
1691 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1692 _outputFilePlayerPtr = NULL;
1693 return -1;
1694 }
1695 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1696 channel_state_.SetOutputFilePlaying(true);
1697 }
1698
1699 if (RegisterFilePlayingToMixer() != 0)
1700 return -1;
1701
1702 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001703}
1704
1705int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001706 FileFormats format,
1707 int startPosition,
1708 float volumeScaling,
1709 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001710 const CodecInst* codecInst) {
1711 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1712 "Channel::StartPlayingFileLocally(format=%d,"
1713 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1714 format, volumeScaling, startPosition, stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001715
kwiberg55b97fe2016-01-28 05:22:45 -08001716 if (stream == NULL) {
1717 _engineStatisticsPtr->SetLastError(
1718 VE_BAD_FILE, kTraceError,
1719 "StartPlayingFileLocally() NULL as input stream");
1720 return -1;
1721 }
1722
1723 if (channel_state_.Get().output_file_playing) {
1724 _engineStatisticsPtr->SetLastError(
1725 VE_ALREADY_PLAYING, kTraceError,
1726 "StartPlayingFileLocally() is already playing");
1727 return -1;
1728 }
1729
1730 {
1731 rtc::CritScope cs(&_fileCritSect);
1732
1733 // Destroy the old instance
1734 if (_outputFilePlayerPtr) {
1735 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1736 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1737 _outputFilePlayerPtr = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +00001738 }
1739
kwiberg55b97fe2016-01-28 05:22:45 -08001740 // Create the instance
1741 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1742 _outputFilePlayerId, (const FileFormats)format);
niklase@google.com470e71d2011-07-07 08:21:25 +00001743
kwiberg55b97fe2016-01-28 05:22:45 -08001744 if (_outputFilePlayerPtr == NULL) {
1745 _engineStatisticsPtr->SetLastError(
1746 VE_INVALID_ARGUMENT, kTraceError,
1747 "StartPlayingFileLocally() filePlayer format isnot correct");
1748 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001749 }
1750
kwiberg55b97fe2016-01-28 05:22:45 -08001751 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001752
kwiberg55b97fe2016-01-28 05:22:45 -08001753 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1754 volumeScaling, notificationTime,
1755 stopPosition, codecInst) != 0) {
1756 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1757 "StartPlayingFile() failed to "
1758 "start file playout");
1759 _outputFilePlayerPtr->StopPlayingFile();
1760 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1761 _outputFilePlayerPtr = NULL;
1762 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 }
kwiberg55b97fe2016-01-28 05:22:45 -08001764 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
1765 channel_state_.SetOutputFilePlaying(true);
1766 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001767
kwiberg55b97fe2016-01-28 05:22:45 -08001768 if (RegisterFilePlayingToMixer() != 0)
1769 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001770
kwiberg55b97fe2016-01-28 05:22:45 -08001771 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001772}
1773
kwiberg55b97fe2016-01-28 05:22:45 -08001774int Channel::StopPlayingFileLocally() {
1775 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1776 "Channel::StopPlayingFileLocally()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001777
kwiberg55b97fe2016-01-28 05:22:45 -08001778 if (!channel_state_.Get().output_file_playing) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001779 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001780 }
1781
1782 {
1783 rtc::CritScope cs(&_fileCritSect);
1784
1785 if (_outputFilePlayerPtr->StopPlayingFile() != 0) {
1786 _engineStatisticsPtr->SetLastError(
1787 VE_STOP_RECORDING_FAILED, kTraceError,
1788 "StopPlayingFile() could not stop playing");
1789 return -1;
1790 }
1791 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1792 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1793 _outputFilePlayerPtr = NULL;
1794 channel_state_.SetOutputFilePlaying(false);
1795 }
1796 // _fileCritSect cannot be taken while calling
1797 // SetAnonymousMixibilityStatus. Refer to comments in
1798 // StartPlayingFileLocally(const char* ...) for more details.
1799 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0) {
1800 _engineStatisticsPtr->SetLastError(
1801 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1802 "StopPlayingFile() failed to stop participant from playing as"
1803 "file in the mixer");
1804 return -1;
1805 }
1806
1807 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001808}
1809
kwiberg55b97fe2016-01-28 05:22:45 -08001810int Channel::IsPlayingFileLocally() const {
1811 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001812}
1813
kwiberg55b97fe2016-01-28 05:22:45 -08001814int Channel::RegisterFilePlayingToMixer() {
1815 // Return success for not registering for file playing to mixer if:
1816 // 1. playing file before playout is started on that channel.
1817 // 2. starting playout without file playing on that channel.
1818 if (!channel_state_.Get().playing ||
1819 !channel_state_.Get().output_file_playing) {
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001820 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001821 }
1822
1823 // |_fileCritSect| cannot be taken while calling
1824 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1825 // frames can be pulled by the mixer. Since the frames are generated from
1826 // the file, _fileCritSect will be taken. This would result in a deadlock.
1827 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0) {
1828 channel_state_.SetOutputFilePlaying(false);
1829 rtc::CritScope cs(&_fileCritSect);
1830 _engineStatisticsPtr->SetLastError(
1831 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1832 "StartPlayingFile() failed to add participant as file to mixer");
1833 _outputFilePlayerPtr->StopPlayingFile();
1834 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1835 _outputFilePlayerPtr = NULL;
1836 return -1;
1837 }
1838
1839 return 0;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001840}
1841
niklase@google.com470e71d2011-07-07 08:21:25 +00001842int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001843 bool loop,
1844 FileFormats format,
1845 int startPosition,
1846 float volumeScaling,
1847 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001848 const CodecInst* codecInst) {
1849 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1850 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1851 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1852 "stopPosition=%d)",
1853 fileName, loop, format, volumeScaling, startPosition,
1854 stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001855
kwiberg55b97fe2016-01-28 05:22:45 -08001856 rtc::CritScope cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001857
kwiberg55b97fe2016-01-28 05:22:45 -08001858 if (channel_state_.Get().input_file_playing) {
1859 _engineStatisticsPtr->SetLastError(
1860 VE_ALREADY_PLAYING, kTraceWarning,
1861 "StartPlayingFileAsMicrophone() filePlayer is playing");
niklase@google.com470e71d2011-07-07 08:21:25 +00001862 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001863 }
1864
1865 // Destroy the old instance
1866 if (_inputFilePlayerPtr) {
1867 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1868 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1869 _inputFilePlayerPtr = NULL;
1870 }
1871
1872 // Create the instance
1873 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
1874 (const FileFormats)format);
1875
1876 if (_inputFilePlayerPtr == NULL) {
1877 _engineStatisticsPtr->SetLastError(
1878 VE_INVALID_ARGUMENT, kTraceError,
1879 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
1880 return -1;
1881 }
1882
1883 const uint32_t notificationTime(0);
1884
1885 if (_inputFilePlayerPtr->StartPlayingFile(
1886 fileName, loop, startPosition, volumeScaling, notificationTime,
1887 stopPosition, (const CodecInst*)codecInst) != 0) {
1888 _engineStatisticsPtr->SetLastError(
1889 VE_BAD_FILE, kTraceError,
1890 "StartPlayingFile() failed to start file playout");
1891 _inputFilePlayerPtr->StopPlayingFile();
1892 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1893 _inputFilePlayerPtr = NULL;
1894 return -1;
1895 }
1896 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
1897 channel_state_.SetInputFilePlaying(true);
1898
1899 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001900}
1901
1902int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001903 FileFormats format,
1904 int startPosition,
1905 float volumeScaling,
1906 int stopPosition,
kwiberg55b97fe2016-01-28 05:22:45 -08001907 const CodecInst* codecInst) {
1908 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1909 "Channel::StartPlayingFileAsMicrophone(format=%d, "
1910 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1911 format, volumeScaling, startPosition, stopPosition);
niklase@google.com470e71d2011-07-07 08:21:25 +00001912
kwiberg55b97fe2016-01-28 05:22:45 -08001913 if (stream == NULL) {
1914 _engineStatisticsPtr->SetLastError(
1915 VE_BAD_FILE, kTraceError,
1916 "StartPlayingFileAsMicrophone NULL as input stream");
1917 return -1;
1918 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001919
kwiberg55b97fe2016-01-28 05:22:45 -08001920 rtc::CritScope cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001921
kwiberg55b97fe2016-01-28 05:22:45 -08001922 if (channel_state_.Get().input_file_playing) {
1923 _engineStatisticsPtr->SetLastError(
1924 VE_ALREADY_PLAYING, kTraceWarning,
1925 "StartPlayingFileAsMicrophone() is playing");
niklase@google.com470e71d2011-07-07 08:21:25 +00001926 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08001927 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001928
kwiberg55b97fe2016-01-28 05:22:45 -08001929 // Destroy the old instance
1930 if (_inputFilePlayerPtr) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001931 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1932 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1933 _inputFilePlayerPtr = NULL;
kwiberg55b97fe2016-01-28 05:22:45 -08001934 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001935
kwiberg55b97fe2016-01-28 05:22:45 -08001936 // Create the instance
1937 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(_inputFilePlayerId,
1938 (const FileFormats)format);
1939
1940 if (_inputFilePlayerPtr == NULL) {
1941 _engineStatisticsPtr->SetLastError(
1942 VE_INVALID_ARGUMENT, kTraceError,
1943 "StartPlayingInputFile() filePlayer format isnot correct");
1944 return -1;
1945 }
1946
1947 const uint32_t notificationTime(0);
1948
1949 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1950 volumeScaling, notificationTime,
1951 stopPosition, codecInst) != 0) {
1952 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1953 "StartPlayingFile() failed to start "
1954 "file playout");
1955 _inputFilePlayerPtr->StopPlayingFile();
1956 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1957 _inputFilePlayerPtr = NULL;
1958 return -1;
1959 }
1960
1961 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
1962 channel_state_.SetInputFilePlaying(true);
1963
1964 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001965}
1966
kwiberg55b97fe2016-01-28 05:22:45 -08001967int Channel::StopPlayingFileAsMicrophone() {
1968 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1969 "Channel::StopPlayingFileAsMicrophone()");
1970
1971 rtc::CritScope cs(&_fileCritSect);
1972
1973 if (!channel_state_.Get().input_file_playing) {
1974 return 0;
1975 }
1976
1977 if (_inputFilePlayerPtr->StopPlayingFile() != 0) {
1978 _engineStatisticsPtr->SetLastError(
1979 VE_STOP_RECORDING_FAILED, kTraceError,
1980 "StopPlayingFile() could not stop playing");
1981 return -1;
1982 }
1983 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1984 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1985 _inputFilePlayerPtr = NULL;
1986 channel_state_.SetInputFilePlaying(false);
1987
1988 return 0;
1989}
1990
1991int Channel::IsPlayingFileAsMicrophone() const {
1992 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001993}
1994
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00001995int Channel::StartRecordingPlayout(const char* fileName,
kwiberg55b97fe2016-01-28 05:22:45 -08001996 const CodecInst* codecInst) {
1997 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1998 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
niklase@google.com470e71d2011-07-07 08:21:25 +00001999
kwiberg55b97fe2016-01-28 05:22:45 -08002000 if (_outputFileRecording) {
2001 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
2002 "StartRecordingPlayout() is already recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00002003 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002004 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002005
kwiberg55b97fe2016-01-28 05:22:45 -08002006 FileFormats format;
2007 const uint32_t notificationTime(0); // Not supported in VoE
2008 CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
niklase@google.com470e71d2011-07-07 08:21:25 +00002009
kwiberg55b97fe2016-01-28 05:22:45 -08002010 if ((codecInst != NULL) &&
2011 ((codecInst->channels < 1) || (codecInst->channels > 2))) {
2012 _engineStatisticsPtr->SetLastError(
2013 VE_BAD_ARGUMENT, kTraceError,
2014 "StartRecordingPlayout() invalid compression");
2015 return (-1);
2016 }
2017 if (codecInst == NULL) {
2018 format = kFileFormatPcm16kHzFile;
2019 codecInst = &dummyCodec;
2020 } else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
2021 (STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
2022 (STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
2023 format = kFileFormatWavFile;
2024 } else {
2025 format = kFileFormatCompressedFile;
2026 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002027
kwiberg55b97fe2016-01-28 05:22:45 -08002028 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002029
kwiberg55b97fe2016-01-28 05:22:45 -08002030 // Destroy the old instance
2031 if (_outputFileRecorderPtr) {
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2033 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2034 _outputFileRecorderPtr = NULL;
kwiberg55b97fe2016-01-28 05:22:45 -08002035 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002036
kwiberg55b97fe2016-01-28 05:22:45 -08002037 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2038 _outputFileRecorderId, (const FileFormats)format);
2039 if (_outputFileRecorderPtr == NULL) {
2040 _engineStatisticsPtr->SetLastError(
2041 VE_INVALID_ARGUMENT, kTraceError,
2042 "StartRecordingPlayout() fileRecorder format isnot correct");
2043 return -1;
2044 }
2045
2046 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2047 fileName, (const CodecInst&)*codecInst, notificationTime) != 0) {
2048 _engineStatisticsPtr->SetLastError(
2049 VE_BAD_FILE, kTraceError,
2050 "StartRecordingAudioFile() failed to start file recording");
2051 _outputFileRecorderPtr->StopRecording();
2052 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2053 _outputFileRecorderPtr = NULL;
2054 return -1;
2055 }
2056 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2057 _outputFileRecording = true;
2058
2059 return 0;
2060}
2061
2062int Channel::StartRecordingPlayout(OutStream* stream,
2063 const CodecInst* codecInst) {
2064 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2065 "Channel::StartRecordingPlayout()");
2066
2067 if (_outputFileRecording) {
2068 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
2069 "StartRecordingPlayout() is already recording");
niklase@google.com470e71d2011-07-07 08:21:25 +00002070 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002071 }
2072
2073 FileFormats format;
2074 const uint32_t notificationTime(0); // Not supported in VoE
2075 CodecInst dummyCodec = {100, "L16", 16000, 320, 1, 320000};
2076
2077 if (codecInst != NULL && codecInst->channels != 1) {
2078 _engineStatisticsPtr->SetLastError(
2079 VE_BAD_ARGUMENT, kTraceError,
2080 "StartRecordingPlayout() invalid compression");
2081 return (-1);
2082 }
2083 if (codecInst == NULL) {
2084 format = kFileFormatPcm16kHzFile;
2085 codecInst = &dummyCodec;
2086 } else if ((STR_CASE_CMP(codecInst->plname, "L16") == 0) ||
2087 (STR_CASE_CMP(codecInst->plname, "PCMU") == 0) ||
2088 (STR_CASE_CMP(codecInst->plname, "PCMA") == 0)) {
2089 format = kFileFormatWavFile;
2090 } else {
2091 format = kFileFormatCompressedFile;
2092 }
2093
2094 rtc::CritScope cs(&_fileCritSect);
2095
2096 // Destroy the old instance
2097 if (_outputFileRecorderPtr) {
2098 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2099 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2100 _outputFileRecorderPtr = NULL;
2101 }
2102
2103 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2104 _outputFileRecorderId, (const FileFormats)format);
2105 if (_outputFileRecorderPtr == NULL) {
2106 _engineStatisticsPtr->SetLastError(
2107 VE_INVALID_ARGUMENT, kTraceError,
2108 "StartRecordingPlayout() fileRecorder format isnot correct");
2109 return -1;
2110 }
2111
2112 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2113 notificationTime) != 0) {
2114 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2115 "StartRecordingPlayout() failed to "
2116 "start file recording");
2117 _outputFileRecorderPtr->StopRecording();
2118 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2119 _outputFileRecorderPtr = NULL;
2120 return -1;
2121 }
2122
2123 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2124 _outputFileRecording = true;
2125
2126 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002127}
2128
kwiberg55b97fe2016-01-28 05:22:45 -08002129int Channel::StopRecordingPlayout() {
2130 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
2131 "Channel::StopRecordingPlayout()");
2132
2133 if (!_outputFileRecording) {
2134 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
2135 "StopRecordingPlayout() isnot recording");
2136 return -1;
2137 }
2138
2139 rtc::CritScope cs(&_fileCritSect);
2140
2141 if (_outputFileRecorderPtr->StopRecording() != 0) {
2142 _engineStatisticsPtr->SetLastError(
2143 VE_STOP_RECORDING_FAILED, kTraceError,
2144 "StopRecording() could not stop recording");
2145 return (-1);
2146 }
2147 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2148 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2149 _outputFileRecorderPtr = NULL;
2150 _outputFileRecording = false;
2151
2152 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002153}
2154
kwiberg55b97fe2016-01-28 05:22:45 -08002155void Channel::SetMixWithMicStatus(bool mix) {
2156 rtc::CritScope cs(&_fileCritSect);
2157 _mixFileWithMicrophone = mix;
niklase@google.com470e71d2011-07-07 08:21:25 +00002158}
2159
kwiberg55b97fe2016-01-28 05:22:45 -08002160int Channel::GetSpeechOutputLevel(uint32_t& level) const {
2161 int8_t currentLevel = _outputAudioLevel.Level();
2162 level = static_cast<int32_t>(currentLevel);
2163 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002164}
2165
kwiberg55b97fe2016-01-28 05:22:45 -08002166int Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const {
2167 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2168 level = static_cast<int32_t>(currentLevel);
2169 return 0;
2170}
2171
2172int Channel::SetMute(bool enable) {
2173 rtc::CritScope cs(&volume_settings_critsect_);
2174 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002175 "Channel::SetMute(enable=%d)", enable);
kwiberg55b97fe2016-01-28 05:22:45 -08002176 _mute = enable;
2177 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002178}
2179
kwiberg55b97fe2016-01-28 05:22:45 -08002180bool Channel::Mute() const {
2181 rtc::CritScope cs(&volume_settings_critsect_);
2182 return _mute;
niklase@google.com470e71d2011-07-07 08:21:25 +00002183}
2184
kwiberg55b97fe2016-01-28 05:22:45 -08002185int Channel::SetOutputVolumePan(float left, float right) {
2186 rtc::CritScope cs(&volume_settings_critsect_);
2187 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002188 "Channel::SetOutputVolumePan()");
kwiberg55b97fe2016-01-28 05:22:45 -08002189 _panLeft = left;
2190 _panRight = right;
2191 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002192}
2193
kwiberg55b97fe2016-01-28 05:22:45 -08002194int Channel::GetOutputVolumePan(float& left, float& right) const {
2195 rtc::CritScope cs(&volume_settings_critsect_);
2196 left = _panLeft;
2197 right = _panRight;
2198 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002199}
2200
kwiberg55b97fe2016-01-28 05:22:45 -08002201int Channel::SetChannelOutputVolumeScaling(float scaling) {
2202 rtc::CritScope cs(&volume_settings_critsect_);
2203 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002204 "Channel::SetChannelOutputVolumeScaling()");
kwiberg55b97fe2016-01-28 05:22:45 -08002205 _outputGain = scaling;
2206 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002207}
2208
kwiberg55b97fe2016-01-28 05:22:45 -08002209int Channel::GetChannelOutputVolumeScaling(float& scaling) const {
2210 rtc::CritScope cs(&volume_settings_critsect_);
2211 scaling = _outputGain;
2212 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002213}
2214
niklase@google.com470e71d2011-07-07 08:21:25 +00002215int Channel::SendTelephoneEventOutband(unsigned char eventCode,
kwiberg55b97fe2016-01-28 05:22:45 -08002216 int lengthMs,
2217 int attenuationDb,
2218 bool playDtmfEvent) {
2219 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002220 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2221 playDtmfEvent);
kwiberg55b97fe2016-01-28 05:22:45 -08002222 if (!Sending()) {
2223 return -1;
2224 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002225
kwiberg55b97fe2016-01-28 05:22:45 -08002226 _playOutbandDtmfEvent = playDtmfEvent;
niklase@google.com470e71d2011-07-07 08:21:25 +00002227
kwiberg55b97fe2016-01-28 05:22:45 -08002228 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
2229 attenuationDb) != 0) {
2230 _engineStatisticsPtr->SetLastError(
2231 VE_SEND_DTMF_FAILED, kTraceWarning,
2232 "SendTelephoneEventOutband() failed to send event");
2233 return -1;
2234 }
2235 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002236}
2237
2238int Channel::SendTelephoneEventInband(unsigned char eventCode,
kwiberg55b97fe2016-01-28 05:22:45 -08002239 int lengthMs,
2240 int attenuationDb,
2241 bool playDtmfEvent) {
2242 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002243 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2244 playDtmfEvent);
2245
kwiberg55b97fe2016-01-28 05:22:45 -08002246 _playInbandDtmfEvent = playDtmfEvent;
2247 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
niklase@google.com470e71d2011-07-07 08:21:25 +00002248
kwiberg55b97fe2016-01-28 05:22:45 -08002249 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002250}
2251
kwiberg55b97fe2016-01-28 05:22:45 -08002252int Channel::SetSendTelephoneEventPayloadType(unsigned char type) {
2253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00002254 "Channel::SetSendTelephoneEventPayloadType()");
kwiberg55b97fe2016-01-28 05:22:45 -08002255 if (type > 127) {
2256 _engineStatisticsPtr->SetLastError(
2257 VE_INVALID_ARGUMENT, kTraceError,
2258 "SetSendTelephoneEventPayloadType() invalid type");
2259 return -1;
2260 }
2261 CodecInst codec = {};
2262 codec.plfreq = 8000;
2263 codec.pltype = type;
2264 memcpy(codec.plname, "telephone-event", 16);
2265 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2266 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2267 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2268 _engineStatisticsPtr->SetLastError(
2269 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2270 "SetSendTelephoneEventPayloadType() failed to register send"
2271 "payload type");
2272 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002273 }
kwiberg55b97fe2016-01-28 05:22:45 -08002274 }
2275 _sendTelephoneEventPayloadType = type;
2276 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002277}
2278
kwiberg55b97fe2016-01-28 05:22:45 -08002279int Channel::GetSendTelephoneEventPayloadType(unsigned char& type) {
2280 type = _sendTelephoneEventPayloadType;
2281 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002282}
2283
kwiberg55b97fe2016-01-28 05:22:45 -08002284int Channel::UpdateRxVadDetection(AudioFrame& audioFrame) {
2285 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2286 "Channel::UpdateRxVadDetection()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002287
kwiberg55b97fe2016-01-28 05:22:45 -08002288 int vadDecision = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002289
kwiberg55b97fe2016-01-28 05:22:45 -08002290 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive) ? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002291
kwiberg55b97fe2016-01-28 05:22:45 -08002292 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr) {
2293 OnRxVadDetected(vadDecision);
2294 _oldVadDecision = vadDecision;
2295 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002296
kwiberg55b97fe2016-01-28 05:22:45 -08002297 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2298 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2299 vadDecision);
2300 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002301}
2302
kwiberg55b97fe2016-01-28 05:22:45 -08002303int Channel::RegisterRxVadObserver(VoERxVadCallback& observer) {
2304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2305 "Channel::RegisterRxVadObserver()");
2306 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002307
kwiberg55b97fe2016-01-28 05:22:45 -08002308 if (_rxVadObserverPtr) {
2309 _engineStatisticsPtr->SetLastError(
2310 VE_INVALID_OPERATION, kTraceError,
2311 "RegisterRxVadObserver() observer already enabled");
2312 return -1;
2313 }
2314 _rxVadObserverPtr = &observer;
2315 _RxVadDetection = true;
2316 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002317}
2318
kwiberg55b97fe2016-01-28 05:22:45 -08002319int Channel::DeRegisterRxVadObserver() {
2320 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2321 "Channel::DeRegisterRxVadObserver()");
2322 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002323
kwiberg55b97fe2016-01-28 05:22:45 -08002324 if (!_rxVadObserverPtr) {
2325 _engineStatisticsPtr->SetLastError(
2326 VE_INVALID_OPERATION, kTraceWarning,
2327 "DeRegisterRxVadObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002328 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002329 }
2330 _rxVadObserverPtr = NULL;
2331 _RxVadDetection = false;
2332 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002333}
2334
kwiberg55b97fe2016-01-28 05:22:45 -08002335int Channel::VoiceActivityIndicator(int& activity) {
2336 activity = _sendFrameType;
2337 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002338}
2339
2340#ifdef WEBRTC_VOICE_ENGINE_AGC
2341
kwiberg55b97fe2016-01-28 05:22:45 -08002342int Channel::SetRxAgcStatus(bool enable, AgcModes mode) {
2343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2344 "Channel::SetRxAgcStatus(enable=%d, mode=%d)", (int)enable,
2345 (int)mode);
niklase@google.com470e71d2011-07-07 08:21:25 +00002346
kwiberg55b97fe2016-01-28 05:22:45 -08002347 GainControl::Mode agcMode = kDefaultRxAgcMode;
2348 switch (mode) {
2349 case kAgcDefault:
2350 break;
2351 case kAgcUnchanged:
2352 agcMode = rx_audioproc_->gain_control()->mode();
2353 break;
2354 case kAgcFixedDigital:
2355 agcMode = GainControl::kFixedDigital;
2356 break;
2357 case kAgcAdaptiveDigital:
2358 agcMode = GainControl::kAdaptiveDigital;
2359 break;
2360 default:
2361 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
2362 "SetRxAgcStatus() invalid Agc mode");
2363 return -1;
2364 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002365
kwiberg55b97fe2016-01-28 05:22:45 -08002366 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0) {
2367 _engineStatisticsPtr->SetLastError(
2368 VE_APM_ERROR, kTraceError, "SetRxAgcStatus() failed to set Agc mode");
2369 return -1;
2370 }
2371 if (rx_audioproc_->gain_control()->Enable(enable) != 0) {
2372 _engineStatisticsPtr->SetLastError(
2373 VE_APM_ERROR, kTraceError, "SetRxAgcStatus() failed to set Agc state");
2374 return -1;
2375 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002376
kwiberg55b97fe2016-01-28 05:22:45 -08002377 _rxAgcIsEnabled = enable;
2378 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002379
kwiberg55b97fe2016-01-28 05:22:45 -08002380 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002381}
2382
kwiberg55b97fe2016-01-28 05:22:45 -08002383int Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode) {
2384 bool enable = rx_audioproc_->gain_control()->is_enabled();
2385 GainControl::Mode agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002386
kwiberg55b97fe2016-01-28 05:22:45 -08002387 enabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00002388
kwiberg55b97fe2016-01-28 05:22:45 -08002389 switch (agcMode) {
2390 case GainControl::kFixedDigital:
2391 mode = kAgcFixedDigital;
2392 break;
2393 case GainControl::kAdaptiveDigital:
2394 mode = kAgcAdaptiveDigital;
2395 break;
2396 default:
2397 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
2398 "GetRxAgcStatus() invalid Agc mode");
2399 return -1;
2400 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002401
kwiberg55b97fe2016-01-28 05:22:45 -08002402 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002403}
2404
kwiberg55b97fe2016-01-28 05:22:45 -08002405int Channel::SetRxAgcConfig(AgcConfig config) {
2406 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2407 "Channel::SetRxAgcConfig()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002408
kwiberg55b97fe2016-01-28 05:22:45 -08002409 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
2410 config.targetLeveldBOv) != 0) {
2411 _engineStatisticsPtr->SetLastError(
2412 VE_APM_ERROR, kTraceError,
2413 "SetRxAgcConfig() failed to set target peak |level|"
2414 "(or envelope) of the Agc");
2415 return -1;
2416 }
2417 if (rx_audioproc_->gain_control()->set_compression_gain_db(
2418 config.digitalCompressionGaindB) != 0) {
2419 _engineStatisticsPtr->SetLastError(
2420 VE_APM_ERROR, kTraceError,
2421 "SetRxAgcConfig() failed to set the range in |gain| the"
2422 " digital compression stage may apply");
2423 return -1;
2424 }
2425 if (rx_audioproc_->gain_control()->enable_limiter(config.limiterEnable) !=
2426 0) {
2427 _engineStatisticsPtr->SetLastError(
2428 VE_APM_ERROR, kTraceError,
2429 "SetRxAgcConfig() failed to set hard limiter to the signal");
2430 return -1;
2431 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002432
kwiberg55b97fe2016-01-28 05:22:45 -08002433 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002434}
2435
kwiberg55b97fe2016-01-28 05:22:45 -08002436int Channel::GetRxAgcConfig(AgcConfig& config) {
2437 config.targetLeveldBOv = rx_audioproc_->gain_control()->target_level_dbfs();
2438 config.digitalCompressionGaindB =
2439 rx_audioproc_->gain_control()->compression_gain_db();
2440 config.limiterEnable = rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002441
kwiberg55b97fe2016-01-28 05:22:45 -08002442 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002443}
2444
kwiberg55b97fe2016-01-28 05:22:45 -08002445#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
niklase@google.com470e71d2011-07-07 08:21:25 +00002446
2447#ifdef WEBRTC_VOICE_ENGINE_NR
2448
kwiberg55b97fe2016-01-28 05:22:45 -08002449int Channel::SetRxNsStatus(bool enable, NsModes mode) {
2450 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2451 "Channel::SetRxNsStatus(enable=%d, mode=%d)", (int)enable,
2452 (int)mode);
niklase@google.com470e71d2011-07-07 08:21:25 +00002453
kwiberg55b97fe2016-01-28 05:22:45 -08002454 NoiseSuppression::Level nsLevel = kDefaultNsMode;
2455 switch (mode) {
2456 case kNsDefault:
2457 break;
2458 case kNsUnchanged:
2459 nsLevel = rx_audioproc_->noise_suppression()->level();
2460 break;
2461 case kNsConference:
2462 nsLevel = NoiseSuppression::kHigh;
2463 break;
2464 case kNsLowSuppression:
2465 nsLevel = NoiseSuppression::kLow;
2466 break;
2467 case kNsModerateSuppression:
2468 nsLevel = NoiseSuppression::kModerate;
2469 break;
2470 case kNsHighSuppression:
2471 nsLevel = NoiseSuppression::kHigh;
2472 break;
2473 case kNsVeryHighSuppression:
2474 nsLevel = NoiseSuppression::kVeryHigh;
2475 break;
2476 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002477
kwiberg55b97fe2016-01-28 05:22:45 -08002478 if (rx_audioproc_->noise_suppression()->set_level(nsLevel) != 0) {
2479 _engineStatisticsPtr->SetLastError(
2480 VE_APM_ERROR, kTraceError, "SetRxNsStatus() failed to set NS level");
2481 return -1;
2482 }
2483 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0) {
2484 _engineStatisticsPtr->SetLastError(
2485 VE_APM_ERROR, kTraceError, "SetRxNsStatus() failed to set NS state");
2486 return -1;
2487 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002488
kwiberg55b97fe2016-01-28 05:22:45 -08002489 _rxNsIsEnabled = enable;
2490 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002491
kwiberg55b97fe2016-01-28 05:22:45 -08002492 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002493}
2494
kwiberg55b97fe2016-01-28 05:22:45 -08002495int Channel::GetRxNsStatus(bool& enabled, NsModes& mode) {
2496 bool enable = rx_audioproc_->noise_suppression()->is_enabled();
2497 NoiseSuppression::Level ncLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002498
kwiberg55b97fe2016-01-28 05:22:45 -08002499 enabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00002500
kwiberg55b97fe2016-01-28 05:22:45 -08002501 switch (ncLevel) {
2502 case NoiseSuppression::kLow:
2503 mode = kNsLowSuppression;
2504 break;
2505 case NoiseSuppression::kModerate:
2506 mode = kNsModerateSuppression;
2507 break;
2508 case NoiseSuppression::kHigh:
2509 mode = kNsHighSuppression;
2510 break;
2511 case NoiseSuppression::kVeryHigh:
2512 mode = kNsVeryHighSuppression;
2513 break;
2514 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002515
kwiberg55b97fe2016-01-28 05:22:45 -08002516 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002517}
2518
kwiberg55b97fe2016-01-28 05:22:45 -08002519#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
niklase@google.com470e71d2011-07-07 08:21:25 +00002520
kwiberg55b97fe2016-01-28 05:22:45 -08002521int Channel::SetLocalSSRC(unsigned int ssrc) {
2522 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2523 "Channel::SetLocalSSRC()");
2524 if (channel_state_.Get().sending) {
2525 _engineStatisticsPtr->SetLastError(VE_ALREADY_SENDING, kTraceError,
2526 "SetLocalSSRC() already sending");
2527 return -1;
2528 }
2529 _rtpRtcpModule->SetSSRC(ssrc);
2530 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002531}
2532
kwiberg55b97fe2016-01-28 05:22:45 -08002533int Channel::GetLocalSSRC(unsigned int& ssrc) {
2534 ssrc = _rtpRtcpModule->SSRC();
2535 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002536}
2537
kwiberg55b97fe2016-01-28 05:22:45 -08002538int Channel::GetRemoteSSRC(unsigned int& ssrc) {
2539 ssrc = rtp_receiver_->SSRC();
2540 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002541}
2542
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002543int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002544 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002545 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002546}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002547
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002548int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2549 unsigned char id) {
kwiberg55b97fe2016-01-28 05:22:45 -08002550 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
2551 if (enable &&
2552 !rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
2553 id)) {
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002554 return -1;
2555 }
2556 return 0;
2557}
2558
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002559int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2560 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2561}
2562
2563int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2564 rtp_header_parser_->DeregisterRtpHeaderExtension(
2565 kRtpExtensionAbsoluteSendTime);
kwiberg55b97fe2016-01-28 05:22:45 -08002566 if (enable &&
2567 !rtp_header_parser_->RegisterRtpHeaderExtension(
2568 kRtpExtensionAbsoluteSendTime, id)) {
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002569 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002570 }
2571 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002572}
2573
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002574void Channel::EnableSendTransportSequenceNumber(int id) {
2575 int ret =
2576 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2577 RTC_DCHECK_EQ(0, ret);
2578}
2579
stefan3313ec92016-01-21 06:32:43 -08002580void Channel::EnableReceiveTransportSequenceNumber(int id) {
2581 rtp_header_parser_->DeregisterRtpHeaderExtension(
2582 kRtpExtensionTransportSequenceNumber);
2583 bool ret = rtp_header_parser_->RegisterRtpHeaderExtension(
2584 kRtpExtensionTransportSequenceNumber, id);
2585 RTC_DCHECK(ret);
2586}
2587
stefanbba9dec2016-02-01 04:39:55 -08002588void Channel::RegisterSenderCongestionControlObjects(
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002589 RtpPacketSender* rtp_packet_sender,
2590 TransportFeedbackObserver* transport_feedback_observer,
2591 PacketRouter* packet_router) {
stefanbba9dec2016-02-01 04:39:55 -08002592 RTC_DCHECK(rtp_packet_sender);
2593 RTC_DCHECK(transport_feedback_observer);
2594 RTC_DCHECK(packet_router && !packet_router_);
2595 feedback_observer_proxy_->SetTransportFeedbackObserver(
2596 transport_feedback_observer);
2597 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2598 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2599 _rtpRtcpModule->SetStorePacketsStatus(true, 600);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002600 packet_router->AddRtpModule(_rtpRtcpModule.get());
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002601 packet_router_ = packet_router;
2602}
2603
stefanbba9dec2016-02-01 04:39:55 -08002604void Channel::RegisterReceiverCongestionControlObjects(
2605 PacketRouter* packet_router) {
2606 RTC_DCHECK(packet_router && !packet_router_);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002607 packet_router->AddRtpModule(_rtpRtcpModule.get());
stefanbba9dec2016-02-01 04:39:55 -08002608 packet_router_ = packet_router;
2609}
2610
2611void Channel::ResetCongestionControlObjects() {
2612 RTC_DCHECK(packet_router_);
2613 _rtpRtcpModule->SetStorePacketsStatus(false, 600);
2614 feedback_observer_proxy_->SetTransportFeedbackObserver(nullptr);
2615 seq_num_allocator_proxy_->SetSequenceNumberAllocator(nullptr);
Peter Boström3dd5d1d2016-02-25 16:56:48 +01002616 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
stefanbba9dec2016-02-01 04:39:55 -08002617 packet_router_ = nullptr;
2618 rtp_packet_sender_proxy_->SetPacketSender(nullptr);
2619}
2620
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002621void Channel::SetRTCPStatus(bool enable) {
2622 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2623 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002624 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002625}
2626
kwiberg55b97fe2016-01-28 05:22:45 -08002627int Channel::GetRTCPStatus(bool& enabled) {
pbosda903ea2015-10-02 02:36:56 -07002628 RtcpMode method = _rtpRtcpModule->RTCP();
2629 enabled = (method != RtcpMode::kOff);
kwiberg55b97fe2016-01-28 05:22:45 -08002630 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002631}
2632
kwiberg55b97fe2016-01-28 05:22:45 -08002633int Channel::SetRTCP_CNAME(const char cName[256]) {
2634 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2635 "Channel::SetRTCP_CNAME()");
2636 if (_rtpRtcpModule->SetCNAME(cName) != 0) {
2637 _engineStatisticsPtr->SetLastError(
2638 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2639 "SetRTCP_CNAME() failed to set RTCP CNAME");
2640 return -1;
2641 }
2642 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002643}
2644
kwiberg55b97fe2016-01-28 05:22:45 -08002645int Channel::GetRemoteRTCP_CNAME(char cName[256]) {
2646 if (cName == NULL) {
2647 _engineStatisticsPtr->SetLastError(
2648 VE_INVALID_ARGUMENT, kTraceError,
2649 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2650 return -1;
2651 }
2652 char cname[RTCP_CNAME_SIZE];
2653 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
2654 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0) {
2655 _engineStatisticsPtr->SetLastError(
2656 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2657 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2658 return -1;
2659 }
2660 strcpy(cName, cname);
2661 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002662}
2663
kwiberg55b97fe2016-01-28 05:22:45 -08002664int Channel::GetRemoteRTCPData(unsigned int& NTPHigh,
2665 unsigned int& NTPLow,
2666 unsigned int& timestamp,
2667 unsigned int& playoutTimestamp,
2668 unsigned int* jitter,
2669 unsigned short* fractionLost) {
2670 // --- Information from sender info in received Sender Reports
niklase@google.com470e71d2011-07-07 08:21:25 +00002671
kwiberg55b97fe2016-01-28 05:22:45 -08002672 RTCPSenderInfo senderInfo;
2673 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0) {
2674 _engineStatisticsPtr->SetLastError(
2675 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2676 "GetRemoteRTCPData() failed to retrieve sender info for remote "
2677 "side");
2678 return -1;
2679 }
2680
2681 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2682 // and octet count)
2683 NTPHigh = senderInfo.NTPseconds;
2684 NTPLow = senderInfo.NTPfraction;
2685 timestamp = senderInfo.RTPtimeStamp;
2686
2687 // --- Locally derived information
2688
2689 // This value is updated on each incoming RTCP packet (0 when no packet
2690 // has been received)
2691 playoutTimestamp = playout_timestamp_rtcp_;
2692
2693 if (NULL != jitter || NULL != fractionLost) {
2694 // Get all RTCP receiver report blocks that have been received on this
2695 // channel. If we receive RTP packets from a remote source we know the
2696 // remote SSRC and use the report block from him.
2697 // Otherwise use the first report block.
2698 std::vector<RTCPReportBlock> remote_stats;
2699 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
2700 remote_stats.empty()) {
2701 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
2702 "GetRemoteRTCPData() failed to measure statistics due"
2703 " to lack of received RTP and/or RTCP packets");
2704 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002705 }
2706
kwiberg55b97fe2016-01-28 05:22:45 -08002707 uint32_t remoteSSRC = rtp_receiver_->SSRC();
2708 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2709 for (; it != remote_stats.end(); ++it) {
2710 if (it->remoteSSRC == remoteSSRC)
2711 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002712 }
kwiberg55b97fe2016-01-28 05:22:45 -08002713
2714 if (it == remote_stats.end()) {
2715 // If we have not received any RTCP packets from this SSRC it probably
2716 // means that we have not received any RTP packets.
2717 // Use the first received report block instead.
2718 it = remote_stats.begin();
2719 remoteSSRC = it->remoteSSRC;
2720 }
2721
2722 if (jitter) {
2723 *jitter = it->jitter;
2724 }
2725
2726 if (fractionLost) {
2727 *fractionLost = it->fractionLost;
2728 }
2729 }
2730 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002731}
2732
kwiberg55b97fe2016-01-28 05:22:45 -08002733int Channel::SendApplicationDefinedRTCPPacket(
2734 unsigned char subType,
2735 unsigned int name,
2736 const char* data,
2737 unsigned short dataLengthInBytes) {
2738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2739 "Channel::SendApplicationDefinedRTCPPacket()");
2740 if (!channel_state_.Get().sending) {
2741 _engineStatisticsPtr->SetLastError(
2742 VE_NOT_SENDING, kTraceError,
2743 "SendApplicationDefinedRTCPPacket() not sending");
2744 return -1;
2745 }
2746 if (NULL == data) {
2747 _engineStatisticsPtr->SetLastError(
2748 VE_INVALID_ARGUMENT, kTraceError,
2749 "SendApplicationDefinedRTCPPacket() invalid data value");
2750 return -1;
2751 }
2752 if (dataLengthInBytes % 4 != 0) {
2753 _engineStatisticsPtr->SetLastError(
2754 VE_INVALID_ARGUMENT, kTraceError,
2755 "SendApplicationDefinedRTCPPacket() invalid length value");
2756 return -1;
2757 }
2758 RtcpMode status = _rtpRtcpModule->RTCP();
2759 if (status == RtcpMode::kOff) {
2760 _engineStatisticsPtr->SetLastError(
2761 VE_RTCP_ERROR, kTraceError,
2762 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
2763 return -1;
2764 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002765
kwiberg55b97fe2016-01-28 05:22:45 -08002766 // Create and schedule the RTCP APP packet for transmission
2767 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
2768 subType, name, (const unsigned char*)data, dataLengthInBytes) != 0) {
2769 _engineStatisticsPtr->SetLastError(
2770 VE_SEND_ERROR, kTraceError,
2771 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
2772 return -1;
2773 }
2774 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002775}
2776
kwiberg55b97fe2016-01-28 05:22:45 -08002777int Channel::GetRTPStatistics(unsigned int& averageJitterMs,
2778 unsigned int& maxJitterMs,
2779 unsigned int& discardedPackets) {
2780 // The jitter statistics is updated for each received RTP packet and is
2781 // based on received packets.
2782 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
2783 // If RTCP is off, there is no timed thread in the RTCP module regularly
2784 // generating new stats, trigger the update manually here instead.
2785 StreamStatistician* statistician =
2786 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
2787 if (statistician) {
2788 // Don't use returned statistics, use data from proxy instead so that
2789 // max jitter can be fetched atomically.
2790 RtcpStatistics s;
2791 statistician->GetStatistics(&s, true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002792 }
kwiberg55b97fe2016-01-28 05:22:45 -08002793 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002794
kwiberg55b97fe2016-01-28 05:22:45 -08002795 ChannelStatistics stats = statistics_proxy_->GetStats();
2796 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
2797 if (playoutFrequency > 0) {
2798 // Scale RTP statistics given the current playout frequency
2799 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
2800 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
2801 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002802
kwiberg55b97fe2016-01-28 05:22:45 -08002803 discardedPackets = _numberOfDiscardedPackets;
niklase@google.com470e71d2011-07-07 08:21:25 +00002804
kwiberg55b97fe2016-01-28 05:22:45 -08002805 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002806}
2807
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002808int Channel::GetRemoteRTCPReportBlocks(
2809 std::vector<ReportBlock>* report_blocks) {
2810 if (report_blocks == NULL) {
kwiberg55b97fe2016-01-28 05:22:45 -08002811 _engineStatisticsPtr->SetLastError(
2812 VE_INVALID_ARGUMENT, kTraceError,
2813 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002814 return -1;
2815 }
2816
2817 // Get the report blocks from the latest received RTCP Sender or Receiver
2818 // Report. Each element in the vector contains the sender's SSRC and a
2819 // report block according to RFC 3550.
2820 std::vector<RTCPReportBlock> rtcp_report_blocks;
2821 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002822 return -1;
2823 }
2824
2825 if (rtcp_report_blocks.empty())
2826 return 0;
2827
2828 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
2829 for (; it != rtcp_report_blocks.end(); ++it) {
2830 ReportBlock report_block;
2831 report_block.sender_SSRC = it->remoteSSRC;
2832 report_block.source_SSRC = it->sourceSSRC;
2833 report_block.fraction_lost = it->fractionLost;
2834 report_block.cumulative_num_packets_lost = it->cumulativeLost;
2835 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
2836 report_block.interarrival_jitter = it->jitter;
2837 report_block.last_SR_timestamp = it->lastSR;
2838 report_block.delay_since_last_SR = it->delaySinceLastSR;
2839 report_blocks->push_back(report_block);
2840 }
2841 return 0;
2842}
2843
kwiberg55b97fe2016-01-28 05:22:45 -08002844int Channel::GetRTPStatistics(CallStatistics& stats) {
2845 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00002846
kwiberg55b97fe2016-01-28 05:22:45 -08002847 // The jitter statistics is updated for each received RTP packet and is
2848 // based on received packets.
2849 RtcpStatistics statistics;
2850 StreamStatistician* statistician =
2851 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
Peter Boström59013bc2016-02-12 11:35:08 +01002852 if (statistician) {
2853 statistician->GetStatistics(&statistics,
2854 _rtpRtcpModule->RTCP() == RtcpMode::kOff);
kwiberg55b97fe2016-01-28 05:22:45 -08002855 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002856
kwiberg55b97fe2016-01-28 05:22:45 -08002857 stats.fractionLost = statistics.fraction_lost;
2858 stats.cumulativeLost = statistics.cumulative_lost;
2859 stats.extendedMax = statistics.extended_max_sequence_number;
2860 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00002861
kwiberg55b97fe2016-01-28 05:22:45 -08002862 // --- RTT
2863 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002864
kwiberg55b97fe2016-01-28 05:22:45 -08002865 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00002866
kwiberg55b97fe2016-01-28 05:22:45 -08002867 size_t bytesSent(0);
2868 uint32_t packetsSent(0);
2869 size_t bytesReceived(0);
2870 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002871
kwiberg55b97fe2016-01-28 05:22:45 -08002872 if (statistician) {
2873 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
2874 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002875
kwiberg55b97fe2016-01-28 05:22:45 -08002876 if (_rtpRtcpModule->DataCountersRTP(&bytesSent, &packetsSent) != 0) {
2877 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
2878 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
2879 " output will not be complete");
2880 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002881
kwiberg55b97fe2016-01-28 05:22:45 -08002882 stats.bytesSent = bytesSent;
2883 stats.packetsSent = packetsSent;
2884 stats.bytesReceived = bytesReceived;
2885 stats.packetsReceived = packetsReceived;
niklase@google.com470e71d2011-07-07 08:21:25 +00002886
kwiberg55b97fe2016-01-28 05:22:45 -08002887 // --- Timestamps
2888 {
2889 rtc::CritScope lock(&ts_stats_lock_);
2890 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
2891 }
2892 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002893}
2894
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002895int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002896 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002897 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00002898
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00002899 if (enable) {
2900 if (redPayloadtype < 0 || redPayloadtype > 127) {
2901 _engineStatisticsPtr->SetLastError(
2902 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002903 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00002904 return -1;
2905 }
2906
2907 if (SetRedPayloadType(redPayloadtype) < 0) {
2908 _engineStatisticsPtr->SetLastError(
2909 VE_CODEC_ERROR, kTraceError,
2910 "SetSecondarySendCodec() Failed to register RED ACM");
2911 return -1;
2912 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002913 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002914
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00002915 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002916 _engineStatisticsPtr->SetLastError(
2917 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00002918 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00002919 return -1;
2920 }
2921 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002922}
2923
kwiberg55b97fe2016-01-28 05:22:45 -08002924int Channel::GetREDStatus(bool& enabled, int& redPayloadtype) {
2925 enabled = audio_coding_->REDStatus();
2926 if (enabled) {
2927 int8_t payloadType = 0;
2928 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
2929 _engineStatisticsPtr->SetLastError(
2930 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2931 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
2932 "module");
2933 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002934 }
kwiberg55b97fe2016-01-28 05:22:45 -08002935 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002936 return 0;
kwiberg55b97fe2016-01-28 05:22:45 -08002937 }
2938 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002939}
2940
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002941int Channel::SetCodecFECStatus(bool enable) {
2942 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2943 "Channel::SetCodecFECStatus()");
2944
2945 if (audio_coding_->SetCodecFEC(enable) != 0) {
2946 _engineStatisticsPtr->SetLastError(
2947 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2948 "SetCodecFECStatus() failed to set FEC state");
2949 return -1;
2950 }
2951 return 0;
2952}
2953
2954bool Channel::GetCodecFECStatus() {
2955 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00002956 return enabled;
2957}
2958
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002959void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
2960 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002961 // If pacing is enabled we always store packets.
2962 if (!pacing_enabled_)
2963 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002964 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
2965 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002966 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002967 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002968 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002969 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002970}
2971
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00002972// Called when we are missing one or more packets.
2973int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00002974 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
2975}
2976
kwiberg55b97fe2016-01-28 05:22:45 -08002977uint32_t Channel::Demultiplex(const AudioFrame& audioFrame) {
2978 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
2979 "Channel::Demultiplex()");
2980 _audioFrame.CopyFrom(audioFrame);
2981 _audioFrame.id_ = _channelId;
2982 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002983}
2984
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002985void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00002986 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07002987 size_t number_of_frames,
Peter Kasting69558702016-01-12 16:26:35 -08002988 size_t number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002989 CodecInst codec;
2990 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002991
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07002992 // Never upsample or upmix the capture signal here. This should be done at the
2993 // end of the send chain.
2994 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
2995 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
2996 RemixAndResample(audio_data, number_of_frames, number_of_channels,
2997 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00002998}
2999
kwiberg55b97fe2016-01-28 05:22:45 -08003000uint32_t Channel::PrepareEncodeAndSend(int mixingFrequency) {
3001 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
3002 "Channel::PrepareEncodeAndSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003003
kwiberg55b97fe2016-01-28 05:22:45 -08003004 if (_audioFrame.samples_per_channel_ == 0) {
3005 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3006 "Channel::PrepareEncodeAndSend() invalid audio frame");
3007 return 0xFFFFFFFF;
3008 }
3009
3010 if (channel_state_.Get().input_file_playing) {
3011 MixOrReplaceAudioWithFile(mixingFrequency);
3012 }
3013
3014 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3015 if (is_muted) {
3016 AudioFrameOperations::Mute(_audioFrame);
3017 }
3018
3019 if (channel_state_.Get().input_external_media) {
3020 rtc::CritScope cs(&_callbackCritSect);
3021 const bool isStereo = (_audioFrame.num_channels_ == 2);
3022 if (_inputExternalMediaCallbackPtr) {
3023 _inputExternalMediaCallbackPtr->Process(
3024 _channelId, kRecordingPerChannel, (int16_t*)_audioFrame.data_,
3025 _audioFrame.samples_per_channel_, _audioFrame.sample_rate_hz_,
3026 isStereo);
niklase@google.com470e71d2011-07-07 08:21:25 +00003027 }
kwiberg55b97fe2016-01-28 05:22:45 -08003028 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003029
kwiberg55b97fe2016-01-28 05:22:45 -08003030 InsertInbandDtmfTone();
niklase@google.com470e71d2011-07-07 08:21:25 +00003031
kwiberg55b97fe2016-01-28 05:22:45 -08003032 if (_includeAudioLevelIndication) {
3033 size_t length =
3034 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003035 if (is_muted) {
kwiberg55b97fe2016-01-28 05:22:45 -08003036 rms_level_.ProcessMuted(length);
3037 } else {
3038 rms_level_.Process(_audioFrame.data_, length);
niklase@google.com470e71d2011-07-07 08:21:25 +00003039 }
kwiberg55b97fe2016-01-28 05:22:45 -08003040 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003041
kwiberg55b97fe2016-01-28 05:22:45 -08003042 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003043}
3044
kwiberg55b97fe2016-01-28 05:22:45 -08003045uint32_t Channel::EncodeAndSend() {
3046 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
3047 "Channel::EncodeAndSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003048
kwiberg55b97fe2016-01-28 05:22:45 -08003049 assert(_audioFrame.num_channels_ <= 2);
3050 if (_audioFrame.samples_per_channel_ == 0) {
3051 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3052 "Channel::EncodeAndSend() invalid audio frame");
3053 return 0xFFFFFFFF;
3054 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003055
kwiberg55b97fe2016-01-28 05:22:45 -08003056 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003057
kwiberg55b97fe2016-01-28 05:22:45 -08003058 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
niklase@google.com470e71d2011-07-07 08:21:25 +00003059
kwiberg55b97fe2016-01-28 05:22:45 -08003060 // The ACM resamples internally.
3061 _audioFrame.timestamp_ = _timeStamp;
3062 // This call will trigger AudioPacketizationCallback::SendData if encoding
3063 // is done and payload is ready for packetization and transmission.
3064 // Otherwise, it will return without invoking the callback.
3065 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0) {
3066 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
3067 "Channel::EncodeAndSend() ACM encoding failed");
3068 return 0xFFFFFFFF;
3069 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003070
kwiberg55b97fe2016-01-28 05:22:45 -08003071 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
3072 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003073}
3074
Minyue2013aec2015-05-13 14:14:42 +02003075void Channel::DisassociateSendChannel(int channel_id) {
tommi31fc21f2016-01-21 10:37:37 -08003076 rtc::CritScope lock(&assoc_send_channel_lock_);
Minyue2013aec2015-05-13 14:14:42 +02003077 Channel* channel = associate_send_channel_.channel();
3078 if (channel && channel->ChannelId() == channel_id) {
3079 // If this channel is associated with a send channel of the specified
3080 // Channel ID, disassociate with it.
3081 ChannelOwner ref(NULL);
3082 associate_send_channel_ = ref;
3083 }
3084}
3085
kwiberg55b97fe2016-01-28 05:22:45 -08003086int Channel::RegisterExternalMediaProcessing(ProcessingTypes type,
3087 VoEMediaProcess& processObject) {
3088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3089 "Channel::RegisterExternalMediaProcessing()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003090
kwiberg55b97fe2016-01-28 05:22:45 -08003091 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003092
kwiberg55b97fe2016-01-28 05:22:45 -08003093 if (kPlaybackPerChannel == type) {
3094 if (_outputExternalMediaCallbackPtr) {
3095 _engineStatisticsPtr->SetLastError(
3096 VE_INVALID_OPERATION, kTraceError,
3097 "Channel::RegisterExternalMediaProcessing() "
3098 "output external media already enabled");
3099 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003100 }
kwiberg55b97fe2016-01-28 05:22:45 -08003101 _outputExternalMediaCallbackPtr = &processObject;
3102 _outputExternalMedia = true;
3103 } else if (kRecordingPerChannel == type) {
3104 if (_inputExternalMediaCallbackPtr) {
3105 _engineStatisticsPtr->SetLastError(
3106 VE_INVALID_OPERATION, kTraceError,
3107 "Channel::RegisterExternalMediaProcessing() "
3108 "output external media already enabled");
3109 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003110 }
kwiberg55b97fe2016-01-28 05:22:45 -08003111 _inputExternalMediaCallbackPtr = &processObject;
3112 channel_state_.SetInputExternalMedia(true);
3113 }
3114 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003115}
3116
kwiberg55b97fe2016-01-28 05:22:45 -08003117int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type) {
3118 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3119 "Channel::DeRegisterExternalMediaProcessing()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003120
kwiberg55b97fe2016-01-28 05:22:45 -08003121 rtc::CritScope cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003122
kwiberg55b97fe2016-01-28 05:22:45 -08003123 if (kPlaybackPerChannel == type) {
3124 if (!_outputExternalMediaCallbackPtr) {
3125 _engineStatisticsPtr->SetLastError(
3126 VE_INVALID_OPERATION, kTraceWarning,
3127 "Channel::DeRegisterExternalMediaProcessing() "
3128 "output external media already disabled");
3129 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003130 }
kwiberg55b97fe2016-01-28 05:22:45 -08003131 _outputExternalMedia = false;
3132 _outputExternalMediaCallbackPtr = NULL;
3133 } else if (kRecordingPerChannel == type) {
3134 if (!_inputExternalMediaCallbackPtr) {
3135 _engineStatisticsPtr->SetLastError(
3136 VE_INVALID_OPERATION, kTraceWarning,
3137 "Channel::DeRegisterExternalMediaProcessing() "
3138 "input external media already disabled");
3139 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003140 }
kwiberg55b97fe2016-01-28 05:22:45 -08003141 channel_state_.SetInputExternalMedia(false);
3142 _inputExternalMediaCallbackPtr = NULL;
3143 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003144
kwiberg55b97fe2016-01-28 05:22:45 -08003145 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003146}
3147
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003148int Channel::SetExternalMixing(bool enabled) {
kwiberg55b97fe2016-01-28 05:22:45 -08003149 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3150 "Channel::SetExternalMixing(enabled=%d)", enabled);
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003151
kwiberg55b97fe2016-01-28 05:22:45 -08003152 if (channel_state_.Get().playing) {
3153 _engineStatisticsPtr->SetLastError(
3154 VE_INVALID_OPERATION, kTraceError,
3155 "Channel::SetExternalMixing() "
3156 "external mixing cannot be changed while playing.");
3157 return -1;
3158 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003159
kwiberg55b97fe2016-01-28 05:22:45 -08003160 _externalMixing = enabled;
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003161
kwiberg55b97fe2016-01-28 05:22:45 -08003162 return 0;
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003163}
3164
kwiberg55b97fe2016-01-28 05:22:45 -08003165int Channel::GetNetworkStatistics(NetworkStatistics& stats) {
3166 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003167}
3168
wu@webrtc.org24301a62013-12-13 19:17:43 +00003169void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3170 audio_coding_->GetDecodingCallStatistics(stats);
3171}
3172
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003173bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3174 int* playout_buffer_delay_ms) const {
tommi31fc21f2016-01-21 10:37:37 -08003175 rtc::CritScope lock(&video_sync_lock_);
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003176 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003177 return false;
3178 }
kwiberg55b97fe2016-01-28 05:22:45 -08003179 *jitter_buffer_delay_ms =
3180 (_average_jitter_buffer_delay_us + 500) / 1000 + _recPacketDelayMs;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003181 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003182 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003183}
3184
solenberg358057b2015-11-27 10:46:42 -08003185uint32_t Channel::GetDelayEstimate() const {
3186 int jitter_buffer_delay_ms = 0;
3187 int playout_buffer_delay_ms = 0;
3188 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3189 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3190}
3191
deadbeef74375882015-08-13 12:09:10 -07003192int Channel::LeastRequiredDelayMs() const {
3193 return audio_coding_->LeastRequiredDelayMs();
3194}
3195
kwiberg55b97fe2016-01-28 05:22:45 -08003196int Channel::SetMinimumPlayoutDelay(int delayMs) {
3197 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3198 "Channel::SetMinimumPlayoutDelay()");
3199 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3200 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs)) {
3201 _engineStatisticsPtr->SetLastError(
3202 VE_INVALID_ARGUMENT, kTraceError,
3203 "SetMinimumPlayoutDelay() invalid min delay");
3204 return -1;
3205 }
3206 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0) {
3207 _engineStatisticsPtr->SetLastError(
3208 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3209 "SetMinimumPlayoutDelay() failed to set min playout delay");
3210 return -1;
3211 }
3212 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003213}
3214
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003215int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003216 uint32_t playout_timestamp_rtp = 0;
3217 {
tommi31fc21f2016-01-21 10:37:37 -08003218 rtc::CritScope lock(&video_sync_lock_);
deadbeef74375882015-08-13 12:09:10 -07003219 playout_timestamp_rtp = playout_timestamp_rtp_;
3220 }
kwiberg55b97fe2016-01-28 05:22:45 -08003221 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003222 _engineStatisticsPtr->SetLastError(
3223 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3224 "GetPlayoutTimestamp() failed to retrieve timestamp");
3225 return -1;
3226 }
deadbeef74375882015-08-13 12:09:10 -07003227 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003228 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003229}
3230
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003231int Channel::SetInitTimestamp(unsigned int timestamp) {
3232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003233 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003234 if (channel_state_.Get().sending) {
3235 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3236 "SetInitTimestamp() already sending");
3237 return -1;
3238 }
3239 _rtpRtcpModule->SetStartTimestamp(timestamp);
3240 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003241}
3242
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003243int Channel::SetInitSequenceNumber(short sequenceNumber) {
3244 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3245 "Channel::SetInitSequenceNumber()");
3246 if (channel_state_.Get().sending) {
3247 _engineStatisticsPtr->SetLastError(
3248 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3249 return -1;
3250 }
3251 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3252 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003253}
3254
kwiberg55b97fe2016-01-28 05:22:45 -08003255int Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule,
3256 RtpReceiver** rtp_receiver) const {
3257 *rtpRtcpModule = _rtpRtcpModule.get();
3258 *rtp_receiver = rtp_receiver_.get();
3259 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003260}
3261
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003262// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3263// a shared helper.
kwiberg55b97fe2016-01-28 05:22:45 -08003264int32_t Channel::MixOrReplaceAudioWithFile(int mixingFrequency) {
kwibergb7f89d62016-02-17 10:04:18 -08003265 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[640]);
kwiberg55b97fe2016-01-28 05:22:45 -08003266 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003267
kwiberg55b97fe2016-01-28 05:22:45 -08003268 {
3269 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003270
kwiberg55b97fe2016-01-28 05:22:45 -08003271 if (_inputFilePlayerPtr == NULL) {
3272 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3273 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3274 " doesnt exist");
3275 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003276 }
3277
kwiberg55b97fe2016-01-28 05:22:45 -08003278 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(), fileSamples,
3279 mixingFrequency) == -1) {
3280 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3281 "Channel::MixOrReplaceAudioWithFile() file mixing "
3282 "failed");
3283 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003284 }
kwiberg55b97fe2016-01-28 05:22:45 -08003285 if (fileSamples == 0) {
3286 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3287 "Channel::MixOrReplaceAudioWithFile() file is ended");
3288 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003289 }
kwiberg55b97fe2016-01-28 05:22:45 -08003290 }
3291
3292 assert(_audioFrame.samples_per_channel_ == fileSamples);
3293
3294 if (_mixFileWithMicrophone) {
3295 // Currently file stream is always mono.
3296 // TODO(xians): Change the code when FilePlayer supports real stereo.
3297 MixWithSat(_audioFrame.data_, _audioFrame.num_channels_, fileBuffer.get(),
3298 1, fileSamples);
3299 } else {
3300 // Replace ACM audio with file.
3301 // Currently file stream is always mono.
3302 // TODO(xians): Change the code when FilePlayer supports real stereo.
3303 _audioFrame.UpdateFrame(
3304 _channelId, 0xFFFFFFFF, fileBuffer.get(), fileSamples, mixingFrequency,
3305 AudioFrame::kNormalSpeech, AudioFrame::kVadUnknown, 1);
3306 }
3307 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003308}
3309
kwiberg55b97fe2016-01-28 05:22:45 -08003310int32_t Channel::MixAudioWithFile(AudioFrame& audioFrame, int mixingFrequency) {
3311 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003312
kwibergb7f89d62016-02-17 10:04:18 -08003313 std::unique_ptr<int16_t[]> fileBuffer(new int16_t[960]);
kwiberg55b97fe2016-01-28 05:22:45 -08003314 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003315
kwiberg55b97fe2016-01-28 05:22:45 -08003316 {
3317 rtc::CritScope cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003318
kwiberg55b97fe2016-01-28 05:22:45 -08003319 if (_outputFilePlayerPtr == NULL) {
3320 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3321 "Channel::MixAudioWithFile() file mixing failed");
3322 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003323 }
3324
kwiberg55b97fe2016-01-28 05:22:45 -08003325 // We should get the frequency we ask for.
3326 if (_outputFilePlayerPtr->Get10msAudioFromFile(
3327 fileBuffer.get(), fileSamples, mixingFrequency) == -1) {
3328 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3329 "Channel::MixAudioWithFile() file mixing failed");
3330 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003331 }
kwiberg55b97fe2016-01-28 05:22:45 -08003332 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003333
kwiberg55b97fe2016-01-28 05:22:45 -08003334 if (audioFrame.samples_per_channel_ == fileSamples) {
3335 // Currently file stream is always mono.
3336 // TODO(xians): Change the code when FilePlayer supports real stereo.
3337 MixWithSat(audioFrame.data_, audioFrame.num_channels_, fileBuffer.get(), 1,
3338 fileSamples);
3339 } else {
3340 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3341 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS
3342 ") != "
3343 "fileSamples(%" PRIuS ")",
3344 audioFrame.samples_per_channel_, fileSamples);
3345 return -1;
3346 }
3347
3348 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003349}
3350
kwiberg55b97fe2016-01-28 05:22:45 -08003351int Channel::InsertInbandDtmfTone() {
3352 // Check if we should start a new tone.
3353 if (_inbandDtmfQueue.PendingDtmf() && !_inbandDtmfGenerator.IsAddingTone() &&
3354 _inbandDtmfGenerator.DelaySinceLastTone() >
3355 kMinTelephoneEventSeparationMs) {
3356 int8_t eventCode(0);
3357 uint16_t lengthMs(0);
3358 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003359
kwiberg55b97fe2016-01-28 05:22:45 -08003360 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3361 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3362 if (_playInbandDtmfEvent) {
3363 // Add tone to output mixer using a reduced length to minimize
3364 // risk of echo.
3365 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80, attenuationDb);
3366 }
3367 }
3368
3369 if (_inbandDtmfGenerator.IsAddingTone()) {
3370 uint16_t frequency(0);
3371 _inbandDtmfGenerator.GetSampleRate(frequency);
3372
3373 if (frequency != _audioFrame.sample_rate_hz_) {
3374 // Update sample rate of Dtmf tone since the mixing frequency
3375 // has changed.
3376 _inbandDtmfGenerator.SetSampleRate(
3377 (uint16_t)(_audioFrame.sample_rate_hz_));
3378 // Reset the tone to be added taking the new sample rate into
3379 // account.
3380 _inbandDtmfGenerator.ResetTone();
niklase@google.com470e71d2011-07-07 08:21:25 +00003381 }
3382
kwiberg55b97fe2016-01-28 05:22:45 -08003383 int16_t toneBuffer[320];
3384 uint16_t toneSamples(0);
3385 // Get 10ms tone segment and set time since last tone to zero
3386 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1) {
3387 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3388 "Channel::EncodeAndSend() inserting Dtmf failed");
3389 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003390 }
kwiberg55b97fe2016-01-28 05:22:45 -08003391
3392 // Replace mixed audio with DTMF tone.
3393 for (size_t sample = 0; sample < _audioFrame.samples_per_channel_;
3394 sample++) {
3395 for (size_t channel = 0; channel < _audioFrame.num_channels_; channel++) {
3396 const size_t index = sample * _audioFrame.num_channels_ + channel;
3397 _audioFrame.data_[index] = toneBuffer[sample];
3398 }
3399 }
3400
3401 assert(_audioFrame.samples_per_channel_ == toneSamples);
3402 } else {
3403 // Add 10ms to "delay-since-last-tone" counter
3404 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3405 }
3406 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003407}
3408
deadbeef74375882015-08-13 12:09:10 -07003409void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3410 uint32_t playout_timestamp = 0;
3411
kwiberg55b97fe2016-01-28 05:22:45 -08003412 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
deadbeef74375882015-08-13 12:09:10 -07003413 // This can happen if this channel has not been received any RTP packet. In
3414 // this case, NetEq is not capable of computing playout timestamp.
3415 return;
3416 }
3417
3418 uint16_t delay_ms = 0;
3419 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
kwiberg55b97fe2016-01-28 05:22:45 -08003420 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
deadbeef74375882015-08-13 12:09:10 -07003421 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3422 " delay from the ADM");
3423 _engineStatisticsPtr->SetLastError(
3424 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3425 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3426 return;
3427 }
3428
3429 jitter_buffer_playout_timestamp_ = playout_timestamp;
3430
3431 // Remove the playout delay.
3432 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3433
kwiberg55b97fe2016-01-28 05:22:45 -08003434 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
deadbeef74375882015-08-13 12:09:10 -07003435 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3436 playout_timestamp);
3437
3438 {
tommi31fc21f2016-01-21 10:37:37 -08003439 rtc::CritScope lock(&video_sync_lock_);
deadbeef74375882015-08-13 12:09:10 -07003440 if (rtcp) {
3441 playout_timestamp_rtcp_ = playout_timestamp;
3442 } else {
3443 playout_timestamp_rtp_ = playout_timestamp;
3444 }
3445 playout_delay_ms_ = delay_ms;
3446 }
3447}
3448
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003449// Called for incoming RTP packets after successful RTP header parsing.
3450void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3451 uint16_t sequence_number) {
kwiberg55b97fe2016-01-28 05:22:45 -08003452 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003453 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3454 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003455
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003456 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003457 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003458
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003459 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3460 // every incoming packet.
kwiberg55b97fe2016-01-28 05:22:45 -08003461 uint32_t timestamp_diff_ms =
3462 (rtp_timestamp - jitter_buffer_playout_timestamp_) /
3463 (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003464 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3465 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3466 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3467 // timestamp, the resulting difference is negative, but is set to zero.
3468 // This can happen when a network glitch causes a packet to arrive late,
3469 // and during long comfort noise periods with clock drift.
3470 timestamp_diff_ms = 0;
3471 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003472
kwiberg55b97fe2016-01-28 05:22:45 -08003473 uint16_t packet_delay_ms =
3474 (rtp_timestamp - _previousTimestamp) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003475
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003476 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003477
kwiberg55b97fe2016-01-28 05:22:45 -08003478 if (timestamp_diff_ms == 0)
3479 return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003480
deadbeef74375882015-08-13 12:09:10 -07003481 {
tommi31fc21f2016-01-21 10:37:37 -08003482 rtc::CritScope lock(&video_sync_lock_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003483
deadbeef74375882015-08-13 12:09:10 -07003484 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3485 _recPacketDelayMs = packet_delay_ms;
3486 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003487
deadbeef74375882015-08-13 12:09:10 -07003488 if (_average_jitter_buffer_delay_us == 0) {
3489 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3490 return;
3491 }
3492
3493 // Filter average delay value using exponential filter (alpha is
3494 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3495 // risk of rounding error) and compensate for it in GetDelayEstimate()
3496 // later.
kwiberg55b97fe2016-01-28 05:22:45 -08003497 _average_jitter_buffer_delay_us =
3498 (_average_jitter_buffer_delay_us * 7 + 1000 * timestamp_diff_ms + 500) /
3499 8;
deadbeef74375882015-08-13 12:09:10 -07003500 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003501}
3502
kwiberg55b97fe2016-01-28 05:22:45 -08003503void Channel::RegisterReceiveCodecsToRTPModule() {
3504 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3505 "Channel::RegisterReceiveCodecsToRTPModule()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003506
kwiberg55b97fe2016-01-28 05:22:45 -08003507 CodecInst codec;
3508 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003509
kwiberg55b97fe2016-01-28 05:22:45 -08003510 for (int idx = 0; idx < nSupportedCodecs; idx++) {
3511 // Open up the RTP/RTCP receiver for all supported codecs
3512 if ((audio_coding_->Codec(idx, &codec) == -1) ||
3513 (rtp_receiver_->RegisterReceivePayload(
3514 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3515 (codec.rate < 0) ? 0 : codec.rate) == -1)) {
3516 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3517 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3518 " to register %s (%d/%d/%" PRIuS
3519 "/%d) to RTP/RTCP "
3520 "receiver",
3521 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3522 codec.rate);
3523 } else {
3524 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3525 "Channel::RegisterReceiveCodecsToRTPModule() %s "
3526 "(%d/%d/%" PRIuS
3527 "/%d) has been added to the RTP/RTCP "
3528 "receiver",
3529 codec.plname, codec.pltype, codec.plfreq, codec.channels,
3530 codec.rate);
niklase@google.com470e71d2011-07-07 08:21:25 +00003531 }
kwiberg55b97fe2016-01-28 05:22:45 -08003532 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003533}
3534
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003535// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003536int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003537 CodecInst codec;
3538 bool found_red = false;
3539
3540 // Get default RED settings from the ACM database
3541 const int num_codecs = AudioCodingModule::NumberOfCodecs();
3542 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003543 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003544 if (!STR_CASE_CMP(codec.plname, "RED")) {
3545 found_red = true;
3546 break;
3547 }
3548 }
3549
3550 if (!found_red) {
3551 _engineStatisticsPtr->SetLastError(
3552 VE_CODEC_ERROR, kTraceError,
3553 "SetRedPayloadType() RED is not supported");
3554 return -1;
3555 }
3556
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00003557 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003558 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003559 _engineStatisticsPtr->SetLastError(
3560 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3561 "SetRedPayloadType() RED registration in ACM module failed");
3562 return -1;
3563 }
3564
3565 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
3566 _engineStatisticsPtr->SetLastError(
3567 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3568 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
3569 return -1;
3570 }
3571 return 0;
3572}
3573
kwiberg55b97fe2016-01-28 05:22:45 -08003574int Channel::SetSendRtpHeaderExtension(bool enable,
3575 RTPExtensionType type,
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003576 unsigned char id) {
3577 int error = 0;
3578 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
3579 if (enable) {
3580 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
3581 }
3582 return error;
3583}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003584
wu@webrtc.org94454b72014-06-05 20:34:08 +00003585int32_t Channel::GetPlayoutFrequency() {
3586 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
3587 CodecInst current_recive_codec;
3588 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
3589 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3590 // Even though the actual sampling rate for G.722 audio is
3591 // 16,000 Hz, the RTP clock rate for the G722 payload format is
3592 // 8,000 Hz because that value was erroneously assigned in
3593 // RFC 1890 and must remain unchanged for backward compatibility.
3594 playout_frequency = 8000;
3595 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3596 // We are resampling Opus internally to 32,000 Hz until all our
3597 // DSP routines can operate at 48,000 Hz, but the RTP clock
3598 // rate for the Opus payload format is standardized to 48,000 Hz,
3599 // because that is the maximum supported decoding sampling rate.
3600 playout_frequency = 48000;
3601 }
3602 }
3603 return playout_frequency;
3604}
3605
Minyue2013aec2015-05-13 14:14:42 +02003606int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07003607 RtcpMode method = _rtpRtcpModule->RTCP();
3608 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003609 return 0;
3610 }
3611 std::vector<RTCPReportBlock> report_blocks;
3612 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02003613
3614 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003615 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02003616 if (allow_associate_channel) {
tommi31fc21f2016-01-21 10:37:37 -08003617 rtc::CritScope lock(&assoc_send_channel_lock_);
Minyue2013aec2015-05-13 14:14:42 +02003618 Channel* channel = associate_send_channel_.channel();
3619 // Tries to get RTT from an associated channel. This is important for
3620 // receive-only channels.
3621 if (channel) {
3622 // To prevent infinite recursion and deadlock, calling GetRTT of
3623 // associate channel should always use "false" for argument:
3624 // |allow_associate_channel|.
3625 rtt = channel->GetRTT(false);
3626 }
3627 }
3628 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003629 }
3630
3631 uint32_t remoteSSRC = rtp_receiver_->SSRC();
3632 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
3633 for (; it != report_blocks.end(); ++it) {
3634 if (it->remoteSSRC == remoteSSRC)
3635 break;
3636 }
3637 if (it == report_blocks.end()) {
3638 // We have not received packets with SSRC matching the report blocks.
3639 // To calculate RTT we try with the SSRC of the first report block.
3640 // This is very important for send-only channels where we don't know
3641 // the SSRC of the other end.
3642 remoteSSRC = report_blocks[0].remoteSSRC;
3643 }
Minyue2013aec2015-05-13 14:14:42 +02003644
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003645 int64_t avg_rtt = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08003646 int64_t max_rtt = 0;
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003647 int64_t min_rtt = 0;
kwiberg55b97fe2016-01-28 05:22:45 -08003648 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt) !=
3649 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003650 return 0;
3651 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003652 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003653}
3654
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00003655} // namespace voe
3656} // namespace webrtc