blob: 46e04ba88241c135f893a3d66a3189cd67b5c966 [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
2927void Channel::SetCongestionControlObjects(
2928 RtpPacketSender* rtp_packet_sender,
2929 TransportFeedbackObserver* transport_feedback_observer,
2930 PacketRouter* packet_router) {
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002931 RTC_DCHECK(packet_router != nullptr || packet_router_ != nullptr);
Stefan Holmer3842c5c2016-01-12 13:55:00 +01002932 if (transport_feedback_observer) {
2933 RTC_DCHECK(feedback_observer_proxy_.get());
2934 feedback_observer_proxy_->SetTransportFeedbackObserver(
2935 transport_feedback_observer);
2936 }
2937 if (rtp_packet_sender) {
2938 RTC_DCHECK(rtp_packet_sender_proxy_.get());
2939 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2940 }
2941 if (seq_num_allocator_proxy_.get()) {
2942 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2943 }
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002944 _rtpRtcpModule->SetStorePacketsStatus(rtp_packet_sender != nullptr, 600);
2945 if (packet_router != nullptr) {
2946 packet_router->AddRtpModule(_rtpRtcpModule.get());
2947 } else {
2948 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
2949 }
2950 packet_router_ = packet_router;
2951}
2952
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002953void Channel::SetRTCPStatus(bool enable) {
2954 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2955 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002956 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002957}
2958
2959int
2960Channel::GetRTCPStatus(bool& enabled)
2961{
pbosda903ea2015-10-02 02:36:56 -07002962 RtcpMode method = _rtpRtcpModule->RTCP();
2963 enabled = (method != RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002964 return 0;
2965}
2966
2967int
2968Channel::SetRTCP_CNAME(const char cName[256])
2969{
2970 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2971 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002972 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002973 {
2974 _engineStatisticsPtr->SetLastError(
2975 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2976 "SetRTCP_CNAME() failed to set RTCP CNAME");
2977 return -1;
2978 }
2979 return 0;
2980}
2981
2982int
niklase@google.com470e71d2011-07-07 08:21:25 +00002983Channel::GetRemoteRTCP_CNAME(char cName[256])
2984{
2985 if (cName == NULL)
2986 {
2987 _engineStatisticsPtr->SetLastError(
2988 VE_INVALID_ARGUMENT, kTraceError,
2989 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2990 return -1;
2991 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002992 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002993 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002994 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002995 {
2996 _engineStatisticsPtr->SetLastError(
2997 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2998 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2999 return -1;
3000 }
3001 strcpy(cName, cname);
niklase@google.com470e71d2011-07-07 08:21:25 +00003002 return 0;
3003}
3004
3005int
3006Channel::GetRemoteRTCPData(
3007 unsigned int& NTPHigh,
3008 unsigned int& NTPLow,
3009 unsigned int& timestamp,
3010 unsigned int& playoutTimestamp,
3011 unsigned int* jitter,
3012 unsigned short* fractionLost)
3013{
3014 // --- Information from sender info in received Sender Reports
3015
3016 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003017 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003018 {
3019 _engineStatisticsPtr->SetLastError(
3020 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003021 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003022 "side");
3023 return -1;
3024 }
3025
3026 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3027 // and octet count)
3028 NTPHigh = senderInfo.NTPseconds;
3029 NTPLow = senderInfo.NTPfraction;
3030 timestamp = senderInfo.RTPtimeStamp;
3031
niklase@google.com470e71d2011-07-07 08:21:25 +00003032 // --- Locally derived information
3033
3034 // This value is updated on each incoming RTCP packet (0 when no packet
3035 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003036 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003037
niklase@google.com470e71d2011-07-07 08:21:25 +00003038 if (NULL != jitter || NULL != fractionLost)
3039 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003040 // Get all RTCP receiver report blocks that have been received on this
3041 // channel. If we receive RTP packets from a remote source we know the
3042 // remote SSRC and use the report block from him.
3043 // Otherwise use the first report block.
3044 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003045 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003046 remote_stats.empty()) {
3047 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3048 VoEId(_instanceId, _channelId),
3049 "GetRemoteRTCPData() failed to measure statistics due"
3050 " to lack of received RTP and/or RTCP packets");
3051 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003052 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003053
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003054 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003055 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3056 for (; it != remote_stats.end(); ++it) {
3057 if (it->remoteSSRC == remoteSSRC)
3058 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003059 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003060
3061 if (it == remote_stats.end()) {
3062 // If we have not received any RTCP packets from this SSRC it probably
3063 // means that we have not received any RTP packets.
3064 // Use the first received report block instead.
3065 it = remote_stats.begin();
3066 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003067 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003068
xians@webrtc.org79af7342012-01-31 12:22:14 +00003069 if (jitter) {
3070 *jitter = it->jitter;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003071 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003072
xians@webrtc.org79af7342012-01-31 12:22:14 +00003073 if (fractionLost) {
3074 *fractionLost = it->fractionLost;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003075 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003076 }
3077 return 0;
3078}
3079
3080int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003081Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003082 unsigned int name,
3083 const char* data,
3084 unsigned short dataLengthInBytes)
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3087 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003088 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003089 {
3090 _engineStatisticsPtr->SetLastError(
3091 VE_NOT_SENDING, kTraceError,
3092 "SendApplicationDefinedRTCPPacket() not sending");
3093 return -1;
3094 }
3095 if (NULL == data)
3096 {
3097 _engineStatisticsPtr->SetLastError(
3098 VE_INVALID_ARGUMENT, kTraceError,
3099 "SendApplicationDefinedRTCPPacket() invalid data value");
3100 return -1;
3101 }
3102 if (dataLengthInBytes % 4 != 0)
3103 {
3104 _engineStatisticsPtr->SetLastError(
3105 VE_INVALID_ARGUMENT, kTraceError,
3106 "SendApplicationDefinedRTCPPacket() invalid length value");
3107 return -1;
3108 }
pbosda903ea2015-10-02 02:36:56 -07003109 RtcpMode status = _rtpRtcpModule->RTCP();
3110 if (status == RtcpMode::kOff) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003111 _engineStatisticsPtr->SetLastError(
3112 VE_RTCP_ERROR, kTraceError,
3113 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3114 return -1;
3115 }
3116
3117 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003118 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 subType,
3120 name,
3121 (const unsigned char*) data,
3122 dataLengthInBytes) != 0)
3123 {
3124 _engineStatisticsPtr->SetLastError(
3125 VE_SEND_ERROR, kTraceError,
3126 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3127 return -1;
3128 }
3129 return 0;
3130}
3131
3132int
3133Channel::GetRTPStatistics(
3134 unsigned int& averageJitterMs,
3135 unsigned int& maxJitterMs,
3136 unsigned int& discardedPackets)
3137{
niklase@google.com470e71d2011-07-07 08:21:25 +00003138 // The jitter statistics is updated for each received RTP packet and is
3139 // based on received packets.
pbosda903ea2015-10-02 02:36:56 -07003140 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003141 // If RTCP is off, there is no timed thread in the RTCP module regularly
3142 // generating new stats, trigger the update manually here instead.
3143 StreamStatistician* statistician =
3144 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3145 if (statistician) {
3146 // Don't use returned statistics, use data from proxy instead so that
3147 // max jitter can be fetched atomically.
3148 RtcpStatistics s;
3149 statistician->GetStatistics(&s, true);
3150 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003151 }
3152
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003153 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003154 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003155 if (playoutFrequency > 0) {
3156 // Scale RTP statistics given the current playout frequency
3157 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3158 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003159 }
3160
3161 discardedPackets = _numberOfDiscardedPackets;
3162
niklase@google.com470e71d2011-07-07 08:21:25 +00003163 return 0;
3164}
3165
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003166int Channel::GetRemoteRTCPReportBlocks(
3167 std::vector<ReportBlock>* report_blocks) {
3168 if (report_blocks == NULL) {
3169 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3170 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3171 return -1;
3172 }
3173
3174 // Get the report blocks from the latest received RTCP Sender or Receiver
3175 // Report. Each element in the vector contains the sender's SSRC and a
3176 // report block according to RFC 3550.
3177 std::vector<RTCPReportBlock> rtcp_report_blocks;
3178 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003179 return -1;
3180 }
3181
3182 if (rtcp_report_blocks.empty())
3183 return 0;
3184
3185 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3186 for (; it != rtcp_report_blocks.end(); ++it) {
3187 ReportBlock report_block;
3188 report_block.sender_SSRC = it->remoteSSRC;
3189 report_block.source_SSRC = it->sourceSSRC;
3190 report_block.fraction_lost = it->fractionLost;
3191 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3192 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3193 report_block.interarrival_jitter = it->jitter;
3194 report_block.last_SR_timestamp = it->lastSR;
3195 report_block.delay_since_last_SR = it->delaySinceLastSR;
3196 report_blocks->push_back(report_block);
3197 }
3198 return 0;
3199}
3200
niklase@google.com470e71d2011-07-07 08:21:25 +00003201int
3202Channel::GetRTPStatistics(CallStatistics& stats)
3203{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003204 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003205
3206 // The jitter statistics is updated for each received RTP packet and is
3207 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003208 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003209 StreamStatistician* statistician =
3210 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
pbosda903ea2015-10-02 02:36:56 -07003211 if (!statistician ||
3212 !statistician->GetStatistics(
3213 &statistics, _rtpRtcpModule->RTCP() == RtcpMode::kOff)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003214 _engineStatisticsPtr->SetLastError(
3215 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3216 "GetRTPStatistics() failed to read RTP statistics from the "
3217 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003218 }
3219
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003220 stats.fractionLost = statistics.fraction_lost;
3221 stats.cumulativeLost = statistics.cumulative_lost;
3222 stats.extendedMax = statistics.extended_max_sequence_number;
3223 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003224
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003225 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003226 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003227
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003228 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003229
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003230 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003231 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003232 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003233 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003234
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003235 if (statistician) {
3236 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3237 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003238
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003239 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003240 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003241 {
3242 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3243 VoEId(_instanceId, _channelId),
3244 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003245 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003246 }
3247
3248 stats.bytesSent = bytesSent;
3249 stats.packetsSent = packetsSent;
3250 stats.bytesReceived = bytesReceived;
3251 stats.packetsReceived = packetsReceived;
3252
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003253 // --- Timestamps
3254 {
3255 CriticalSectionScoped lock(ts_stats_lock_.get());
3256 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3257 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003258 return 0;
3259}
3260
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003261int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003262 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003263 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003264
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003265 if (enable) {
3266 if (redPayloadtype < 0 || redPayloadtype > 127) {
3267 _engineStatisticsPtr->SetLastError(
3268 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003269 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003270 return -1;
3271 }
3272
3273 if (SetRedPayloadType(redPayloadtype) < 0) {
3274 _engineStatisticsPtr->SetLastError(
3275 VE_CODEC_ERROR, kTraceError,
3276 "SetSecondarySendCodec() Failed to register RED ACM");
3277 return -1;
3278 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003279 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003280
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003281 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003282 _engineStatisticsPtr->SetLastError(
3283 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003284 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003285 return -1;
3286 }
3287 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003288}
3289
3290int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003291Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003292{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003293 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003294 if (enabled)
3295 {
danilchap5c1def82015-12-10 09:51:54 -08003296 int8_t payloadType = 0;
3297 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003298 _engineStatisticsPtr->SetLastError(
3299 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003300 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003301 "module");
3302 return -1;
3303 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003304 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003305 return 0;
3306 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003307 return 0;
3308}
3309
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003310int Channel::SetCodecFECStatus(bool enable) {
3311 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3312 "Channel::SetCodecFECStatus()");
3313
3314 if (audio_coding_->SetCodecFEC(enable) != 0) {
3315 _engineStatisticsPtr->SetLastError(
3316 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3317 "SetCodecFECStatus() failed to set FEC state");
3318 return -1;
3319 }
3320 return 0;
3321}
3322
3323bool Channel::GetCodecFECStatus() {
3324 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003325 return enabled;
3326}
3327
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003328void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3329 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01003330 // If pacing is enabled we always store packets.
3331 if (!pacing_enabled_)
3332 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003333 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3334 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003335 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003336 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003337 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003338 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003339}
3340
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003341// Called when we are missing one or more packets.
3342int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003343 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3344}
3345
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003346uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003347Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003348{
3349 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003350 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003351 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003352 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003353 return 0;
3354}
3355
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003356void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003357 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003358 size_t number_of_frames,
Peter Kasting69558702016-01-12 16:26:35 -08003359 size_t number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003360 CodecInst codec;
3361 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003362
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07003363 // Never upsample or upmix the capture signal here. This should be done at the
3364 // end of the send chain.
3365 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3366 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3367 RemixAndResample(audio_data, number_of_frames, number_of_channels,
3368 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003369}
3370
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003371uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003372Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003373{
3374 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3375 "Channel::PrepareEncodeAndSend()");
3376
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003377 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003378 {
3379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3380 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003381 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003382 }
3383
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003384 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003385 {
3386 MixOrReplaceAudioWithFile(mixingFrequency);
3387 }
3388
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003389 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3390 if (is_muted) {
3391 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003392 }
3393
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003394 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003395 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003396 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003397 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003398 if (_inputExternalMediaCallbackPtr)
3399 {
3400 _inputExternalMediaCallbackPtr->Process(
3401 _channelId,
3402 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003403 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003404 _audioFrame.samples_per_channel_,
3405 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003406 isStereo);
3407 }
3408 }
3409
3410 InsertInbandDtmfTone();
3411
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003412 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003413 size_t length =
3414 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003415 if (is_muted) {
3416 rms_level_.ProcessMuted(length);
3417 } else {
3418 rms_level_.Process(_audioFrame.data_, length);
3419 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003420 }
3421
niklase@google.com470e71d2011-07-07 08:21:25 +00003422 return 0;
3423}
3424
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003425uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003426Channel::EncodeAndSend()
3427{
3428 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3429 "Channel::EncodeAndSend()");
3430
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003431 assert(_audioFrame.num_channels_ <= 2);
3432 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003433 {
3434 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3435 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003436 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003437 }
3438
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003439 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003440
3441 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3442
3443 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003444 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003445 // This call will trigger AudioPacketizationCallback::SendData if encoding
3446 // is done and payload is ready for packetization and transmission.
3447 // Otherwise, it will return without invoking the callback.
3448 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003449 {
3450 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3451 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003452 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003453 }
3454
Peter Kastingb7e50542015-06-11 12:55:50 -07003455 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003456 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003457}
3458
Minyue2013aec2015-05-13 14:14:42 +02003459void Channel::DisassociateSendChannel(int channel_id) {
3460 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3461 Channel* channel = associate_send_channel_.channel();
3462 if (channel && channel->ChannelId() == channel_id) {
3463 // If this channel is associated with a send channel of the specified
3464 // Channel ID, disassociate with it.
3465 ChannelOwner ref(NULL);
3466 associate_send_channel_ = ref;
3467 }
3468}
3469
niklase@google.com470e71d2011-07-07 08:21:25 +00003470int Channel::RegisterExternalMediaProcessing(
3471 ProcessingTypes type,
3472 VoEMediaProcess& processObject)
3473{
3474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3475 "Channel::RegisterExternalMediaProcessing()");
3476
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003477 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003478
3479 if (kPlaybackPerChannel == type)
3480 {
3481 if (_outputExternalMediaCallbackPtr)
3482 {
3483 _engineStatisticsPtr->SetLastError(
3484 VE_INVALID_OPERATION, kTraceError,
3485 "Channel::RegisterExternalMediaProcessing() "
3486 "output external media already enabled");
3487 return -1;
3488 }
3489 _outputExternalMediaCallbackPtr = &processObject;
3490 _outputExternalMedia = true;
3491 }
3492 else if (kRecordingPerChannel == type)
3493 {
3494 if (_inputExternalMediaCallbackPtr)
3495 {
3496 _engineStatisticsPtr->SetLastError(
3497 VE_INVALID_OPERATION, kTraceError,
3498 "Channel::RegisterExternalMediaProcessing() "
3499 "output external media already enabled");
3500 return -1;
3501 }
3502 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003503 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 }
3505 return 0;
3506}
3507
3508int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3509{
3510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3511 "Channel::DeRegisterExternalMediaProcessing()");
3512
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003513 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003514
3515 if (kPlaybackPerChannel == type)
3516 {
3517 if (!_outputExternalMediaCallbackPtr)
3518 {
3519 _engineStatisticsPtr->SetLastError(
3520 VE_INVALID_OPERATION, kTraceWarning,
3521 "Channel::DeRegisterExternalMediaProcessing() "
3522 "output external media already disabled");
3523 return 0;
3524 }
3525 _outputExternalMedia = false;
3526 _outputExternalMediaCallbackPtr = NULL;
3527 }
3528 else if (kRecordingPerChannel == type)
3529 {
3530 if (!_inputExternalMediaCallbackPtr)
3531 {
3532 _engineStatisticsPtr->SetLastError(
3533 VE_INVALID_OPERATION, kTraceWarning,
3534 "Channel::DeRegisterExternalMediaProcessing() "
3535 "input external media already disabled");
3536 return 0;
3537 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003538 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003539 _inputExternalMediaCallbackPtr = NULL;
3540 }
3541
3542 return 0;
3543}
3544
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003545int Channel::SetExternalMixing(bool enabled) {
3546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3547 "Channel::SetExternalMixing(enabled=%d)", enabled);
3548
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003549 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003550 {
3551 _engineStatisticsPtr->SetLastError(
3552 VE_INVALID_OPERATION, kTraceError,
3553 "Channel::SetExternalMixing() "
3554 "external mixing cannot be changed while playing.");
3555 return -1;
3556 }
3557
3558 _externalMixing = enabled;
3559
3560 return 0;
3561}
3562
niklase@google.com470e71d2011-07-07 08:21:25 +00003563int
niklase@google.com470e71d2011-07-07 08:21:25 +00003564Channel::GetNetworkStatistics(NetworkStatistics& stats)
3565{
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003566 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003567}
3568
wu@webrtc.org24301a62013-12-13 19:17:43 +00003569void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3570 audio_coding_->GetDecodingCallStatistics(stats);
3571}
3572
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003573bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3574 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003575 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003576 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003577 return false;
3578 }
3579 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3580 _recPacketDelayMs;
3581 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003582 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003583}
3584
solenberg358057b2015-11-27 10:46:42 -08003585uint32_t Channel::GetDelayEstimate() const {
3586 int jitter_buffer_delay_ms = 0;
3587 int playout_buffer_delay_ms = 0;
3588 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3589 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3590}
3591
deadbeef74375882015-08-13 12:09:10 -07003592int Channel::LeastRequiredDelayMs() const {
3593 return audio_coding_->LeastRequiredDelayMs();
3594}
3595
niklase@google.com470e71d2011-07-07 08:21:25 +00003596int
3597Channel::SetMinimumPlayoutDelay(int delayMs)
3598{
3599 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3600 "Channel::SetMinimumPlayoutDelay()");
3601 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3602 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_INVALID_ARGUMENT, kTraceError,
3606 "SetMinimumPlayoutDelay() invalid min delay");
3607 return -1;
3608 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003609 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003610 {
3611 _engineStatisticsPtr->SetLastError(
3612 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3613 "SetMinimumPlayoutDelay() failed to set min playout delay");
3614 return -1;
3615 }
3616 return 0;
3617}
3618
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003619int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003620 uint32_t playout_timestamp_rtp = 0;
3621 {
3622 CriticalSectionScoped cs(video_sync_lock_.get());
3623 playout_timestamp_rtp = playout_timestamp_rtp_;
3624 }
3625 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003626 _engineStatisticsPtr->SetLastError(
3627 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3628 "GetPlayoutTimestamp() failed to retrieve timestamp");
3629 return -1;
3630 }
deadbeef74375882015-08-13 12:09:10 -07003631 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003632 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003633}
3634
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003635int Channel::SetInitTimestamp(unsigned int timestamp) {
3636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003637 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003638 if (channel_state_.Get().sending) {
3639 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3640 "SetInitTimestamp() already sending");
3641 return -1;
3642 }
3643 _rtpRtcpModule->SetStartTimestamp(timestamp);
3644 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003645}
3646
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003647int Channel::SetInitSequenceNumber(short sequenceNumber) {
3648 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3649 "Channel::SetInitSequenceNumber()");
3650 if (channel_state_.Get().sending) {
3651 _engineStatisticsPtr->SetLastError(
3652 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3653 return -1;
3654 }
3655 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3656 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003657}
3658
3659int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003660Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003661{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003662 *rtpRtcpModule = _rtpRtcpModule.get();
3663 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003664 return 0;
3665}
3666
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003667// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3668// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003669int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003670Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003671{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003672 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003673 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003674
3675 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003676 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003677
3678 if (_inputFilePlayerPtr == NULL)
3679 {
3680 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3681 VoEId(_instanceId, _channelId),
3682 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3683 " doesnt exist");
3684 return -1;
3685 }
3686
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003687 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003688 fileSamples,
3689 mixingFrequency) == -1)
3690 {
3691 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3692 VoEId(_instanceId, _channelId),
3693 "Channel::MixOrReplaceAudioWithFile() file mixing "
3694 "failed");
3695 return -1;
3696 }
3697 if (fileSamples == 0)
3698 {
3699 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3700 VoEId(_instanceId, _channelId),
3701 "Channel::MixOrReplaceAudioWithFile() file is ended");
3702 return 0;
3703 }
3704 }
3705
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003706 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003707
3708 if (_mixFileWithMicrophone)
3709 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003710 // Currently file stream is always mono.
3711 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003712 MixWithSat(_audioFrame.data_,
3713 _audioFrame.num_channels_,
3714 fileBuffer.get(),
3715 1,
3716 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003717 }
3718 else
3719 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003720 // Replace ACM audio with file.
3721 // Currently file stream is always mono.
3722 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003723 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003724 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003725 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003726 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003727 mixingFrequency,
3728 AudioFrame::kNormalSpeech,
3729 AudioFrame::kVadUnknown,
3730 1);
3731
3732 }
3733 return 0;
3734}
3735
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003736int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003737Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003738 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003739{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003740 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003741
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003742 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003743 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003744
3745 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003746 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003747
3748 if (_outputFilePlayerPtr == NULL)
3749 {
3750 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3751 VoEId(_instanceId, _channelId),
3752 "Channel::MixAudioWithFile() file mixing failed");
3753 return -1;
3754 }
3755
3756 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003757 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003758 fileSamples,
3759 mixingFrequency) == -1)
3760 {
3761 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3762 VoEId(_instanceId, _channelId),
3763 "Channel::MixAudioWithFile() file mixing failed");
3764 return -1;
3765 }
3766 }
3767
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003768 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003769 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003770 // Currently file stream is always mono.
3771 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003772 MixWithSat(audioFrame.data_,
3773 audioFrame.num_channels_,
3774 fileBuffer.get(),
3775 1,
3776 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003777 }
3778 else
3779 {
3780 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003781 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3782 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003783 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003784 return -1;
3785 }
3786
3787 return 0;
3788}
3789
3790int
3791Channel::InsertInbandDtmfTone()
3792{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003793 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003794 if (_inbandDtmfQueue.PendingDtmf() &&
3795 !_inbandDtmfGenerator.IsAddingTone() &&
3796 _inbandDtmfGenerator.DelaySinceLastTone() >
3797 kMinTelephoneEventSeparationMs)
3798 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003799 int8_t eventCode(0);
3800 uint16_t lengthMs(0);
3801 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003802
3803 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3804 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3805 if (_playInbandDtmfEvent)
3806 {
3807 // Add tone to output mixer using a reduced length to minimize
3808 // risk of echo.
3809 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3810 attenuationDb);
3811 }
3812 }
3813
3814 if (_inbandDtmfGenerator.IsAddingTone())
3815 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003816 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003817 _inbandDtmfGenerator.GetSampleRate(frequency);
3818
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003819 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003820 {
3821 // Update sample rate of Dtmf tone since the mixing frequency
3822 // has changed.
3823 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003824 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003825 // Reset the tone to be added taking the new sample rate into
3826 // account.
3827 _inbandDtmfGenerator.ResetTone();
3828 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003829
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003830 int16_t toneBuffer[320];
3831 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003832 // Get 10ms tone segment and set time since last tone to zero
3833 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3834 {
3835 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3836 VoEId(_instanceId, _channelId),
3837 "Channel::EncodeAndSend() inserting Dtmf failed");
3838 return -1;
3839 }
3840
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003841 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003842 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003843 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003844 sample++)
3845 {
Peter Kasting69558702016-01-12 16:26:35 -08003846 for (size_t channel = 0;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003847 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003848 channel++)
3849 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003850 const size_t index =
3851 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003852 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003853 }
3854 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003855
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003856 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003857 } else
3858 {
3859 // Add 10ms to "delay-since-last-tone" counter
3860 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3861 }
3862 return 0;
3863}
3864
deadbeef74375882015-08-13 12:09:10 -07003865void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3866 uint32_t playout_timestamp = 0;
3867
3868 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3869 // This can happen if this channel has not been received any RTP packet. In
3870 // this case, NetEq is not capable of computing playout timestamp.
3871 return;
3872 }
3873
3874 uint16_t delay_ms = 0;
3875 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3876 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3877 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3878 " delay from the ADM");
3879 _engineStatisticsPtr->SetLastError(
3880 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3881 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3882 return;
3883 }
3884
3885 jitter_buffer_playout_timestamp_ = playout_timestamp;
3886
3887 // Remove the playout delay.
3888 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3889
3890 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3891 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3892 playout_timestamp);
3893
3894 {
3895 CriticalSectionScoped cs(video_sync_lock_.get());
3896 if (rtcp) {
3897 playout_timestamp_rtcp_ = playout_timestamp;
3898 } else {
3899 playout_timestamp_rtp_ = playout_timestamp;
3900 }
3901 playout_delay_ms_ = delay_ms;
3902 }
3903}
3904
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003905// Called for incoming RTP packets after successful RTP header parsing.
3906void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3907 uint16_t sequence_number) {
3908 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3909 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3910 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003911
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003912 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003913 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003914
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003915 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3916 // every incoming packet.
3917 uint32_t timestamp_diff_ms = (rtp_timestamp -
3918 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003919 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3920 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3921 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3922 // timestamp, the resulting difference is negative, but is set to zero.
3923 // This can happen when a network glitch causes a packet to arrive late,
3924 // and during long comfort noise periods with clock drift.
3925 timestamp_diff_ms = 0;
3926 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003927
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003928 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3929 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003930
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003931 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003932
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003933 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003934
deadbeef74375882015-08-13 12:09:10 -07003935 {
3936 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003937
deadbeef74375882015-08-13 12:09:10 -07003938 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3939 _recPacketDelayMs = packet_delay_ms;
3940 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003941
deadbeef74375882015-08-13 12:09:10 -07003942 if (_average_jitter_buffer_delay_us == 0) {
3943 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3944 return;
3945 }
3946
3947 // Filter average delay value using exponential filter (alpha is
3948 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3949 // risk of rounding error) and compensate for it in GetDelayEstimate()
3950 // later.
3951 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3952 1000 * timestamp_diff_ms + 500) / 8;
3953 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003954}
3955
3956void
3957Channel::RegisterReceiveCodecsToRTPModule()
3958{
3959 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3960 "Channel::RegisterReceiveCodecsToRTPModule()");
3961
niklase@google.com470e71d2011-07-07 08:21:25 +00003962 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003963 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003964
3965 for (int idx = 0; idx < nSupportedCodecs; idx++)
3966 {
3967 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003968 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003969 (rtp_receiver_->RegisterReceivePayload(
3970 codec.plname,
3971 codec.pltype,
3972 codec.plfreq,
3973 codec.channels,
3974 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003975 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003976 WEBRTC_TRACE(kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00003977 kTraceVoice,
3978 VoEId(_instanceId, _channelId),
3979 "Channel::RegisterReceiveCodecsToRTPModule() unable"
Peter Kasting69558702016-01-12 16:26:35 -08003980 " to register %s (%d/%d/%" PRIuS "/%d) to RTP/RTCP "
3981 "receiver",
niklase@google.com470e71d2011-07-07 08:21:25 +00003982 codec.plname, codec.pltype, codec.plfreq,
3983 codec.channels, codec.rate);
3984 }
3985 else
3986 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003987 WEBRTC_TRACE(kTraceInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +00003988 kTraceVoice,
3989 VoEId(_instanceId, _channelId),
3990 "Channel::RegisterReceiveCodecsToRTPModule() %s "
Peter Kasting69558702016-01-12 16:26:35 -08003991 "(%d/%d/%" PRIuS "/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003992 "receiver",
3993 codec.plname, codec.pltype, codec.plfreq,
3994 codec.channels, codec.rate);
3995 }
3996 }
3997}
3998
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003999// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004000int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004001 CodecInst codec;
4002 bool found_red = false;
4003
4004 // Get default RED settings from the ACM database
4005 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4006 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004007 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004008 if (!STR_CASE_CMP(codec.plname, "RED")) {
4009 found_red = true;
4010 break;
4011 }
4012 }
4013
4014 if (!found_red) {
4015 _engineStatisticsPtr->SetLastError(
4016 VE_CODEC_ERROR, kTraceError,
4017 "SetRedPayloadType() RED is not supported");
4018 return -1;
4019 }
4020
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004021 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004022 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004023 _engineStatisticsPtr->SetLastError(
4024 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4025 "SetRedPayloadType() RED registration in ACM module failed");
4026 return -1;
4027 }
4028
4029 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4030 _engineStatisticsPtr->SetLastError(
4031 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4032 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4033 return -1;
4034 }
4035 return 0;
4036}
4037
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004038int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4039 unsigned char id) {
4040 int error = 0;
4041 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4042 if (enable) {
4043 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4044 }
4045 return error;
4046}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004047
wu@webrtc.org94454b72014-06-05 20:34:08 +00004048int32_t Channel::GetPlayoutFrequency() {
4049 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4050 CodecInst current_recive_codec;
4051 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4052 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4053 // Even though the actual sampling rate for G.722 audio is
4054 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4055 // 8,000 Hz because that value was erroneously assigned in
4056 // RFC 1890 and must remain unchanged for backward compatibility.
4057 playout_frequency = 8000;
4058 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4059 // We are resampling Opus internally to 32,000 Hz until all our
4060 // DSP routines can operate at 48,000 Hz, but the RTP clock
4061 // rate for the Opus payload format is standardized to 48,000 Hz,
4062 // because that is the maximum supported decoding sampling rate.
4063 playout_frequency = 48000;
4064 }
4065 }
4066 return playout_frequency;
4067}
4068
Minyue2013aec2015-05-13 14:14:42 +02004069int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07004070 RtcpMode method = _rtpRtcpModule->RTCP();
4071 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004072 return 0;
4073 }
4074 std::vector<RTCPReportBlock> report_blocks;
4075 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004076
4077 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004078 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004079 if (allow_associate_channel) {
4080 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4081 Channel* channel = associate_send_channel_.channel();
4082 // Tries to get RTT from an associated channel. This is important for
4083 // receive-only channels.
4084 if (channel) {
4085 // To prevent infinite recursion and deadlock, calling GetRTT of
4086 // associate channel should always use "false" for argument:
4087 // |allow_associate_channel|.
4088 rtt = channel->GetRTT(false);
4089 }
4090 }
4091 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004092 }
4093
4094 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4095 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4096 for (; it != report_blocks.end(); ++it) {
4097 if (it->remoteSSRC == remoteSSRC)
4098 break;
4099 }
4100 if (it == report_blocks.end()) {
4101 // We have not received packets with SSRC matching the report blocks.
4102 // To calculate RTT we try with the SSRC of the first report block.
4103 // This is very important for send-only channels where we don't know
4104 // the SSRC of the other end.
4105 remoteSSRC = report_blocks[0].remoteSSRC;
4106 }
Minyue2013aec2015-05-13 14:14:42 +02004107
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004108 int64_t avg_rtt = 0;
4109 int64_t max_rtt= 0;
4110 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004111 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4112 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004113 return 0;
4114 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004115 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004116}
4117
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004118} // namespace voe
4119} // namespace webrtc