blob: 7b9a803a2df06dd3c807abcb24d20e5d534336e5 [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"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000017#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080018#include "webrtc/base/logging.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010019#include "webrtc/base/thread_checker.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000020#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000021#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020022#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000023#include "webrtc/modules/audio_device/include/audio_device.h"
24#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010025#include "webrtc/modules/include/module_common_types.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010026#include "webrtc/modules/pacing/packet_router.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010027#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
28#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
29#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000030#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010031#include "webrtc/modules/utility/include/audio_frame_operations.h"
32#include "webrtc/modules/utility/include/process_thread.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010033#include "webrtc/system_wrappers/include/critical_section_wrapper.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:
119 RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {
120 }
121
122 void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
123 RTC_DCHECK(thread_checker_.CalledOnValidThread());
124 rtc::CritScope lock(&crit_);
125 rtp_packet_sender_ = rtp_packet_sender;
126 }
127
128 // Implements RtpPacketSender.
129 void InsertPacket(Priority priority,
130 uint32_t ssrc,
131 uint16_t sequence_number,
132 int64_t capture_time_ms,
133 size_t bytes,
134 bool retransmission) override {
135 rtc::CritScope lock(&crit_);
136 if (rtp_packet_sender_) {
137 rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
138 capture_time_ms, bytes, retransmission);
139 }
140 }
141
142 private:
143 rtc::ThreadChecker thread_checker_;
144 rtc::CriticalSection crit_;
145 RtpPacketSender* rtp_packet_sender_ GUARDED_BY(&crit_);
146};
147
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000148// Extend the default RTCP statistics struct with max_jitter, defined as the
149// maximum jitter value seen in an RTCP report block.
150struct ChannelStatistics : public RtcpStatistics {
151 ChannelStatistics() : rtcp(), max_jitter(0) {}
152
153 RtcpStatistics rtcp;
154 uint32_t max_jitter;
155};
156
157// Statistics callback, called at each generation of a new RTCP report block.
158class StatisticsProxy : public RtcpStatisticsCallback {
159 public:
160 StatisticsProxy(uint32_t ssrc)
161 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
162 ssrc_(ssrc) {}
163 virtual ~StatisticsProxy() {}
164
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000165 void StatisticsUpdated(const RtcpStatistics& statistics,
166 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000167 if (ssrc != ssrc_)
168 return;
169
170 CriticalSectionScoped cs(stats_lock_.get());
171 stats_.rtcp = statistics;
172 if (statistics.jitter > stats_.max_jitter) {
173 stats_.max_jitter = statistics.jitter;
174 }
175 }
176
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000177 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000178
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000179 ChannelStatistics GetStats() {
180 CriticalSectionScoped cs(stats_lock_.get());
181 return stats_;
182 }
183
184 private:
185 // StatisticsUpdated calls are triggered from threads in the RTP module,
186 // while GetStats calls can be triggered from the public voice engine API,
187 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000188 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000189 const uint32_t ssrc_;
190 ChannelStatistics stats_;
191};
192
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000193class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000194 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000195 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
196 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000197
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000198 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
199 // Not used for Voice Engine.
200 }
201
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000202 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
203 int64_t rtt,
204 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000205 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
206 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
207 // report for VoiceEngine?
208 if (report_blocks.empty())
209 return;
210
211 int fraction_lost_aggregate = 0;
212 int total_number_of_packets = 0;
213
214 // If receiving multiple report blocks, calculate the weighted average based
215 // on the number of packets a report refers to.
216 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
217 block_it != report_blocks.end(); ++block_it) {
218 // Find the previous extended high sequence number for this remote SSRC,
219 // to calculate the number of RTP packets this report refers to. Ignore if
220 // we haven't seen this SSRC before.
221 std::map<uint32_t, uint32_t>::iterator seq_num_it =
222 extended_max_sequence_number_.find(block_it->sourceSSRC);
223 int number_of_packets = 0;
224 if (seq_num_it != extended_max_sequence_number_.end()) {
225 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
226 }
227 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
228 total_number_of_packets += number_of_packets;
229
230 extended_max_sequence_number_[block_it->sourceSSRC] =
231 block_it->extendedHighSeqNum;
232 }
233 int weighted_fraction_lost = 0;
234 if (total_number_of_packets > 0) {
235 weighted_fraction_lost = (fraction_lost_aggregate +
236 total_number_of_packets / 2) / total_number_of_packets;
237 }
238 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000239 }
240
241 private:
242 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000243 // Maps remote side ssrc to extended highest sequence number received.
244 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000245};
246
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000247int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000248Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000249 uint8_t payloadType,
250 uint32_t timeStamp,
251 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000252 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 const RTPFragmentationHeader* fragmentation)
254{
255 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
256 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000257 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
258 frameType, payloadType, timeStamp,
259 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000260
261 if (_includeAudioLevelIndication)
262 {
263 // Store current audio level in the RTP/RTCP module.
264 // The level will be used in combination with voice-activity state
265 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000266 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000267 }
268
269 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
270 // packetization.
271 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000272 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 payloadType,
274 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000275 // Leaving the time when this frame was
276 // received from the capture device as
277 // undefined for voice for now.
278 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 payloadData,
280 payloadSize,
281 fragmentation) == -1)
282 {
283 _engineStatisticsPtr->SetLastError(
284 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
285 "Channel::SendData() failed to send data to RTP/RTCP module");
286 return -1;
287 }
288
289 _lastLocalTimeStamp = timeStamp;
290 _lastPayloadType = payloadType;
291
292 return 0;
293}
294
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000295int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000296Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000297{
298 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000299 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000300
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000301 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000302 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000303 return 0;
304}
305
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000306int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000307Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000308{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000309 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 if (_rxVadObserverPtr)
311 {
312 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
313 }
314
315 return 0;
316}
317
stefan1d8a5062015-10-02 03:39:33 -0700318bool Channel::SendRtp(const uint8_t* data,
319 size_t len,
320 const PacketOptions& options) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200322 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000323
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000324 CriticalSectionScoped cs(&_callbackCritSect);
325
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 if (_transportPtr == NULL)
327 {
328 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
329 "Channel::SendPacket() failed to send RTP packet due to"
330 " invalid transport object");
pbos2d566682015-09-28 09:59:31 -0700331 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000332 }
333
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000334 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000335 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000336
stefan1d8a5062015-10-02 03:39:33 -0700337 if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000338 std::string transport_name =
339 _externalTransport ? "external transport" : "WebRtc sockets";
340 WEBRTC_TRACE(kTraceError, kTraceVoice,
341 VoEId(_instanceId,_channelId),
342 "Channel::SendPacket() RTP transmission using %s failed",
343 transport_name.c_str());
pbos2d566682015-09-28 09:59:31 -0700344 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 }
pbos2d566682015-09-28 09:59:31 -0700346 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000347}
348
pbos2d566682015-09-28 09:59:31 -0700349bool
350Channel::SendRtcp(const uint8_t *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000351{
niklase@google.com470e71d2011-07-07 08:21:25 +0000352 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700353 "Channel::SendRtcp(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000355 CriticalSectionScoped cs(&_callbackCritSect);
356 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000357 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000358 WEBRTC_TRACE(kTraceError, kTraceVoice,
359 VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700360 "Channel::SendRtcp() failed to send RTCP packet"
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000361 " due to invalid transport object");
pbos2d566682015-09-28 09:59:31 -0700362 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 }
364
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000365 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000366 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
pbos2d566682015-09-28 09:59:31 -0700368 int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000369 if (n < 0) {
370 std::string transport_name =
371 _externalTransport ? "external transport" : "WebRtc sockets";
372 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
373 VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700374 "Channel::SendRtcp() transmission using %s failed",
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000375 transport_name.c_str());
pbos2d566682015-09-28 09:59:31 -0700376 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 }
pbos2d566682015-09-28 09:59:31 -0700378 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000379}
380
Peter Boströmac547a62015-09-17 23:03:57 +0200381void Channel::OnPlayTelephoneEvent(uint8_t event,
382 uint16_t lengthMs,
383 uint8_t volume) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200385 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
386 " volume=%u)", event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000387
388 if (!_playOutbandDtmfEvent || (event > 15))
389 {
390 // Ignore callback since feedback is disabled or event is not a
391 // Dtmf tone event.
392 return;
393 }
394
395 assert(_outputMixerPtr != NULL);
396
397 // Start playing out the Dtmf tone (if playout is enabled).
398 // Reduce length of tone with 80ms to the reduce risk of echo.
399 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
400}
401
402void
Peter Boströmac547a62015-09-17 23:03:57 +0200403Channel::OnIncomingSSRCChanged(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000404{
405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200406 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000407
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000408 // Update ssrc so that NTP for AV sync can be updated.
409 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000410}
411
Peter Boströmac547a62015-09-17 23:03:57 +0200412void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
414 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
415 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000416}
417
Peter Boströmac547a62015-09-17 23:03:57 +0200418int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000419 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000420 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000421 int frequency,
Peter Kasting69558702016-01-12 16:26:35 -0800422 size_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200423 uint32_t rate) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200425 "Channel::OnInitializeDecoder(payloadType=%d, "
Peter Kasting69558702016-01-12 16:26:35 -0800426 "payloadName=%s, frequency=%u, channels=%" PRIuS ", rate=%u)",
Peter Boströmac547a62015-09-17 23:03:57 +0200427 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000429 CodecInst receiveCodec = {0};
430 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000431
432 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 receiveCodec.plfreq = frequency;
434 receiveCodec.channels = channels;
435 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000436 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000437
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000438 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 receiveCodec.pacsize = dummyCodec.pacsize;
440
441 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000442 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 {
444 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000445 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 "Channel::OnInitializeDecoder() invalid codec ("
447 "pt=%d, name=%s) received - 1", payloadType, payloadName);
448 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
449 return -1;
450 }
451
452 return 0;
453}
454
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000455int32_t
456Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000457 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000458 const WebRtcRTPHeader* rtpHeader)
459{
460 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000461 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
Peter Kasting69558702016-01-12 16:26:35 -0800462 " payloadType=%u, audioChannel=%" PRIuS ")",
niklase@google.com470e71d2011-07-07 08:21:25 +0000463 payloadSize,
464 rtpHeader->header.payloadType,
465 rtpHeader->type.Audio.channel);
466
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000467 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 {
469 // Avoid inserting into NetEQ when we are not playing. Count the
470 // packet as discarded.
471 WEBRTC_TRACE(kTraceStream, kTraceVoice,
472 VoEId(_instanceId, _channelId),
473 "received packet is discarded since playing is not"
474 " activated");
475 _numberOfDiscardedPackets++;
476 return 0;
477 }
478
479 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000480 if (audio_coding_->IncomingPacket(payloadData,
481 payloadSize,
482 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 {
484 _engineStatisticsPtr->SetLastError(
485 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
486 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
487 return -1;
488 }
489
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000490 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 UpdatePacketDelay(rtpHeader->header.timestamp,
492 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000493
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000494 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000495 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
496 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000497
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000498 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000499 round_trip_time);
500 if (!nack_list.empty()) {
501 // Can't use nack_list.data() since it's not supported by all
502 // compilers.
503 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000504 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 return 0;
506}
507
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000508bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000509 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000510 RTPHeader header;
511 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
512 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
513 "IncomingPacket invalid RTP header");
514 return false;
515 }
516 header.payload_type_frequency =
517 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
518 if (header.payload_type_frequency < 0)
519 return false;
520 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
521}
522
minyuel0f4b3732015-08-31 16:04:32 +0200523int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000524{
Ivo Creusenae856f22015-09-17 16:30:16 +0200525 if (event_log_) {
526 unsigned int ssrc;
527 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
528 event_log_->LogAudioPlayout(ssrc);
529 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200531 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
532 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 {
534 WEBRTC_TRACE(kTraceError, kTraceVoice,
535 VoEId(_instanceId,_channelId),
536 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000537 // In all likelihood, the audio in this frame is garbage. We return an
538 // error so that the audio mixer module doesn't add it to the mix. As
539 // a result, it won't be played out and the actions skipped here are
540 // irrelevant.
541 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 }
543
544 if (_RxVadDetection)
545 {
minyuel0f4b3732015-08-31 16:04:32 +0200546 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 }
548
549 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200550 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000551 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200552 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000553
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000554 ChannelState::State state = channel_state_.Get();
555
556 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200557 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000558 if (err) {
559 LOG(LS_ERROR) << "ProcessStream() error: " << err;
560 assert(false);
561 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000562 }
563
Tommif888bb52015-12-12 01:37:01 +0100564 {
565 // Pass the audio buffers to an optional sink callback, before applying
566 // scaling/panning, as that applies to the mix operation.
567 // External recipients of the audio (e.g. via AudioTrack), will do their
568 // own mixing/dynamic processing.
569 CriticalSectionScoped cs(&_callbackCritSect);
570 if (audio_sink_) {
571 AudioSinkInterface::Data data(
572 &audioFrame->data_[0],
573 audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
574 audioFrame->num_channels_, audioFrame->timestamp_);
575 audio_sink_->OnData(data);
576 }
577 }
578
wu@webrtc.org63420662013-10-17 18:28:55 +0000579 float output_gain = 1.0f;
580 float left_pan = 1.0f;
581 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000583 CriticalSectionScoped cs(&volume_settings_critsect_);
584 output_gain = _outputGain;
585 left_pan = _panLeft;
586 right_pan= _panRight;
587 }
588
589 // Output volume scaling
590 if (output_gain < 0.99f || output_gain > 1.01f)
591 {
minyuel0f4b3732015-08-31 16:04:32 +0200592 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 }
594
595 // Scale left and/or right channel(s) if stereo and master balance is
596 // active
597
wu@webrtc.org63420662013-10-17 18:28:55 +0000598 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 {
minyuel0f4b3732015-08-31 16:04:32 +0200600 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000601 {
602 // Emulate stereo mode since panning is active.
603 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200604 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 }
606 // For true stereo mode (when we are receiving a stereo signal), no
607 // action is needed.
608
609 // Do the panning operation (the audio frame contains stereo at this
610 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200611 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }
613
614 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000615 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 {
minyuel0f4b3732015-08-31 16:04:32 +0200617 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 }
619
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 // External media
621 if (_outputExternalMedia)
622 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000623 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200624 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 if (_outputExternalMediaCallbackPtr)
626 {
Tommif888bb52015-12-12 01:37:01 +0100627 _outputExternalMediaCallbackPtr->Process(
628 _channelId, kPlaybackPerChannel, (int16_t*)audioFrame->data_,
629 audioFrame->samples_per_channel_, audioFrame->sample_rate_hz_,
630 isStereo);
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 }
632 }
633
634 // Record playout if enabled
635 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000636 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000637
638 if (_outputFileRecording && _outputFileRecorderPtr)
639 {
minyuel0f4b3732015-08-31 16:04:32 +0200640 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 }
642 }
643
644 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200645 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000646
minyuel0f4b3732015-08-31 16:04:32 +0200647 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000648 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200649 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000650 }
651
652 if (capture_start_rtp_time_stamp_ >= 0) {
653 // audioFrame.timestamp_ should be valid from now on.
654
655 // Compute elapsed time.
656 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200657 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
658 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000659 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
660 (GetPlayoutFrequency() / 1000);
661
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000662 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000663 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000664 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200665 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
666 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000667 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200668 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000669 // Compute |capture_start_ntp_time_ms_| so that
670 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
671 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200672 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000673 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000674 }
675 }
676
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 return 0;
678}
679
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000680int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200681Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000682{
683 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
684 "Channel::NeededFrequency(id=%d)", id);
685
686 int highestNeeded = 0;
687
688 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000689 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000690
691 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000692 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000693 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000694 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 }
696 else
697 {
698 highestNeeded = receiveFrequency;
699 }
700
701 // Special case, if we're playing a file on the playout side
702 // we take that frequency into consideration as well
703 // This is not needed on sending side, since the codec will
704 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000705 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000707 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000708 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 {
710 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
711 {
712 highestNeeded=_outputFilePlayerPtr->Frequency();
713 }
714 }
715 }
716
717 return(highestNeeded);
718}
719
ivocb04965c2015-09-09 00:09:43 -0700720int32_t Channel::CreateChannel(Channel*& channel,
721 int32_t channelId,
722 uint32_t instanceId,
723 RtcEventLog* const event_log,
724 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000725 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
726 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
727 channelId, instanceId);
728
ivocb04965c2015-09-09 00:09:43 -0700729 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 if (channel == NULL)
731 {
732 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
733 VoEId(instanceId,channelId),
734 "Channel::CreateChannel() unable to allocate memory for"
735 " channel");
736 return -1;
737 }
738 return 0;
739}
740
741void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000742Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000743{
744 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
745 "Channel::PlayNotification(id=%d, durationMs=%d)",
746 id, durationMs);
747
748 // Not implement yet
749}
750
751void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000752Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000753{
754 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
755 "Channel::RecordNotification(id=%d, durationMs=%d)",
756 id, durationMs);
757
758 // Not implement yet
759}
760
761void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000762Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000763{
764 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
765 "Channel::PlayFileEnded(id=%d)", id);
766
767 if (id == _inputFilePlayerId)
768 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000769 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
771 VoEId(_instanceId,_channelId),
772 "Channel::PlayFileEnded() => input file player module is"
773 " shutdown");
774 }
775 else if (id == _outputFilePlayerId)
776 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000777 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
779 VoEId(_instanceId,_channelId),
780 "Channel::PlayFileEnded() => output file player module is"
781 " shutdown");
782 }
783}
784
785void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000786Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000787{
788 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
789 "Channel::RecordFileEnded(id=%d)", id);
790
791 assert(id == _outputFileRecorderId);
792
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000793 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
795 _outputFileRecording = false;
796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
797 VoEId(_instanceId,_channelId),
798 "Channel::RecordFileEnded() => output file recorder module is"
799 " shutdown");
800}
801
pbos@webrtc.org92135212013-05-14 08:31:39 +0000802Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000803 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700804 RtcEventLog* const event_log,
805 const Config& config)
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100806 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
807 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
808 volume_settings_critsect_(
809 *CriticalSectionWrapper::CreateCriticalSection()),
810 _instanceId(instanceId),
811 _channelId(channelId),
812 event_log_(event_log),
813 rtp_header_parser_(RtpHeaderParser::Create()),
814 rtp_payload_registry_(
815 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
816 rtp_receive_statistics_(
817 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
818 rtp_receiver_(
819 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
820 this,
821 this,
822 this,
823 rtp_payload_registry_.get())),
824 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
825 _outputAudioLevel(),
826 _externalTransport(false),
827 _inputFilePlayerPtr(NULL),
828 _outputFilePlayerPtr(NULL),
829 _outputFileRecorderPtr(NULL),
830 // Avoid conflict with other channels by adding 1024 - 1026,
831 // won't use as much as 1024 channels.
832 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
833 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
834 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
835 _outputFileRecording(false),
836 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
837 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
838 _outputExternalMedia(false),
839 _inputExternalMediaCallbackPtr(NULL),
840 _outputExternalMediaCallbackPtr(NULL),
841 _timeStamp(0), // This is just an offset, RTP module will add it's own
842 // random offset
843 _sendTelephoneEventPayloadType(106),
844 ntp_estimator_(Clock::GetRealTimeClock()),
845 jitter_buffer_playout_timestamp_(0),
846 playout_timestamp_rtp_(0),
847 playout_timestamp_rtcp_(0),
848 playout_delay_ms_(0),
849 _numberOfDiscardedPackets(0),
850 send_sequence_number_(0),
851 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
852 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
853 capture_start_rtp_time_stamp_(-1),
854 capture_start_ntp_time_ms_(-1),
855 _engineStatisticsPtr(NULL),
856 _outputMixerPtr(NULL),
857 _transmitMixerPtr(NULL),
858 _moduleProcessThreadPtr(NULL),
859 _audioDeviceModulePtr(NULL),
860 _voiceEngineObserverPtr(NULL),
861 _callbackCritSectPtr(NULL),
862 _transportPtr(NULL),
863 _rxVadObserverPtr(NULL),
864 _oldVadDecision(-1),
865 _sendFrameType(0),
866 _externalMixing(false),
867 _mixFileWithMicrophone(false),
868 _mute(false),
869 _panLeft(1.0f),
870 _panRight(1.0f),
871 _outputGain(1.0f),
872 _playOutbandDtmfEvent(false),
873 _playInbandDtmfEvent(false),
874 _lastLocalTimeStamp(0),
875 _lastPayloadType(0),
876 _includeAudioLevelIndication(false),
877 _outputSpeechType(AudioFrame::kNormalSpeech),
878 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
879 _average_jitter_buffer_delay_us(0),
880 _previousTimestamp(0),
881 _recPacketDelayMs(20),
882 _RxVadDetection(false),
883 _rxAgcIsEnabled(false),
884 _rxNsIsEnabled(false),
885 restored_packet_in_use_(false),
886 rtcp_observer_(new VoERtcpObserver(this)),
887 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
888 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
889 associate_send_channel_(ChannelOwner(nullptr)),
890 pacing_enabled_(config.Get<VoicePacing>().enabled),
891 feedback_observer_proxy_(pacing_enabled_ ? new TransportFeedbackProxy()
892 : nullptr),
893 seq_num_allocator_proxy_(
894 pacing_enabled_ ? new TransportSequenceNumberProxy() : nullptr),
895 rtp_packet_sender_proxy_(pacing_enabled_ ? new RtpPacketSenderProxy()
896 : nullptr) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
898 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200899 AudioCodingModule::Config acm_config;
900 acm_config.id = VoEModuleId(instanceId, channelId);
901 if (config.Get<NetEqCapacityConfig>().enabled) {
902 // Clamping the buffer capacity at 20 packets. While going lower will
903 // probably work, it makes little sense.
904 acm_config.neteq_config.max_packets_in_buffer =
905 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
906 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200907 acm_config.neteq_config.enable_fast_accelerate =
908 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200909 audio_coding_.reset(AudioCodingModule::Create(acm_config));
910
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 _inbandDtmfQueue.ResetDtmf();
912 _inbandDtmfGenerator.Init();
913 _outputAudioLevel.Clear();
914
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000915 RtpRtcp::Configuration configuration;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000916 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000917 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000918 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000919 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000920 configuration.bandwidth_callback = rtcp_observer_.get();
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100921 configuration.paced_sender = rtp_packet_sender_proxy_.get();
922 configuration.transport_sequence_number_allocator =
923 seq_num_allocator_proxy_.get();
924 configuration.transport_feedback_callback = feedback_observer_proxy_.get();
terelius429c3452016-01-21 05:42:04 -0800925 configuration.event_log = event_log;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000926
927 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000928
929 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
930 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
931 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000932
933 Config audioproc_config;
934 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
935 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000936}
937
938Channel::~Channel()
939{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000940 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
942 "Channel::~Channel() - dtor");
943
944 if (_outputExternalMedia)
945 {
946 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
947 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000948 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 {
950 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
951 }
952 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 StopPlayout();
954
955 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000956 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 if (_inputFilePlayerPtr)
958 {
959 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
960 _inputFilePlayerPtr->StopPlayingFile();
961 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
962 _inputFilePlayerPtr = NULL;
963 }
964 if (_outputFilePlayerPtr)
965 {
966 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
967 _outputFilePlayerPtr->StopPlayingFile();
968 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
969 _outputFilePlayerPtr = NULL;
970 }
971 if (_outputFileRecorderPtr)
972 {
973 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
974 _outputFileRecorderPtr->StopRecording();
975 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
976 _outputFileRecorderPtr = NULL;
977 }
978 }
979
980 // The order to safely shutdown modules in a channel is:
981 // 1. De-register callbacks in modules
982 // 2. De-register modules in process thread
983 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000984 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000985 {
986 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
987 VoEId(_instanceId,_channelId),
988 "~Channel() failed to de-register transport callback"
989 " (Audio coding module)");
990 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000991 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
993 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
994 VoEId(_instanceId,_channelId),
995 "~Channel() failed to de-register VAD callback"
996 " (Audio coding module)");
997 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000999 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
1000
niklase@google.com470e71d2011-07-07 08:21:25 +00001001 // End of modules shutdown
1002
1003 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001006 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001007}
1008
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001009int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001010Channel::Init()
1011{
1012 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1013 "Channel::Init()");
1014
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001015 channel_state_.Reset();
1016
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 // --- Initial sanity
1018
1019 if ((_engineStatisticsPtr == NULL) ||
1020 (_moduleProcessThreadPtr == NULL))
1021 {
1022 WEBRTC_TRACE(kTraceError, kTraceVoice,
1023 VoEId(_instanceId,_channelId),
1024 "Channel::Init() must call SetEngineInformation() first");
1025 return -1;
1026 }
1027
1028 // --- Add modules to process thread (for periodic schedulation)
1029
tommi@webrtc.org3985f012015-02-27 13:36:34 +00001030 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
1031
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001032 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001033
henrik.lundin061b79a2015-09-18 01:29:11 -07001034 if (audio_coding_->InitializeReceiver() == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 _engineStatisticsPtr->SetLastError(
1036 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1037 "Channel::Init() unable to initialize the ACM - 1");
1038 return -1;
1039 }
1040
1041 // --- RTP/RTCP module initialization
1042
1043 // Ensure that RTCP is enabled by default for the created channel.
1044 // Note that, the module will keep generating RTCP until it is explicitly
1045 // disabled by the user.
1046 // After StopListen (when no sockets exists), RTCP packets will no longer
1047 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001048 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1049 // RTCP is enabled by default.
pbosda903ea2015-10-02 02:36:56 -07001050 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001051 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001053 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1054 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001055
1056 if (fail)
1057 {
1058 _engineStatisticsPtr->SetLastError(
1059 VE_CANNOT_INIT_CHANNEL, kTraceError,
1060 "Channel::Init() callbacks not registered");
1061 return -1;
1062 }
1063
1064 // --- Register all supported codecs to the receiving side of the
1065 // RTP/RTCP module
1066
1067 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001068 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001069
1070 for (int idx = 0; idx < nSupportedCodecs; idx++)
1071 {
1072 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001073 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001074 (rtp_receiver_->RegisterReceivePayload(
1075 codec.plname,
1076 codec.pltype,
1077 codec.plfreq,
1078 codec.channels,
1079 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 {
1081 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1082 VoEId(_instanceId,_channelId),
Peter Kasting69558702016-01-12 16:26:35 -08001083 "Channel::Init() unable to register %s "
1084 "(%d/%d/%" PRIuS "/%d) to RTP/RTCP receiver",
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 codec.plname, codec.pltype, codec.plfreq,
1086 codec.channels, codec.rate);
1087 }
1088 else
1089 {
1090 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1091 VoEId(_instanceId,_channelId),
Peter Kasting69558702016-01-12 16:26:35 -08001092 "Channel::Init() %s (%d/%d/%" PRIuS "/%d) has been "
1093 "added to the RTP/RTCP receiver",
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 codec.plname, codec.pltype, codec.plfreq,
1095 codec.channels, codec.rate);
1096 }
1097
1098 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001099 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 {
1101 SetSendCodec(codec);
1102 }
1103
1104 // Register default PT for outband 'telephone-event'
1105 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1106 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001107 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001108 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 {
1110 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1111 VoEId(_instanceId,_channelId),
1112 "Channel::Init() failed to register outband "
1113 "'telephone-event' (%d/%d) correctly",
1114 codec.pltype, codec.plfreq);
1115 }
1116 }
1117
1118 if (!STR_CASE_CMP(codec.plname, "CN"))
1119 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001120 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1121 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001122 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 {
1124 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1125 VoEId(_instanceId,_channelId),
1126 "Channel::Init() failed to register CN (%d/%d) "
1127 "correctly - 1",
1128 codec.pltype, codec.plfreq);
1129 }
1130 }
1131#ifdef WEBRTC_CODEC_RED
1132 // Register RED to the receiving side of the ACM.
1133 // We will not receive an OnInitializeDecoder() callback for RED.
1134 if (!STR_CASE_CMP(codec.plname, "RED"))
1135 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001136 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 {
1138 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1139 VoEId(_instanceId,_channelId),
1140 "Channel::Init() failed to register RED (%d/%d) "
1141 "correctly",
1142 codec.pltype, codec.plfreq);
1143 }
1144 }
1145#endif
1146 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001147
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001148 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001149 LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001150 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001151 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001152 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001153 LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001154 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001155 }
1156
1157 return 0;
1158}
1159
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001160int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001161Channel::SetEngineInformation(Statistics& engineStatistics,
1162 OutputMixer& outputMixer,
1163 voe::TransmitMixer& transmitMixer,
1164 ProcessThread& moduleProcessThread,
1165 AudioDeviceModule& audioDeviceModule,
1166 VoiceEngineObserver* voiceEngineObserver,
1167 CriticalSectionWrapper* callbackCritSect)
1168{
1169 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1170 "Channel::SetEngineInformation()");
1171 _engineStatisticsPtr = &engineStatistics;
1172 _outputMixerPtr = &outputMixer;
1173 _transmitMixerPtr = &transmitMixer,
1174 _moduleProcessThreadPtr = &moduleProcessThread;
1175 _audioDeviceModulePtr = &audioDeviceModule;
1176 _voiceEngineObserverPtr = voiceEngineObserver;
1177 _callbackCritSectPtr = callbackCritSect;
1178 return 0;
1179}
1180
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001181int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001182Channel::UpdateLocalTimeStamp()
1183{
1184
Peter Kastingb7e50542015-06-11 12:55:50 -07001185 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 return 0;
1187}
1188
deadbeef2d110be2016-01-13 12:00:26 -08001189void Channel::SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) {
Tommif888bb52015-12-12 01:37:01 +01001190 CriticalSectionScoped cs(&_callbackCritSect);
deadbeef2d110be2016-01-13 12:00:26 -08001191 audio_sink_ = std::move(sink);
Tommif888bb52015-12-12 01:37:01 +01001192}
1193
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001194int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001195Channel::StartPlayout()
1196{
1197 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1198 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001199 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001200 {
1201 return 0;
1202 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001203
1204 if (!_externalMixing) {
1205 // Add participant as candidates for mixing.
1206 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1207 {
1208 _engineStatisticsPtr->SetLastError(
1209 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1210 "StartPlayout() failed to add participant to mixer");
1211 return -1;
1212 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 }
1214
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001215 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001216 if (RegisterFilePlayingToMixer() != 0)
1217 return -1;
1218
niklase@google.com470e71d2011-07-07 08:21:25 +00001219 return 0;
1220}
1221
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001222int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001223Channel::StopPlayout()
1224{
1225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1226 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001227 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001228 {
1229 return 0;
1230 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001231
1232 if (!_externalMixing) {
1233 // Remove participant as candidates for mixing
1234 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1235 {
1236 _engineStatisticsPtr->SetLastError(
1237 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1238 "StopPlayout() failed to remove participant from mixer");
1239 return -1;
1240 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 }
1242
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001243 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001244 _outputAudioLevel.Clear();
1245
1246 return 0;
1247}
1248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001249int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001250Channel::StartSend()
1251{
1252 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1253 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001254 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001255 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001256 if (send_sequence_number_)
1257 SetInitSequenceNumber(send_sequence_number_);
1258
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001259 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001261 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001263 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001264
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001265 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001266 {
1267 _engineStatisticsPtr->SetLastError(
1268 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1269 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001270 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001271 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 return -1;
1273 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001274
niklase@google.com470e71d2011-07-07 08:21:25 +00001275 return 0;
1276}
1277
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001278int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001279Channel::StopSend()
1280{
1281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1282 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001283 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001285 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001286 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001287 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001288
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001289 // Store the sequence number to be able to pick up the same sequence for
1290 // the next StartSend(). This is needed for restarting device, otherwise
1291 // it might cause libSRTP to complain about packets being replayed.
1292 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1293 // CL is landed. See issue
1294 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1295 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1296
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 // Reset sending SSRC and sequence number and triggers direct transmission
1298 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001299 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 {
1301 _engineStatisticsPtr->SetLastError(
1302 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1303 "StartSend() RTP/RTCP failed to stop sending");
1304 }
1305
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 return 0;
1307}
1308
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001309int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001310Channel::StartReceiving()
1311{
1312 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1313 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001314 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 {
1316 return 0;
1317 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001318 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 _numberOfDiscardedPackets = 0;
1320 return 0;
1321}
1322
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001323int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001324Channel::StopReceiving()
1325{
1326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1327 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001328 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001329 {
1330 return 0;
1331 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001332
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001333 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001334 return 0;
1335}
1336
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001337int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001338Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1339{
1340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1341 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001342 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001343
1344 if (_voiceEngineObserverPtr)
1345 {
1346 _engineStatisticsPtr->SetLastError(
1347 VE_INVALID_OPERATION, kTraceError,
1348 "RegisterVoiceEngineObserver() observer already enabled");
1349 return -1;
1350 }
1351 _voiceEngineObserverPtr = &observer;
1352 return 0;
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::DeRegisterVoiceEngineObserver()
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001360 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001361
1362 if (!_voiceEngineObserverPtr)
1363 {
1364 _engineStatisticsPtr->SetLastError(
1365 VE_INVALID_OPERATION, kTraceWarning,
1366 "DeRegisterVoiceEngineObserver() observer already disabled");
1367 return 0;
1368 }
1369 _voiceEngineObserverPtr = NULL;
1370 return 0;
1371}
1372
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001373int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001374Channel::GetSendCodec(CodecInst& codec)
1375{
kwiberg1fd4a4a2015-11-03 11:20:50 -08001376 auto send_codec = audio_coding_->SendCodec();
1377 if (send_codec) {
1378 codec = *send_codec;
1379 return 0;
1380 }
1381 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001382}
1383
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001384int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001385Channel::GetRecCodec(CodecInst& codec)
1386{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001387 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001388}
1389
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001390int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001391Channel::SetSendCodec(const CodecInst& codec)
1392{
1393 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1394 "Channel::SetSendCodec()");
1395
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001396 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001397 {
1398 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1399 "SetSendCodec() failed to register codec to ACM");
1400 return -1;
1401 }
1402
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001403 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001404 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001405 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1406 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 {
1408 WEBRTC_TRACE(
1409 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1410 "SetSendCodec() failed to register codec to"
1411 " RTP/RTCP module");
1412 return -1;
1413 }
1414 }
1415
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001416 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001417 {
1418 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1419 "SetSendCodec() failed to set audio packet size");
1420 return -1;
1421 }
1422
1423 return 0;
1424}
1425
Ivo Creusenadf89b72015-04-29 16:03:33 +02001426void Channel::SetBitRate(int bitrate_bps) {
1427 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1428 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1429 audio_coding_->SetBitRate(bitrate_bps);
1430}
1431
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001432void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001433 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001434 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1435
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001436 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001437 if (audio_coding_->SetPacketLossRate(
1438 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001439 assert(false); // This should not happen.
1440 }
1441}
1442
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001443int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001444Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1445{
1446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1447 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001448 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 // To disable VAD, DTX must be disabled too
1450 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001451 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
1453 _engineStatisticsPtr->SetLastError(
1454 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1455 "SetVADStatus() failed to set VAD");
1456 return -1;
1457 }
1458 return 0;
1459}
1460
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001461int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001462Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1463{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001464 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 {
1466 _engineStatisticsPtr->SetLastError(
1467 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1468 "GetVADStatus() failed to get VAD status");
1469 return -1;
1470 }
1471 disabledDTX = !disabledDTX;
1472 return 0;
1473}
1474
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001475int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001476Channel::SetRecPayloadType(const CodecInst& codec)
1477{
1478 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1479 "Channel::SetRecPayloadType()");
1480
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001481 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 {
1483 _engineStatisticsPtr->SetLastError(
1484 VE_ALREADY_PLAYING, kTraceError,
1485 "SetRecPayloadType() unable to set PT while playing");
1486 return -1;
1487 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001488 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001489 {
1490 _engineStatisticsPtr->SetLastError(
1491 VE_ALREADY_LISTENING, kTraceError,
1492 "SetRecPayloadType() unable to set PT while listening");
1493 return -1;
1494 }
1495
1496 if (codec.pltype == -1)
1497 {
1498 // De-register the selected codec (RTP/RTCP module and ACM)
1499
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001500 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 CodecInst rxCodec = codec;
1502
1503 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001504 rtp_payload_registry_->ReceivePayloadType(
1505 rxCodec.plname,
1506 rxCodec.plfreq,
1507 rxCodec.channels,
1508 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1509 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001510 rxCodec.pltype = pltype;
1511
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001512 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001513 {
1514 _engineStatisticsPtr->SetLastError(
1515 VE_RTP_RTCP_MODULE_ERROR,
1516 kTraceError,
1517 "SetRecPayloadType() RTP/RTCP-module deregistration "
1518 "failed");
1519 return -1;
1520 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001521 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001522 {
1523 _engineStatisticsPtr->SetLastError(
1524 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1525 "SetRecPayloadType() ACM deregistration failed - 1");
1526 return -1;
1527 }
1528 return 0;
1529 }
1530
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001531 if (rtp_receiver_->RegisterReceivePayload(
1532 codec.plname,
1533 codec.pltype,
1534 codec.plfreq,
1535 codec.channels,
1536 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 {
1538 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001539 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1540 if (rtp_receiver_->RegisterReceivePayload(
1541 codec.plname,
1542 codec.pltype,
1543 codec.plfreq,
1544 codec.channels,
1545 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001546 {
1547 _engineStatisticsPtr->SetLastError(
1548 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1549 "SetRecPayloadType() RTP/RTCP-module registration failed");
1550 return -1;
1551 }
1552 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001553 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001554 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001555 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1556 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001557 {
1558 _engineStatisticsPtr->SetLastError(
1559 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1560 "SetRecPayloadType() ACM registration failed - 1");
1561 return -1;
1562 }
1563 }
1564 return 0;
1565}
1566
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001567int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001568Channel::GetRecPayloadType(CodecInst& codec)
1569{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001571 if (rtp_payload_registry_->ReceivePayloadType(
1572 codec.plname,
1573 codec.plfreq,
1574 codec.channels,
1575 (codec.rate < 0) ? 0 : codec.rate,
1576 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001577 {
1578 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001579 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001580 "GetRecPayloadType() failed to retrieve RX payload type");
1581 return -1;
1582 }
1583 codec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001584 return 0;
1585}
1586
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001587int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001588Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1589{
1590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1591 "Channel::SetSendCNPayloadType()");
1592
1593 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001594 int32_t samplingFreqHz(-1);
Peter Kasting69558702016-01-12 16:26:35 -08001595 const size_t kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 if (frequency == kFreq32000Hz)
1597 samplingFreqHz = 32000;
1598 else if (frequency == kFreq16000Hz)
1599 samplingFreqHz = 16000;
1600
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001601 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001602 {
1603 _engineStatisticsPtr->SetLastError(
1604 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1605 "SetSendCNPayloadType() failed to retrieve default CN codec "
1606 "settings");
1607 return -1;
1608 }
1609
1610 // Modify the payload type (must be set to dynamic range)
1611 codec.pltype = type;
1612
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001613 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001614 {
1615 _engineStatisticsPtr->SetLastError(
1616 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1617 "SetSendCNPayloadType() failed to register CN to ACM");
1618 return -1;
1619 }
1620
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001621 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001622 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001623 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1624 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001625 {
1626 _engineStatisticsPtr->SetLastError(
1627 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1628 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1629 "module");
1630 return -1;
1631 }
1632 }
1633 return 0;
1634}
1635
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001636int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001637 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001638 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001639
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001640 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001641 _engineStatisticsPtr->SetLastError(
1642 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001643 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001644 return -1;
1645 }
1646 return 0;
1647}
1648
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001649int Channel::SetOpusDtx(bool enable_dtx) {
1650 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1651 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001652 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001653 : audio_coding_->DisableOpusDtx();
1654 if (ret != 0) {
1655 _engineStatisticsPtr->SetLastError(
1656 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1657 return -1;
1658 }
1659 return 0;
1660}
1661
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001662int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001663{
1664 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1665 "Channel::RegisterExternalTransport()");
1666
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001667 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001668
niklase@google.com470e71d2011-07-07 08:21:25 +00001669 if (_externalTransport)
1670 {
1671 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1672 kTraceError,
1673 "RegisterExternalTransport() external transport already enabled");
1674 return -1;
1675 }
1676 _externalTransport = true;
1677 _transportPtr = &transport;
1678 return 0;
1679}
1680
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001681int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001682Channel::DeRegisterExternalTransport()
1683{
1684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::DeRegisterExternalTransport()");
1686
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001687 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001688
niklase@google.com470e71d2011-07-07 08:21:25 +00001689 if (!_transportPtr)
1690 {
1691 _engineStatisticsPtr->SetLastError(
1692 VE_INVALID_OPERATION, kTraceWarning,
1693 "DeRegisterExternalTransport() external transport already "
1694 "disabled");
1695 return 0;
1696 }
1697 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001698 _transportPtr = NULL;
1699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1700 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001701 return 0;
1702}
1703
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001704int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001705 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001706 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1707 "Channel::ReceivedRTPPacket()");
1708
1709 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001710 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001711
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001712 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001713 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001714 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1715 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1716 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001717 return -1;
1718 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001719 header.payload_type_frequency =
1720 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001721 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001722 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001723 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001724 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001725 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001726 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001727
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001728 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001729}
1730
1731bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001732 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001733 const RTPHeader& header,
1734 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001735 if (rtp_payload_registry_->IsRtx(header)) {
1736 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001737 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001738 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001739 assert(packet_length >= header.headerLength);
1740 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001741 PayloadUnion payload_specific;
1742 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001743 &payload_specific)) {
1744 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001745 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001746 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1747 payload_specific, in_order);
1748}
1749
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001750bool Channel::HandleRtxPacket(const uint8_t* packet,
1751 size_t packet_length,
1752 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001753 if (!rtp_payload_registry_->IsRtx(header))
1754 return false;
1755
1756 // Remove the RTX header and parse the original RTP header.
1757 if (packet_length < header.headerLength)
1758 return false;
1759 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1760 return false;
1761 if (restored_packet_in_use_) {
1762 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1763 "Multiple RTX headers detected, dropping packet");
1764 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001765 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001766 if (!rtp_payload_registry_->RestoreOriginalPacket(
noahric65220a72015-10-14 11:29:49 -07001767 restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
1768 header)) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001769 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1770 "Incoming RTX packet: invalid RTP header");
1771 return false;
1772 }
1773 restored_packet_in_use_ = true;
noahric65220a72015-10-14 11:29:49 -07001774 bool ret = OnRecoveredPacket(restored_packet_, packet_length);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001775 restored_packet_in_use_ = false;
1776 return ret;
1777}
1778
1779bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1780 StreamStatistician* statistician =
1781 rtp_receive_statistics_->GetStatistician(header.ssrc);
1782 if (!statistician)
1783 return false;
1784 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001785}
1786
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001787bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1788 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001789 // Retransmissions are handled separately if RTX is enabled.
1790 if (rtp_payload_registry_->RtxEnabled())
1791 return false;
1792 StreamStatistician* statistician =
1793 rtp_receive_statistics_->GetStatistician(header.ssrc);
1794 if (!statistician)
1795 return false;
1796 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001797 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001798 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001799 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001800 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001801}
1802
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001803int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001804 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1805 "Channel::ReceivedRTCPPacket()");
1806 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001807 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001808
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001809 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001810 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001811 _engineStatisticsPtr->SetLastError(
1812 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1813 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1814 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001815
Minyue2013aec2015-05-13 14:14:42 +02001816 int64_t rtt = GetRTT(true);
1817 if (rtt == 0) {
1818 // Waiting for valid RTT.
1819 return 0;
1820 }
1821 uint32_t ntp_secs = 0;
1822 uint32_t ntp_frac = 0;
1823 uint32_t rtp_timestamp = 0;
1824 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1825 &rtp_timestamp)) {
1826 // Waiting for RTCP.
1827 return 0;
1828 }
1829
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001830 {
1831 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001832 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001833 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001834 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001835}
1836
niklase@google.com470e71d2011-07-07 08:21:25 +00001837int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001838 bool loop,
1839 FileFormats format,
1840 int startPosition,
1841 float volumeScaling,
1842 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001843 const CodecInst* codecInst)
1844{
1845 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1846 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1847 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1848 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1849 startPosition, stopPosition);
1850
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001851 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001852 {
1853 _engineStatisticsPtr->SetLastError(
1854 VE_ALREADY_PLAYING, kTraceError,
1855 "StartPlayingFileLocally() is already playing");
1856 return -1;
1857 }
1858
niklase@google.com470e71d2011-07-07 08:21:25 +00001859 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001860 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001861
1862 if (_outputFilePlayerPtr)
1863 {
1864 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1865 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1866 _outputFilePlayerPtr = NULL;
1867 }
1868
1869 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1870 _outputFilePlayerId, (const FileFormats)format);
1871
1872 if (_outputFilePlayerPtr == NULL)
1873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001876 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001877 return -1;
1878 }
1879
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001880 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001881
1882 if (_outputFilePlayerPtr->StartPlayingFile(
1883 fileName,
1884 loop,
1885 startPosition,
1886 volumeScaling,
1887 notificationTime,
1888 stopPosition,
1889 (const CodecInst*)codecInst) != 0)
1890 {
1891 _engineStatisticsPtr->SetLastError(
1892 VE_BAD_FILE, kTraceError,
1893 "StartPlayingFile() failed to start file playout");
1894 _outputFilePlayerPtr->StopPlayingFile();
1895 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1896 _outputFilePlayerPtr = NULL;
1897 return -1;
1898 }
1899 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001900 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001901 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001902
1903 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001904 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001905
1906 return 0;
1907}
1908
1909int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001910 FileFormats format,
1911 int startPosition,
1912 float volumeScaling,
1913 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001914 const CodecInst* codecInst)
1915{
1916 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1917 "Channel::StartPlayingFileLocally(format=%d,"
1918 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1919 format, volumeScaling, startPosition, stopPosition);
1920
1921 if(stream == NULL)
1922 {
1923 _engineStatisticsPtr->SetLastError(
1924 VE_BAD_FILE, kTraceError,
1925 "StartPlayingFileLocally() NULL as input stream");
1926 return -1;
1927 }
1928
1929
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001930 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001931 {
1932 _engineStatisticsPtr->SetLastError(
1933 VE_ALREADY_PLAYING, kTraceError,
1934 "StartPlayingFileLocally() is already playing");
1935 return -1;
1936 }
1937
niklase@google.com470e71d2011-07-07 08:21:25 +00001938 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001939 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001940
1941 // Destroy the old instance
1942 if (_outputFilePlayerPtr)
1943 {
1944 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1945 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1946 _outputFilePlayerPtr = NULL;
1947 }
1948
1949 // Create the instance
1950 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1951 _outputFilePlayerId,
1952 (const FileFormats)format);
1953
1954 if (_outputFilePlayerPtr == NULL)
1955 {
1956 _engineStatisticsPtr->SetLastError(
1957 VE_INVALID_ARGUMENT, kTraceError,
1958 "StartPlayingFileLocally() filePlayer format isnot correct");
1959 return -1;
1960 }
1961
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001962 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001963
1964 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1965 volumeScaling,
1966 notificationTime,
1967 stopPosition, codecInst) != 0)
1968 {
1969 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1970 "StartPlayingFile() failed to "
1971 "start file playout");
1972 _outputFilePlayerPtr->StopPlayingFile();
1973 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1974 _outputFilePlayerPtr = NULL;
1975 return -1;
1976 }
1977 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001978 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001979 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001980
1981 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001982 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001983
niklase@google.com470e71d2011-07-07 08:21:25 +00001984 return 0;
1985}
1986
1987int Channel::StopPlayingFileLocally()
1988{
1989 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1990 "Channel::StopPlayingFileLocally()");
1991
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001992 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001993 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001994 return 0;
1995 }
1996
niklase@google.com470e71d2011-07-07 08:21:25 +00001997 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001998 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001999
2000 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2001 {
2002 _engineStatisticsPtr->SetLastError(
2003 VE_STOP_RECORDING_FAILED, kTraceError,
2004 "StopPlayingFile() could not stop playing");
2005 return -1;
2006 }
2007 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2008 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2009 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002010 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002011 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002012 // _fileCritSect cannot be taken while calling
2013 // SetAnonymousMixibilityStatus. Refer to comments in
2014 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002015 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2016 {
2017 _engineStatisticsPtr->SetLastError(
2018 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002019 "StopPlayingFile() failed to stop participant from playing as"
2020 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002021 return -1;
2022 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002023
2024 return 0;
2025}
2026
2027int Channel::IsPlayingFileLocally() const
2028{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002029 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002030}
2031
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002032int Channel::RegisterFilePlayingToMixer()
2033{
2034 // Return success for not registering for file playing to mixer if:
2035 // 1. playing file before playout is started on that channel.
2036 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002037 if (!channel_state_.Get().playing ||
2038 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002039 {
2040 return 0;
2041 }
2042
2043 // |_fileCritSect| cannot be taken while calling
2044 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2045 // frames can be pulled by the mixer. Since the frames are generated from
2046 // the file, _fileCritSect will be taken. This would result in a deadlock.
2047 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2048 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002049 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002050 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002051 _engineStatisticsPtr->SetLastError(
2052 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2053 "StartPlayingFile() failed to add participant as file to mixer");
2054 _outputFilePlayerPtr->StopPlayingFile();
2055 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2056 _outputFilePlayerPtr = NULL;
2057 return -1;
2058 }
2059
2060 return 0;
2061}
2062
niklase@google.com470e71d2011-07-07 08:21:25 +00002063int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002064 bool loop,
2065 FileFormats format,
2066 int startPosition,
2067 float volumeScaling,
2068 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002069 const CodecInst* codecInst)
2070{
2071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2072 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2073 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2074 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2075 startPosition, stopPosition);
2076
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002077 CriticalSectionScoped cs(&_fileCritSect);
2078
2079 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002080 {
2081 _engineStatisticsPtr->SetLastError(
2082 VE_ALREADY_PLAYING, kTraceWarning,
2083 "StartPlayingFileAsMicrophone() filePlayer is playing");
2084 return 0;
2085 }
2086
niklase@google.com470e71d2011-07-07 08:21:25 +00002087 // Destroy the old instance
2088 if (_inputFilePlayerPtr)
2089 {
2090 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2091 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2092 _inputFilePlayerPtr = NULL;
2093 }
2094
2095 // Create the instance
2096 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2097 _inputFilePlayerId, (const FileFormats)format);
2098
2099 if (_inputFilePlayerPtr == NULL)
2100 {
2101 _engineStatisticsPtr->SetLastError(
2102 VE_INVALID_ARGUMENT, kTraceError,
2103 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2104 return -1;
2105 }
2106
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002107 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002108
2109 if (_inputFilePlayerPtr->StartPlayingFile(
2110 fileName,
2111 loop,
2112 startPosition,
2113 volumeScaling,
2114 notificationTime,
2115 stopPosition,
2116 (const CodecInst*)codecInst) != 0)
2117 {
2118 _engineStatisticsPtr->SetLastError(
2119 VE_BAD_FILE, kTraceError,
2120 "StartPlayingFile() failed to start file playout");
2121 _inputFilePlayerPtr->StopPlayingFile();
2122 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2123 _inputFilePlayerPtr = NULL;
2124 return -1;
2125 }
2126 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002127 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002128
2129 return 0;
2130}
2131
2132int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002133 FileFormats format,
2134 int startPosition,
2135 float volumeScaling,
2136 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002137 const CodecInst* codecInst)
2138{
2139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2140 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2141 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2142 format, volumeScaling, startPosition, stopPosition);
2143
2144 if(stream == NULL)
2145 {
2146 _engineStatisticsPtr->SetLastError(
2147 VE_BAD_FILE, kTraceError,
2148 "StartPlayingFileAsMicrophone NULL as input stream");
2149 return -1;
2150 }
2151
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002152 CriticalSectionScoped cs(&_fileCritSect);
2153
2154 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002155 {
2156 _engineStatisticsPtr->SetLastError(
2157 VE_ALREADY_PLAYING, kTraceWarning,
2158 "StartPlayingFileAsMicrophone() is playing");
2159 return 0;
2160 }
2161
niklase@google.com470e71d2011-07-07 08:21:25 +00002162 // Destroy the old instance
2163 if (_inputFilePlayerPtr)
2164 {
2165 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2166 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2167 _inputFilePlayerPtr = NULL;
2168 }
2169
2170 // Create the instance
2171 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2172 _inputFilePlayerId, (const FileFormats)format);
2173
2174 if (_inputFilePlayerPtr == NULL)
2175 {
2176 _engineStatisticsPtr->SetLastError(
2177 VE_INVALID_ARGUMENT, kTraceError,
2178 "StartPlayingInputFile() filePlayer format isnot correct");
2179 return -1;
2180 }
2181
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002182 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002183
2184 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2185 volumeScaling, notificationTime,
2186 stopPosition, codecInst) != 0)
2187 {
2188 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2189 "StartPlayingFile() failed to start "
2190 "file playout");
2191 _inputFilePlayerPtr->StopPlayingFile();
2192 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2193 _inputFilePlayerPtr = NULL;
2194 return -1;
2195 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002196
niklase@google.com470e71d2011-07-07 08:21:25 +00002197 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002198 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002199
2200 return 0;
2201}
2202
2203int Channel::StopPlayingFileAsMicrophone()
2204{
2205 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2206 "Channel::StopPlayingFileAsMicrophone()");
2207
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002208 CriticalSectionScoped cs(&_fileCritSect);
2209
2210 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002211 {
niklase@google.com470e71d2011-07-07 08:21:25 +00002212 return 0;
2213 }
2214
niklase@google.com470e71d2011-07-07 08:21:25 +00002215 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2216 {
2217 _engineStatisticsPtr->SetLastError(
2218 VE_STOP_RECORDING_FAILED, kTraceError,
2219 "StopPlayingFile() could not stop playing");
2220 return -1;
2221 }
2222 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2223 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2224 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002225 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002226
2227 return 0;
2228}
2229
2230int Channel::IsPlayingFileAsMicrophone() const
2231{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002232 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002233}
2234
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002235int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002236 const CodecInst* codecInst)
2237{
2238 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2239 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2240
2241 if (_outputFileRecording)
2242 {
2243 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2244 "StartRecordingPlayout() is already recording");
2245 return 0;
2246 }
2247
2248 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002249 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002250 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2251
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002252 if ((codecInst != NULL) &&
2253 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002254 {
2255 _engineStatisticsPtr->SetLastError(
2256 VE_BAD_ARGUMENT, kTraceError,
2257 "StartRecordingPlayout() invalid compression");
2258 return(-1);
2259 }
2260 if(codecInst == NULL)
2261 {
2262 format = kFileFormatPcm16kHzFile;
2263 codecInst=&dummyCodec;
2264 }
2265 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2266 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2267 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2268 {
2269 format = kFileFormatWavFile;
2270 }
2271 else
2272 {
2273 format = kFileFormatCompressedFile;
2274 }
2275
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002276 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002277
2278 // Destroy the old instance
2279 if (_outputFileRecorderPtr)
2280 {
2281 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2282 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2283 _outputFileRecorderPtr = NULL;
2284 }
2285
2286 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2287 _outputFileRecorderId, (const FileFormats)format);
2288 if (_outputFileRecorderPtr == NULL)
2289 {
2290 _engineStatisticsPtr->SetLastError(
2291 VE_INVALID_ARGUMENT, kTraceError,
2292 "StartRecordingPlayout() fileRecorder format isnot correct");
2293 return -1;
2294 }
2295
2296 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2297 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2298 {
2299 _engineStatisticsPtr->SetLastError(
2300 VE_BAD_FILE, kTraceError,
2301 "StartRecordingAudioFile() failed to start file recording");
2302 _outputFileRecorderPtr->StopRecording();
2303 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2304 _outputFileRecorderPtr = NULL;
2305 return -1;
2306 }
2307 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2308 _outputFileRecording = true;
2309
2310 return 0;
2311}
2312
2313int Channel::StartRecordingPlayout(OutStream* stream,
2314 const CodecInst* codecInst)
2315{
2316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2317 "Channel::StartRecordingPlayout()");
2318
2319 if (_outputFileRecording)
2320 {
2321 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2322 "StartRecordingPlayout() is already recording");
2323 return 0;
2324 }
2325
2326 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002327 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002328 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2329
2330 if (codecInst != NULL && codecInst->channels != 1)
2331 {
2332 _engineStatisticsPtr->SetLastError(
2333 VE_BAD_ARGUMENT, kTraceError,
2334 "StartRecordingPlayout() invalid compression");
2335 return(-1);
2336 }
2337 if(codecInst == NULL)
2338 {
2339 format = kFileFormatPcm16kHzFile;
2340 codecInst=&dummyCodec;
2341 }
2342 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2343 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2344 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2345 {
2346 format = kFileFormatWavFile;
2347 }
2348 else
2349 {
2350 format = kFileFormatCompressedFile;
2351 }
2352
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002353 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002354
2355 // Destroy the old instance
2356 if (_outputFileRecorderPtr)
2357 {
2358 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2359 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2360 _outputFileRecorderPtr = NULL;
2361 }
2362
2363 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2364 _outputFileRecorderId, (const FileFormats)format);
2365 if (_outputFileRecorderPtr == NULL)
2366 {
2367 _engineStatisticsPtr->SetLastError(
2368 VE_INVALID_ARGUMENT, kTraceError,
2369 "StartRecordingPlayout() fileRecorder format isnot correct");
2370 return -1;
2371 }
2372
2373 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2374 notificationTime) != 0)
2375 {
2376 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2377 "StartRecordingPlayout() failed to "
2378 "start file recording");
2379 _outputFileRecorderPtr->StopRecording();
2380 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2381 _outputFileRecorderPtr = NULL;
2382 return -1;
2383 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002384
niklase@google.com470e71d2011-07-07 08:21:25 +00002385 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2386 _outputFileRecording = true;
2387
2388 return 0;
2389}
2390
2391int Channel::StopRecordingPlayout()
2392{
2393 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2394 "Channel::StopRecordingPlayout()");
2395
2396 if (!_outputFileRecording)
2397 {
2398 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2399 "StopRecordingPlayout() isnot recording");
2400 return -1;
2401 }
2402
2403
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002404 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002405
2406 if (_outputFileRecorderPtr->StopRecording() != 0)
2407 {
2408 _engineStatisticsPtr->SetLastError(
2409 VE_STOP_RECORDING_FAILED, kTraceError,
2410 "StopRecording() could not stop recording");
2411 return(-1);
2412 }
2413 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2414 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2415 _outputFileRecorderPtr = NULL;
2416 _outputFileRecording = false;
2417
2418 return 0;
2419}
2420
2421void
2422Channel::SetMixWithMicStatus(bool mix)
2423{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002424 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002425 _mixFileWithMicrophone=mix;
2426}
2427
2428int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002429Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002430{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002431 int8_t currentLevel = _outputAudioLevel.Level();
2432 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002433 return 0;
2434}
2435
2436int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002437Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002438{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002439 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2440 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002441 return 0;
2442}
2443
2444int
2445Channel::SetMute(bool enable)
2446{
wu@webrtc.org63420662013-10-17 18:28:55 +00002447 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002448 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2449 "Channel::SetMute(enable=%d)", enable);
2450 _mute = enable;
2451 return 0;
2452}
2453
2454bool
2455Channel::Mute() const
2456{
wu@webrtc.org63420662013-10-17 18:28:55 +00002457 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002458 return _mute;
2459}
2460
2461int
2462Channel::SetOutputVolumePan(float left, float right)
2463{
wu@webrtc.org63420662013-10-17 18:28:55 +00002464 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002465 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2466 "Channel::SetOutputVolumePan()");
2467 _panLeft = left;
2468 _panRight = right;
2469 return 0;
2470}
2471
2472int
2473Channel::GetOutputVolumePan(float& left, float& right) const
2474{
wu@webrtc.org63420662013-10-17 18:28:55 +00002475 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 left = _panLeft;
2477 right = _panRight;
niklase@google.com470e71d2011-07-07 08:21:25 +00002478 return 0;
2479}
2480
2481int
2482Channel::SetChannelOutputVolumeScaling(float scaling)
2483{
wu@webrtc.org63420662013-10-17 18:28:55 +00002484 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002485 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2486 "Channel::SetChannelOutputVolumeScaling()");
2487 _outputGain = scaling;
2488 return 0;
2489}
2490
2491int
2492Channel::GetChannelOutputVolumeScaling(float& scaling) const
2493{
wu@webrtc.org63420662013-10-17 18:28:55 +00002494 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002495 scaling = _outputGain;
niklase@google.com470e71d2011-07-07 08:21:25 +00002496 return 0;
2497}
2498
niklase@google.com470e71d2011-07-07 08:21:25 +00002499int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002500 int lengthMs, int attenuationDb,
2501 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002502{
2503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2504 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2505 playDtmfEvent);
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002506 if (!Sending()) {
2507 return -1;
2508 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002509
2510 _playOutbandDtmfEvent = playDtmfEvent;
2511
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002512 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002513 attenuationDb) != 0)
2514 {
2515 _engineStatisticsPtr->SetLastError(
2516 VE_SEND_DTMF_FAILED,
2517 kTraceWarning,
2518 "SendTelephoneEventOutband() failed to send event");
2519 return -1;
2520 }
2521 return 0;
2522}
2523
2524int Channel::SendTelephoneEventInband(unsigned char eventCode,
2525 int lengthMs,
2526 int attenuationDb,
2527 bool playDtmfEvent)
2528{
2529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2530 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2531 playDtmfEvent);
2532
2533 _playInbandDtmfEvent = playDtmfEvent;
2534 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2535
2536 return 0;
2537}
2538
2539int
niklase@google.com470e71d2011-07-07 08:21:25 +00002540Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2541{
2542 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2543 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002544 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002545 {
2546 _engineStatisticsPtr->SetLastError(
2547 VE_INVALID_ARGUMENT, kTraceError,
2548 "SetSendTelephoneEventPayloadType() invalid type");
2549 return -1;
2550 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002551 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002552 codec.plfreq = 8000;
2553 codec.pltype = type;
2554 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002555 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002556 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002557 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2558 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2559 _engineStatisticsPtr->SetLastError(
2560 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2561 "SetSendTelephoneEventPayloadType() failed to register send"
2562 "payload type");
2563 return -1;
2564 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002565 }
2566 _sendTelephoneEventPayloadType = type;
2567 return 0;
2568}
2569
2570int
2571Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2572{
niklase@google.com470e71d2011-07-07 08:21:25 +00002573 type = _sendTelephoneEventPayloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002574 return 0;
2575}
2576
niklase@google.com470e71d2011-07-07 08:21:25 +00002577int
2578Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2579{
2580 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2581 "Channel::UpdateRxVadDetection()");
2582
2583 int vadDecision = 1;
2584
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002585 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002586
2587 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2588 {
2589 OnRxVadDetected(vadDecision);
2590 _oldVadDecision = vadDecision;
2591 }
2592
2593 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2594 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2595 vadDecision);
2596 return 0;
2597}
2598
2599int
2600Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2601{
2602 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2603 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002604 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002605
2606 if (_rxVadObserverPtr)
2607 {
2608 _engineStatisticsPtr->SetLastError(
2609 VE_INVALID_OPERATION, kTraceError,
2610 "RegisterRxVadObserver() observer already enabled");
2611 return -1;
2612 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002613 _rxVadObserverPtr = &observer;
2614 _RxVadDetection = true;
2615 return 0;
2616}
2617
2618int
2619Channel::DeRegisterRxVadObserver()
2620{
2621 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2622 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002623 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002624
2625 if (!_rxVadObserverPtr)
2626 {
2627 _engineStatisticsPtr->SetLastError(
2628 VE_INVALID_OPERATION, kTraceWarning,
2629 "DeRegisterRxVadObserver() observer already disabled");
2630 return 0;
2631 }
2632 _rxVadObserverPtr = NULL;
2633 _RxVadDetection = false;
2634 return 0;
2635}
2636
2637int
2638Channel::VoiceActivityIndicator(int &activity)
2639{
2640 activity = _sendFrameType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002641 return 0;
2642}
2643
2644#ifdef WEBRTC_VOICE_ENGINE_AGC
2645
2646int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002647Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002648{
2649 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2650 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2651 (int)enable, (int)mode);
2652
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002653 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002654 switch (mode)
2655 {
2656 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002657 break;
2658 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002659 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002660 break;
2661 case kAgcFixedDigital:
2662 agcMode = GainControl::kFixedDigital;
2663 break;
2664 case kAgcAdaptiveDigital:
2665 agcMode =GainControl::kAdaptiveDigital;
2666 break;
2667 default:
2668 _engineStatisticsPtr->SetLastError(
2669 VE_INVALID_ARGUMENT, kTraceError,
2670 "SetRxAgcStatus() invalid Agc mode");
2671 return -1;
2672 }
2673
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002674 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002675 {
2676 _engineStatisticsPtr->SetLastError(
2677 VE_APM_ERROR, kTraceError,
2678 "SetRxAgcStatus() failed to set Agc mode");
2679 return -1;
2680 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002681 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002682 {
2683 _engineStatisticsPtr->SetLastError(
2684 VE_APM_ERROR, kTraceError,
2685 "SetRxAgcStatus() failed to set Agc state");
2686 return -1;
2687 }
2688
2689 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002690 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002691
2692 return 0;
2693}
2694
2695int
2696Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2697{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002698 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002699 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002700 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002701
2702 enabled = enable;
2703
2704 switch (agcMode)
2705 {
2706 case GainControl::kFixedDigital:
2707 mode = kAgcFixedDigital;
2708 break;
2709 case GainControl::kAdaptiveDigital:
2710 mode = kAgcAdaptiveDigital;
2711 break;
2712 default:
2713 _engineStatisticsPtr->SetLastError(
2714 VE_APM_ERROR, kTraceError,
2715 "GetRxAgcStatus() invalid Agc mode");
2716 return -1;
2717 }
2718
2719 return 0;
2720}
2721
2722int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002723Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002724{
2725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2726 "Channel::SetRxAgcConfig()");
2727
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002728 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002729 config.targetLeveldBOv) != 0)
2730 {
2731 _engineStatisticsPtr->SetLastError(
2732 VE_APM_ERROR, kTraceError,
2733 "SetRxAgcConfig() failed to set target peak |level|"
2734 "(or envelope) of the Agc");
2735 return -1;
2736 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002737 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002738 config.digitalCompressionGaindB) != 0)
2739 {
2740 _engineStatisticsPtr->SetLastError(
2741 VE_APM_ERROR, kTraceError,
2742 "SetRxAgcConfig() failed to set the range in |gain| the"
2743 " digital compression stage may apply");
2744 return -1;
2745 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002746 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002747 config.limiterEnable) != 0)
2748 {
2749 _engineStatisticsPtr->SetLastError(
2750 VE_APM_ERROR, kTraceError,
2751 "SetRxAgcConfig() failed to set hard limiter to the signal");
2752 return -1;
2753 }
2754
2755 return 0;
2756}
2757
2758int
2759Channel::GetRxAgcConfig(AgcConfig& config)
2760{
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002762 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002763 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002764 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002765 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002766 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002767
niklase@google.com470e71d2011-07-07 08:21:25 +00002768 return 0;
2769}
2770
2771#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2772
2773#ifdef WEBRTC_VOICE_ENGINE_NR
2774
2775int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002776Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002777{
2778 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2779 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2780 (int)enable, (int)mode);
2781
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002782 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002783 switch (mode)
2784 {
2785
2786 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002787 break;
2788 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002789 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002790 break;
2791 case kNsConference:
2792 nsLevel = NoiseSuppression::kHigh;
2793 break;
2794 case kNsLowSuppression:
2795 nsLevel = NoiseSuppression::kLow;
2796 break;
2797 case kNsModerateSuppression:
2798 nsLevel = NoiseSuppression::kModerate;
2799 break;
2800 case kNsHighSuppression:
2801 nsLevel = NoiseSuppression::kHigh;
2802 break;
2803 case kNsVeryHighSuppression:
2804 nsLevel = NoiseSuppression::kVeryHigh;
2805 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002806 }
2807
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002808 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002809 != 0)
2810 {
2811 _engineStatisticsPtr->SetLastError(
2812 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002813 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002814 return -1;
2815 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002816 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002817 {
2818 _engineStatisticsPtr->SetLastError(
2819 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002820 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002821 return -1;
2822 }
2823
2824 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002825 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002826
2827 return 0;
2828}
2829
2830int
2831Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2832{
niklase@google.com470e71d2011-07-07 08:21:25 +00002833 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002834 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002835 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002836 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002837
2838 enabled = enable;
2839
2840 switch (ncLevel)
2841 {
2842 case NoiseSuppression::kLow:
2843 mode = kNsLowSuppression;
2844 break;
2845 case NoiseSuppression::kModerate:
2846 mode = kNsModerateSuppression;
2847 break;
2848 case NoiseSuppression::kHigh:
2849 mode = kNsHighSuppression;
2850 break;
2851 case NoiseSuppression::kVeryHigh:
2852 mode = kNsVeryHighSuppression;
2853 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002854 }
2855
niklase@google.com470e71d2011-07-07 08:21:25 +00002856 return 0;
2857}
2858
2859#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2860
2861int
niklase@google.com470e71d2011-07-07 08:21:25 +00002862Channel::SetLocalSSRC(unsigned int ssrc)
2863{
2864 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2865 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002866 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002867 {
2868 _engineStatisticsPtr->SetLastError(
2869 VE_ALREADY_SENDING, kTraceError,
2870 "SetLocalSSRC() already sending");
2871 return -1;
2872 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002873 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002874 return 0;
2875}
2876
2877int
2878Channel::GetLocalSSRC(unsigned int& ssrc)
2879{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002880 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002881 return 0;
2882}
2883
2884int
2885Channel::GetRemoteSSRC(unsigned int& ssrc)
2886{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002887 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002888 return 0;
2889}
2890
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002891int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002892 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002893 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002894}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002895
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002896int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2897 unsigned char id) {
2898 rtp_header_parser_->DeregisterRtpHeaderExtension(
2899 kRtpExtensionAudioLevel);
2900 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2901 kRtpExtensionAudioLevel, id)) {
2902 return -1;
2903 }
2904 return 0;
2905}
2906
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002907int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2908 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2909}
2910
2911int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2912 rtp_header_parser_->DeregisterRtpHeaderExtension(
2913 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002914 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2915 kRtpExtensionAbsoluteSendTime, id)) {
2916 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002917 }
2918 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002919}
2920
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002921void Channel::EnableSendTransportSequenceNumber(int id) {
2922 int ret =
2923 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2924 RTC_DCHECK_EQ(0, ret);
2925}
2926
stefan3313ec92016-01-21 06:32:43 -08002927void Channel::EnableReceiveTransportSequenceNumber(int id) {
2928 rtp_header_parser_->DeregisterRtpHeaderExtension(
2929 kRtpExtensionTransportSequenceNumber);
2930 bool ret = rtp_header_parser_->RegisterRtpHeaderExtension(
2931 kRtpExtensionTransportSequenceNumber, id);
2932 RTC_DCHECK(ret);
2933}
2934
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002935void Channel::SetCongestionControlObjects(
2936 RtpPacketSender* rtp_packet_sender,
2937 TransportFeedbackObserver* transport_feedback_observer,
2938 PacketRouter* packet_router) {
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002939 RTC_DCHECK(packet_router != nullptr || packet_router_ != nullptr);
Stefan Holmer3842c5c2016-01-12 13:55:00 +01002940 if (transport_feedback_observer) {
2941 RTC_DCHECK(feedback_observer_proxy_.get());
2942 feedback_observer_proxy_->SetTransportFeedbackObserver(
2943 transport_feedback_observer);
2944 }
2945 if (rtp_packet_sender) {
2946 RTC_DCHECK(rtp_packet_sender_proxy_.get());
2947 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2948 }
2949 if (seq_num_allocator_proxy_.get()) {
2950 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2951 }
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002952 _rtpRtcpModule->SetStorePacketsStatus(rtp_packet_sender != nullptr, 600);
2953 if (packet_router != nullptr) {
2954 packet_router->AddRtpModule(_rtpRtcpModule.get());
2955 } else {
2956 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
2957 }
2958 packet_router_ = packet_router;
2959}
2960
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002961void Channel::SetRTCPStatus(bool enable) {
2962 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2963 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002964 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002965}
2966
2967int
2968Channel::GetRTCPStatus(bool& enabled)
2969{
pbosda903ea2015-10-02 02:36:56 -07002970 RtcpMode method = _rtpRtcpModule->RTCP();
2971 enabled = (method != RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002972 return 0;
2973}
2974
2975int
2976Channel::SetRTCP_CNAME(const char cName[256])
2977{
2978 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2979 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002980 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002981 {
2982 _engineStatisticsPtr->SetLastError(
2983 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2984 "SetRTCP_CNAME() failed to set RTCP CNAME");
2985 return -1;
2986 }
2987 return 0;
2988}
2989
2990int
niklase@google.com470e71d2011-07-07 08:21:25 +00002991Channel::GetRemoteRTCP_CNAME(char cName[256])
2992{
2993 if (cName == NULL)
2994 {
2995 _engineStatisticsPtr->SetLastError(
2996 VE_INVALID_ARGUMENT, kTraceError,
2997 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2998 return -1;
2999 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003000 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003001 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003002 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003003 {
3004 _engineStatisticsPtr->SetLastError(
3005 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3006 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3007 return -1;
3008 }
3009 strcpy(cName, cname);
niklase@google.com470e71d2011-07-07 08:21:25 +00003010 return 0;
3011}
3012
3013int
3014Channel::GetRemoteRTCPData(
3015 unsigned int& NTPHigh,
3016 unsigned int& NTPLow,
3017 unsigned int& timestamp,
3018 unsigned int& playoutTimestamp,
3019 unsigned int* jitter,
3020 unsigned short* fractionLost)
3021{
3022 // --- Information from sender info in received Sender Reports
3023
3024 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003025 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003026 {
3027 _engineStatisticsPtr->SetLastError(
3028 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003029 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003030 "side");
3031 return -1;
3032 }
3033
3034 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3035 // and octet count)
3036 NTPHigh = senderInfo.NTPseconds;
3037 NTPLow = senderInfo.NTPfraction;
3038 timestamp = senderInfo.RTPtimeStamp;
3039
niklase@google.com470e71d2011-07-07 08:21:25 +00003040 // --- Locally derived information
3041
3042 // This value is updated on each incoming RTCP packet (0 when no packet
3043 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003044 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003045
niklase@google.com470e71d2011-07-07 08:21:25 +00003046 if (NULL != jitter || NULL != fractionLost)
3047 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003048 // Get all RTCP receiver report blocks that have been received on this
3049 // channel. If we receive RTP packets from a remote source we know the
3050 // remote SSRC and use the report block from him.
3051 // Otherwise use the first report block.
3052 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003053 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003054 remote_stats.empty()) {
3055 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3056 VoEId(_instanceId, _channelId),
3057 "GetRemoteRTCPData() failed to measure statistics due"
3058 " to lack of received RTP and/or RTCP packets");
3059 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003060 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003061
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003062 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003063 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3064 for (; it != remote_stats.end(); ++it) {
3065 if (it->remoteSSRC == remoteSSRC)
3066 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003067 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003068
3069 if (it == remote_stats.end()) {
3070 // If we have not received any RTCP packets from this SSRC it probably
3071 // means that we have not received any RTP packets.
3072 // Use the first received report block instead.
3073 it = remote_stats.begin();
3074 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003075 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003076
xians@webrtc.org79af7342012-01-31 12:22:14 +00003077 if (jitter) {
3078 *jitter = it->jitter;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003079 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003080
xians@webrtc.org79af7342012-01-31 12:22:14 +00003081 if (fractionLost) {
3082 *fractionLost = it->fractionLost;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003083 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003084 }
3085 return 0;
3086}
3087
3088int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003089Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003090 unsigned int name,
3091 const char* data,
3092 unsigned short dataLengthInBytes)
3093{
3094 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3095 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003096 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003097 {
3098 _engineStatisticsPtr->SetLastError(
3099 VE_NOT_SENDING, kTraceError,
3100 "SendApplicationDefinedRTCPPacket() not sending");
3101 return -1;
3102 }
3103 if (NULL == data)
3104 {
3105 _engineStatisticsPtr->SetLastError(
3106 VE_INVALID_ARGUMENT, kTraceError,
3107 "SendApplicationDefinedRTCPPacket() invalid data value");
3108 return -1;
3109 }
3110 if (dataLengthInBytes % 4 != 0)
3111 {
3112 _engineStatisticsPtr->SetLastError(
3113 VE_INVALID_ARGUMENT, kTraceError,
3114 "SendApplicationDefinedRTCPPacket() invalid length value");
3115 return -1;
3116 }
pbosda903ea2015-10-02 02:36:56 -07003117 RtcpMode status = _rtpRtcpModule->RTCP();
3118 if (status == RtcpMode::kOff) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 _engineStatisticsPtr->SetLastError(
3120 VE_RTCP_ERROR, kTraceError,
3121 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3122 return -1;
3123 }
3124
3125 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003126 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 subType,
3128 name,
3129 (const unsigned char*) data,
3130 dataLengthInBytes) != 0)
3131 {
3132 _engineStatisticsPtr->SetLastError(
3133 VE_SEND_ERROR, kTraceError,
3134 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3135 return -1;
3136 }
3137 return 0;
3138}
3139
3140int
3141Channel::GetRTPStatistics(
3142 unsigned int& averageJitterMs,
3143 unsigned int& maxJitterMs,
3144 unsigned int& discardedPackets)
3145{
niklase@google.com470e71d2011-07-07 08:21:25 +00003146 // The jitter statistics is updated for each received RTP packet and is
3147 // based on received packets.
pbosda903ea2015-10-02 02:36:56 -07003148 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003149 // If RTCP is off, there is no timed thread in the RTCP module regularly
3150 // generating new stats, trigger the update manually here instead.
3151 StreamStatistician* statistician =
3152 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3153 if (statistician) {
3154 // Don't use returned statistics, use data from proxy instead so that
3155 // max jitter can be fetched atomically.
3156 RtcpStatistics s;
3157 statistician->GetStatistics(&s, true);
3158 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003159 }
3160
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003161 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003162 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003163 if (playoutFrequency > 0) {
3164 // Scale RTP statistics given the current playout frequency
3165 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3166 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003167 }
3168
3169 discardedPackets = _numberOfDiscardedPackets;
3170
niklase@google.com470e71d2011-07-07 08:21:25 +00003171 return 0;
3172}
3173
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003174int Channel::GetRemoteRTCPReportBlocks(
3175 std::vector<ReportBlock>* report_blocks) {
3176 if (report_blocks == NULL) {
3177 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3178 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3179 return -1;
3180 }
3181
3182 // Get the report blocks from the latest received RTCP Sender or Receiver
3183 // Report. Each element in the vector contains the sender's SSRC and a
3184 // report block according to RFC 3550.
3185 std::vector<RTCPReportBlock> rtcp_report_blocks;
3186 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003187 return -1;
3188 }
3189
3190 if (rtcp_report_blocks.empty())
3191 return 0;
3192
3193 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3194 for (; it != rtcp_report_blocks.end(); ++it) {
3195 ReportBlock report_block;
3196 report_block.sender_SSRC = it->remoteSSRC;
3197 report_block.source_SSRC = it->sourceSSRC;
3198 report_block.fraction_lost = it->fractionLost;
3199 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3200 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3201 report_block.interarrival_jitter = it->jitter;
3202 report_block.last_SR_timestamp = it->lastSR;
3203 report_block.delay_since_last_SR = it->delaySinceLastSR;
3204 report_blocks->push_back(report_block);
3205 }
3206 return 0;
3207}
3208
niklase@google.com470e71d2011-07-07 08:21:25 +00003209int
3210Channel::GetRTPStatistics(CallStatistics& stats)
3211{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003212 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003213
3214 // The jitter statistics is updated for each received RTP packet and is
3215 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003216 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003217 StreamStatistician* statistician =
3218 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
pbosda903ea2015-10-02 02:36:56 -07003219 if (!statistician ||
3220 !statistician->GetStatistics(
3221 &statistics, _rtpRtcpModule->RTCP() == RtcpMode::kOff)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003222 _engineStatisticsPtr->SetLastError(
3223 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3224 "GetRTPStatistics() failed to read RTP statistics from the "
3225 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003226 }
3227
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003228 stats.fractionLost = statistics.fraction_lost;
3229 stats.cumulativeLost = statistics.cumulative_lost;
3230 stats.extendedMax = statistics.extended_max_sequence_number;
3231 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003232
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003233 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003234 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003235
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003236 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003237
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003238 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003239 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003240 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003241 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003242
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003243 if (statistician) {
3244 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3245 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003246
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003247 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003248 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003249 {
3250 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3251 VoEId(_instanceId, _channelId),
3252 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003253 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003254 }
3255
3256 stats.bytesSent = bytesSent;
3257 stats.packetsSent = packetsSent;
3258 stats.bytesReceived = bytesReceived;
3259 stats.packetsReceived = packetsReceived;
3260
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003261 // --- Timestamps
3262 {
3263 CriticalSectionScoped lock(ts_stats_lock_.get());
3264 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3265 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003266 return 0;
3267}
3268
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003269int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003271 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003272
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003273 if (enable) {
3274 if (redPayloadtype < 0 || redPayloadtype > 127) {
3275 _engineStatisticsPtr->SetLastError(
3276 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003277 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003278 return -1;
3279 }
3280
3281 if (SetRedPayloadType(redPayloadtype) < 0) {
3282 _engineStatisticsPtr->SetLastError(
3283 VE_CODEC_ERROR, kTraceError,
3284 "SetSecondarySendCodec() Failed to register RED ACM");
3285 return -1;
3286 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003287 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003288
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003289 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003290 _engineStatisticsPtr->SetLastError(
3291 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003292 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003293 return -1;
3294 }
3295 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003296}
3297
3298int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003299Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003300{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003301 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003302 if (enabled)
3303 {
danilchap5c1def82015-12-10 09:51:54 -08003304 int8_t payloadType = 0;
3305 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003306 _engineStatisticsPtr->SetLastError(
3307 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003308 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003309 "module");
3310 return -1;
3311 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003312 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003313 return 0;
3314 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003315 return 0;
3316}
3317
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003318int Channel::SetCodecFECStatus(bool enable) {
3319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3320 "Channel::SetCodecFECStatus()");
3321
3322 if (audio_coding_->SetCodecFEC(enable) != 0) {
3323 _engineStatisticsPtr->SetLastError(
3324 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3325 "SetCodecFECStatus() failed to set FEC state");
3326 return -1;
3327 }
3328 return 0;
3329}
3330
3331bool Channel::GetCodecFECStatus() {
3332 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003333 return enabled;
3334}
3335
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003336void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3337 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01003338 // If pacing is enabled we always store packets.
3339 if (!pacing_enabled_)
3340 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003341 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3342 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003343 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003344 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003345 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003346 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003347}
3348
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003349// Called when we are missing one or more packets.
3350int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003351 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3352}
3353
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003354uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003355Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003356{
3357 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003358 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003359 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003360 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003361 return 0;
3362}
3363
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003364void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003365 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003366 size_t number_of_frames,
Peter Kasting69558702016-01-12 16:26:35 -08003367 size_t number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003368 CodecInst codec;
3369 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003370
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07003371 // Never upsample or upmix the capture signal here. This should be done at the
3372 // end of the send chain.
3373 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3374 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3375 RemixAndResample(audio_data, number_of_frames, number_of_channels,
3376 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003377}
3378
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003379uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003380Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003381{
3382 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3383 "Channel::PrepareEncodeAndSend()");
3384
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003385 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003386 {
3387 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3388 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003389 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003390 }
3391
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003392 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003393 {
3394 MixOrReplaceAudioWithFile(mixingFrequency);
3395 }
3396
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003397 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3398 if (is_muted) {
3399 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003400 }
3401
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003402 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003403 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003404 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003405 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003406 if (_inputExternalMediaCallbackPtr)
3407 {
3408 _inputExternalMediaCallbackPtr->Process(
3409 _channelId,
3410 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003411 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003412 _audioFrame.samples_per_channel_,
3413 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003414 isStereo);
3415 }
3416 }
3417
3418 InsertInbandDtmfTone();
3419
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003420 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003421 size_t length =
3422 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003423 if (is_muted) {
3424 rms_level_.ProcessMuted(length);
3425 } else {
3426 rms_level_.Process(_audioFrame.data_, length);
3427 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003428 }
3429
niklase@google.com470e71d2011-07-07 08:21:25 +00003430 return 0;
3431}
3432
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003433uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003434Channel::EncodeAndSend()
3435{
3436 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3437 "Channel::EncodeAndSend()");
3438
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003439 assert(_audioFrame.num_channels_ <= 2);
3440 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003441 {
3442 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3443 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003444 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003445 }
3446
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003447 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003448
3449 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3450
3451 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003452 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003453 // This call will trigger AudioPacketizationCallback::SendData if encoding
3454 // is done and payload is ready for packetization and transmission.
3455 // Otherwise, it will return without invoking the callback.
3456 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003457 {
3458 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3459 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003460 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003461 }
3462
Peter Kastingb7e50542015-06-11 12:55:50 -07003463 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003464 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003465}
3466
Minyue2013aec2015-05-13 14:14:42 +02003467void Channel::DisassociateSendChannel(int channel_id) {
3468 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3469 Channel* channel = associate_send_channel_.channel();
3470 if (channel && channel->ChannelId() == channel_id) {
3471 // If this channel is associated with a send channel of the specified
3472 // Channel ID, disassociate with it.
3473 ChannelOwner ref(NULL);
3474 associate_send_channel_ = ref;
3475 }
3476}
3477
niklase@google.com470e71d2011-07-07 08:21:25 +00003478int Channel::RegisterExternalMediaProcessing(
3479 ProcessingTypes type,
3480 VoEMediaProcess& processObject)
3481{
3482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3483 "Channel::RegisterExternalMediaProcessing()");
3484
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003485 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003486
3487 if (kPlaybackPerChannel == type)
3488 {
3489 if (_outputExternalMediaCallbackPtr)
3490 {
3491 _engineStatisticsPtr->SetLastError(
3492 VE_INVALID_OPERATION, kTraceError,
3493 "Channel::RegisterExternalMediaProcessing() "
3494 "output external media already enabled");
3495 return -1;
3496 }
3497 _outputExternalMediaCallbackPtr = &processObject;
3498 _outputExternalMedia = true;
3499 }
3500 else if (kRecordingPerChannel == type)
3501 {
3502 if (_inputExternalMediaCallbackPtr)
3503 {
3504 _engineStatisticsPtr->SetLastError(
3505 VE_INVALID_OPERATION, kTraceError,
3506 "Channel::RegisterExternalMediaProcessing() "
3507 "output external media already enabled");
3508 return -1;
3509 }
3510 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003511 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003512 }
3513 return 0;
3514}
3515
3516int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3517{
3518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3519 "Channel::DeRegisterExternalMediaProcessing()");
3520
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003521 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003522
3523 if (kPlaybackPerChannel == type)
3524 {
3525 if (!_outputExternalMediaCallbackPtr)
3526 {
3527 _engineStatisticsPtr->SetLastError(
3528 VE_INVALID_OPERATION, kTraceWarning,
3529 "Channel::DeRegisterExternalMediaProcessing() "
3530 "output external media already disabled");
3531 return 0;
3532 }
3533 _outputExternalMedia = false;
3534 _outputExternalMediaCallbackPtr = NULL;
3535 }
3536 else if (kRecordingPerChannel == type)
3537 {
3538 if (!_inputExternalMediaCallbackPtr)
3539 {
3540 _engineStatisticsPtr->SetLastError(
3541 VE_INVALID_OPERATION, kTraceWarning,
3542 "Channel::DeRegisterExternalMediaProcessing() "
3543 "input external media already disabled");
3544 return 0;
3545 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003546 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003547 _inputExternalMediaCallbackPtr = NULL;
3548 }
3549
3550 return 0;
3551}
3552
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003553int Channel::SetExternalMixing(bool enabled) {
3554 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3555 "Channel::SetExternalMixing(enabled=%d)", enabled);
3556
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003557 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003558 {
3559 _engineStatisticsPtr->SetLastError(
3560 VE_INVALID_OPERATION, kTraceError,
3561 "Channel::SetExternalMixing() "
3562 "external mixing cannot be changed while playing.");
3563 return -1;
3564 }
3565
3566 _externalMixing = enabled;
3567
3568 return 0;
3569}
3570
niklase@google.com470e71d2011-07-07 08:21:25 +00003571int
niklase@google.com470e71d2011-07-07 08:21:25 +00003572Channel::GetNetworkStatistics(NetworkStatistics& stats)
3573{
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003574 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003575}
3576
wu@webrtc.org24301a62013-12-13 19:17:43 +00003577void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3578 audio_coding_->GetDecodingCallStatistics(stats);
3579}
3580
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003581bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3582 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003583 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003584 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003585 return false;
3586 }
3587 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3588 _recPacketDelayMs;
3589 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003590 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003591}
3592
solenberg358057b2015-11-27 10:46:42 -08003593uint32_t Channel::GetDelayEstimate() const {
3594 int jitter_buffer_delay_ms = 0;
3595 int playout_buffer_delay_ms = 0;
3596 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3597 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3598}
3599
deadbeef74375882015-08-13 12:09:10 -07003600int Channel::LeastRequiredDelayMs() const {
3601 return audio_coding_->LeastRequiredDelayMs();
3602}
3603
niklase@google.com470e71d2011-07-07 08:21:25 +00003604int
3605Channel::SetMinimumPlayoutDelay(int delayMs)
3606{
3607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3608 "Channel::SetMinimumPlayoutDelay()");
3609 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3610 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3611 {
3612 _engineStatisticsPtr->SetLastError(
3613 VE_INVALID_ARGUMENT, kTraceError,
3614 "SetMinimumPlayoutDelay() invalid min delay");
3615 return -1;
3616 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003617 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003618 {
3619 _engineStatisticsPtr->SetLastError(
3620 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3621 "SetMinimumPlayoutDelay() failed to set min playout delay");
3622 return -1;
3623 }
3624 return 0;
3625}
3626
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003627int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003628 uint32_t playout_timestamp_rtp = 0;
3629 {
3630 CriticalSectionScoped cs(video_sync_lock_.get());
3631 playout_timestamp_rtp = playout_timestamp_rtp_;
3632 }
3633 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003634 _engineStatisticsPtr->SetLastError(
3635 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3636 "GetPlayoutTimestamp() failed to retrieve timestamp");
3637 return -1;
3638 }
deadbeef74375882015-08-13 12:09:10 -07003639 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003640 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003641}
3642
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003643int Channel::SetInitTimestamp(unsigned int timestamp) {
3644 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003645 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003646 if (channel_state_.Get().sending) {
3647 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3648 "SetInitTimestamp() already sending");
3649 return -1;
3650 }
3651 _rtpRtcpModule->SetStartTimestamp(timestamp);
3652 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003653}
3654
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003655int Channel::SetInitSequenceNumber(short sequenceNumber) {
3656 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3657 "Channel::SetInitSequenceNumber()");
3658 if (channel_state_.Get().sending) {
3659 _engineStatisticsPtr->SetLastError(
3660 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3661 return -1;
3662 }
3663 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3664 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003665}
3666
3667int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003668Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003669{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003670 *rtpRtcpModule = _rtpRtcpModule.get();
3671 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003672 return 0;
3673}
3674
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003675// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3676// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003677int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003678Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003679{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003680 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003681 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003682
3683 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003684 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003685
3686 if (_inputFilePlayerPtr == NULL)
3687 {
3688 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3689 VoEId(_instanceId, _channelId),
3690 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3691 " doesnt exist");
3692 return -1;
3693 }
3694
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003695 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003696 fileSamples,
3697 mixingFrequency) == -1)
3698 {
3699 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3700 VoEId(_instanceId, _channelId),
3701 "Channel::MixOrReplaceAudioWithFile() file mixing "
3702 "failed");
3703 return -1;
3704 }
3705 if (fileSamples == 0)
3706 {
3707 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3708 VoEId(_instanceId, _channelId),
3709 "Channel::MixOrReplaceAudioWithFile() file is ended");
3710 return 0;
3711 }
3712 }
3713
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003714 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003715
3716 if (_mixFileWithMicrophone)
3717 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003718 // Currently file stream is always mono.
3719 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003720 MixWithSat(_audioFrame.data_,
3721 _audioFrame.num_channels_,
3722 fileBuffer.get(),
3723 1,
3724 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003725 }
3726 else
3727 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003728 // Replace ACM audio with file.
3729 // Currently file stream is always mono.
3730 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003731 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003732 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003733 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003734 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003735 mixingFrequency,
3736 AudioFrame::kNormalSpeech,
3737 AudioFrame::kVadUnknown,
3738 1);
3739
3740 }
3741 return 0;
3742}
3743
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003744int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003745Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003746 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003747{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003748 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003749
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003750 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003751 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003752
3753 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003754 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003755
3756 if (_outputFilePlayerPtr == NULL)
3757 {
3758 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3759 VoEId(_instanceId, _channelId),
3760 "Channel::MixAudioWithFile() file mixing failed");
3761 return -1;
3762 }
3763
3764 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003765 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003766 fileSamples,
3767 mixingFrequency) == -1)
3768 {
3769 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3770 VoEId(_instanceId, _channelId),
3771 "Channel::MixAudioWithFile() file mixing failed");
3772 return -1;
3773 }
3774 }
3775
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003776 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003777 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003778 // Currently file stream is always mono.
3779 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003780 MixWithSat(audioFrame.data_,
3781 audioFrame.num_channels_,
3782 fileBuffer.get(),
3783 1,
3784 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003785 }
3786 else
3787 {
3788 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003789 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3790 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003791 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003792 return -1;
3793 }
3794
3795 return 0;
3796}
3797
3798int
3799Channel::InsertInbandDtmfTone()
3800{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003801 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003802 if (_inbandDtmfQueue.PendingDtmf() &&
3803 !_inbandDtmfGenerator.IsAddingTone() &&
3804 _inbandDtmfGenerator.DelaySinceLastTone() >
3805 kMinTelephoneEventSeparationMs)
3806 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003807 int8_t eventCode(0);
3808 uint16_t lengthMs(0);
3809 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003810
3811 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3812 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3813 if (_playInbandDtmfEvent)
3814 {
3815 // Add tone to output mixer using a reduced length to minimize
3816 // risk of echo.
3817 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3818 attenuationDb);
3819 }
3820 }
3821
3822 if (_inbandDtmfGenerator.IsAddingTone())
3823 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003824 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003825 _inbandDtmfGenerator.GetSampleRate(frequency);
3826
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003827 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003828 {
3829 // Update sample rate of Dtmf tone since the mixing frequency
3830 // has changed.
3831 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003832 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003833 // Reset the tone to be added taking the new sample rate into
3834 // account.
3835 _inbandDtmfGenerator.ResetTone();
3836 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003837
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003838 int16_t toneBuffer[320];
3839 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003840 // Get 10ms tone segment and set time since last tone to zero
3841 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3842 {
3843 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3844 VoEId(_instanceId, _channelId),
3845 "Channel::EncodeAndSend() inserting Dtmf failed");
3846 return -1;
3847 }
3848
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003849 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003850 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003851 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003852 sample++)
3853 {
Peter Kasting69558702016-01-12 16:26:35 -08003854 for (size_t channel = 0;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003855 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003856 channel++)
3857 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003858 const size_t index =
3859 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003860 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003861 }
3862 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003863
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003864 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003865 } else
3866 {
3867 // Add 10ms to "delay-since-last-tone" counter
3868 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3869 }
3870 return 0;
3871}
3872
deadbeef74375882015-08-13 12:09:10 -07003873void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3874 uint32_t playout_timestamp = 0;
3875
3876 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3877 // This can happen if this channel has not been received any RTP packet. In
3878 // this case, NetEq is not capable of computing playout timestamp.
3879 return;
3880 }
3881
3882 uint16_t delay_ms = 0;
3883 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3884 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3885 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3886 " delay from the ADM");
3887 _engineStatisticsPtr->SetLastError(
3888 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3889 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3890 return;
3891 }
3892
3893 jitter_buffer_playout_timestamp_ = playout_timestamp;
3894
3895 // Remove the playout delay.
3896 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3897
3898 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3899 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3900 playout_timestamp);
3901
3902 {
3903 CriticalSectionScoped cs(video_sync_lock_.get());
3904 if (rtcp) {
3905 playout_timestamp_rtcp_ = playout_timestamp;
3906 } else {
3907 playout_timestamp_rtp_ = playout_timestamp;
3908 }
3909 playout_delay_ms_ = delay_ms;
3910 }
3911}
3912
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003913// Called for incoming RTP packets after successful RTP header parsing.
3914void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3915 uint16_t sequence_number) {
3916 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3917 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3918 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003919
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003920 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003921 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003922
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003923 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3924 // every incoming packet.
3925 uint32_t timestamp_diff_ms = (rtp_timestamp -
3926 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003927 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3928 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3929 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3930 // timestamp, the resulting difference is negative, but is set to zero.
3931 // This can happen when a network glitch causes a packet to arrive late,
3932 // and during long comfort noise periods with clock drift.
3933 timestamp_diff_ms = 0;
3934 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003935
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003936 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3937 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003938
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003939 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003940
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003941 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003942
deadbeef74375882015-08-13 12:09:10 -07003943 {
3944 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003945
deadbeef74375882015-08-13 12:09:10 -07003946 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3947 _recPacketDelayMs = packet_delay_ms;
3948 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003949
deadbeef74375882015-08-13 12:09:10 -07003950 if (_average_jitter_buffer_delay_us == 0) {
3951 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3952 return;
3953 }
3954
3955 // Filter average delay value using exponential filter (alpha is
3956 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3957 // risk of rounding error) and compensate for it in GetDelayEstimate()
3958 // later.
3959 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3960 1000 * timestamp_diff_ms + 500) / 8;
3961 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003962}
3963
3964void
3965Channel::RegisterReceiveCodecsToRTPModule()
3966{
3967 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3968 "Channel::RegisterReceiveCodecsToRTPModule()");
3969
niklase@google.com470e71d2011-07-07 08:21:25 +00003970 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003971 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003972
3973 for (int idx = 0; idx < nSupportedCodecs; idx++)
3974 {
3975 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003976 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003977 (rtp_receiver_->RegisterReceivePayload(
3978 codec.plname,
3979 codec.pltype,
3980 codec.plfreq,
3981 codec.channels,
3982 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003983 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003984 WEBRTC_TRACE(kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00003985 kTraceVoice,
3986 VoEId(_instanceId, _channelId),
3987 "Channel::RegisterReceiveCodecsToRTPModule() unable"
Peter Kasting69558702016-01-12 16:26:35 -08003988 " to register %s (%d/%d/%" PRIuS "/%d) to RTP/RTCP "
3989 "receiver",
niklase@google.com470e71d2011-07-07 08:21:25 +00003990 codec.plname, codec.pltype, codec.plfreq,
3991 codec.channels, codec.rate);
3992 }
3993 else
3994 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003995 WEBRTC_TRACE(kTraceInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +00003996 kTraceVoice,
3997 VoEId(_instanceId, _channelId),
3998 "Channel::RegisterReceiveCodecsToRTPModule() %s "
Peter Kasting69558702016-01-12 16:26:35 -08003999 "(%d/%d/%" PRIuS "/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004000 "receiver",
4001 codec.plname, codec.pltype, codec.plfreq,
4002 codec.channels, codec.rate);
4003 }
4004 }
4005}
4006
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004007// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004008int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004009 CodecInst codec;
4010 bool found_red = false;
4011
4012 // Get default RED settings from the ACM database
4013 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4014 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004015 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004016 if (!STR_CASE_CMP(codec.plname, "RED")) {
4017 found_red = true;
4018 break;
4019 }
4020 }
4021
4022 if (!found_red) {
4023 _engineStatisticsPtr->SetLastError(
4024 VE_CODEC_ERROR, kTraceError,
4025 "SetRedPayloadType() RED is not supported");
4026 return -1;
4027 }
4028
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004029 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004030 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004031 _engineStatisticsPtr->SetLastError(
4032 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4033 "SetRedPayloadType() RED registration in ACM module failed");
4034 return -1;
4035 }
4036
4037 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4038 _engineStatisticsPtr->SetLastError(
4039 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4040 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4041 return -1;
4042 }
4043 return 0;
4044}
4045
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004046int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4047 unsigned char id) {
4048 int error = 0;
4049 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4050 if (enable) {
4051 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4052 }
4053 return error;
4054}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004055
wu@webrtc.org94454b72014-06-05 20:34:08 +00004056int32_t Channel::GetPlayoutFrequency() {
4057 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4058 CodecInst current_recive_codec;
4059 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4060 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4061 // Even though the actual sampling rate for G.722 audio is
4062 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4063 // 8,000 Hz because that value was erroneously assigned in
4064 // RFC 1890 and must remain unchanged for backward compatibility.
4065 playout_frequency = 8000;
4066 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4067 // We are resampling Opus internally to 32,000 Hz until all our
4068 // DSP routines can operate at 48,000 Hz, but the RTP clock
4069 // rate for the Opus payload format is standardized to 48,000 Hz,
4070 // because that is the maximum supported decoding sampling rate.
4071 playout_frequency = 48000;
4072 }
4073 }
4074 return playout_frequency;
4075}
4076
Minyue2013aec2015-05-13 14:14:42 +02004077int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07004078 RtcpMode method = _rtpRtcpModule->RTCP();
4079 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004080 return 0;
4081 }
4082 std::vector<RTCPReportBlock> report_blocks;
4083 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004084
4085 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004086 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004087 if (allow_associate_channel) {
4088 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4089 Channel* channel = associate_send_channel_.channel();
4090 // Tries to get RTT from an associated channel. This is important for
4091 // receive-only channels.
4092 if (channel) {
4093 // To prevent infinite recursion and deadlock, calling GetRTT of
4094 // associate channel should always use "false" for argument:
4095 // |allow_associate_channel|.
4096 rtt = channel->GetRTT(false);
4097 }
4098 }
4099 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004100 }
4101
4102 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4103 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4104 for (; it != report_blocks.end(); ++it) {
4105 if (it->remoteSSRC == remoteSSRC)
4106 break;
4107 }
4108 if (it == report_blocks.end()) {
4109 // We have not received packets with SSRC matching the report blocks.
4110 // To calculate RTT we try with the SSRC of the first report block.
4111 // This is very important for send-only channels where we don't know
4112 // the SSRC of the other end.
4113 remoteSSRC = report_blocks[0].remoteSSRC;
4114 }
Minyue2013aec2015-05-13 14:14:42 +02004115
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004116 int64_t avg_rtt = 0;
4117 int64_t max_rtt= 0;
4118 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004119 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4120 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004121 return 0;
4122 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004123 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004124}
4125
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004126} // namespace voe
4127} // namespace webrtc