blob: 64b40a864ba57221a8d3e469b4a48ca00c862674 [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,
422 uint8_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, "
niklase@google.com470e71d2011-07-07 08:21:25 +0000426 "payloadName=%s, frequency=%u, channels=%u, 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 ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000462 " payloadType=%u, audioChannel=%u)",
463 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();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000925
926 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000927
928 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
929 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
930 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000931
932 Config audioproc_config;
933 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
934 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000935}
936
937Channel::~Channel()
938{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000939 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
941 "Channel::~Channel() - dtor");
942
943 if (_outputExternalMedia)
944 {
945 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
946 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000947 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 {
949 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
950 }
951 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000952 StopPlayout();
953
954 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000955 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 if (_inputFilePlayerPtr)
957 {
958 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
959 _inputFilePlayerPtr->StopPlayingFile();
960 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
961 _inputFilePlayerPtr = NULL;
962 }
963 if (_outputFilePlayerPtr)
964 {
965 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
966 _outputFilePlayerPtr->StopPlayingFile();
967 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
968 _outputFilePlayerPtr = NULL;
969 }
970 if (_outputFileRecorderPtr)
971 {
972 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
973 _outputFileRecorderPtr->StopRecording();
974 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
975 _outputFileRecorderPtr = NULL;
976 }
977 }
978
979 // The order to safely shutdown modules in a channel is:
980 // 1. De-register callbacks in modules
981 // 2. De-register modules in process thread
982 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000983 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 {
985 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
986 VoEId(_instanceId,_channelId),
987 "~Channel() failed to de-register transport callback"
988 " (Audio coding module)");
989 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000990 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 {
992 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
993 VoEId(_instanceId,_channelId),
994 "~Channel() failed to de-register VAD callback"
995 " (Audio coding module)");
996 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000998 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
999
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 // End of modules shutdown
1001
1002 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001005 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001006}
1007
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001008int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001009Channel::Init()
1010{
1011 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1012 "Channel::Init()");
1013
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001014 channel_state_.Reset();
1015
niklase@google.com470e71d2011-07-07 08:21:25 +00001016 // --- Initial sanity
1017
1018 if ((_engineStatisticsPtr == NULL) ||
1019 (_moduleProcessThreadPtr == NULL))
1020 {
1021 WEBRTC_TRACE(kTraceError, kTraceVoice,
1022 VoEId(_instanceId,_channelId),
1023 "Channel::Init() must call SetEngineInformation() first");
1024 return -1;
1025 }
1026
1027 // --- Add modules to process thread (for periodic schedulation)
1028
tommi@webrtc.org3985f012015-02-27 13:36:34 +00001029 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
1030
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001031 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001032
henrik.lundin061b79a2015-09-18 01:29:11 -07001033 if (audio_coding_->InitializeReceiver() == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 _engineStatisticsPtr->SetLastError(
1035 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1036 "Channel::Init() unable to initialize the ACM - 1");
1037 return -1;
1038 }
1039
1040 // --- RTP/RTCP module initialization
1041
1042 // Ensure that RTCP is enabled by default for the created channel.
1043 // Note that, the module will keep generating RTCP until it is explicitly
1044 // disabled by the user.
1045 // After StopListen (when no sockets exists), RTCP packets will no longer
1046 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001047 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1048 // RTCP is enabled by default.
pbosda903ea2015-10-02 02:36:56 -07001049 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001050 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001052 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1053 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
1055 if (fail)
1056 {
1057 _engineStatisticsPtr->SetLastError(
1058 VE_CANNOT_INIT_CHANNEL, kTraceError,
1059 "Channel::Init() callbacks not registered");
1060 return -1;
1061 }
1062
1063 // --- Register all supported codecs to the receiving side of the
1064 // RTP/RTCP module
1065
1066 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001067 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001068
1069 for (int idx = 0; idx < nSupportedCodecs; idx++)
1070 {
1071 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001072 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001073 (rtp_receiver_->RegisterReceivePayload(
1074 codec.plname,
1075 codec.pltype,
1076 codec.plfreq,
1077 codec.channels,
1078 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 {
1080 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1081 VoEId(_instanceId,_channelId),
1082 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1083 "to RTP/RTCP receiver",
1084 codec.plname, codec.pltype, codec.plfreq,
1085 codec.channels, codec.rate);
1086 }
1087 else
1088 {
1089 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1090 VoEId(_instanceId,_channelId),
1091 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1092 "the RTP/RTCP receiver",
1093 codec.plname, codec.pltype, codec.plfreq,
1094 codec.channels, codec.rate);
1095 }
1096
1097 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001098 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 {
1100 SetSendCodec(codec);
1101 }
1102
1103 // Register default PT for outband 'telephone-event'
1104 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1105 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001106 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001107 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 {
1109 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1110 VoEId(_instanceId,_channelId),
1111 "Channel::Init() failed to register outband "
1112 "'telephone-event' (%d/%d) correctly",
1113 codec.pltype, codec.plfreq);
1114 }
1115 }
1116
1117 if (!STR_CASE_CMP(codec.plname, "CN"))
1118 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001119 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1120 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001121 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
1123 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1124 VoEId(_instanceId,_channelId),
1125 "Channel::Init() failed to register CN (%d/%d) "
1126 "correctly - 1",
1127 codec.pltype, codec.plfreq);
1128 }
1129 }
1130#ifdef WEBRTC_CODEC_RED
1131 // Register RED to the receiving side of the ACM.
1132 // We will not receive an OnInitializeDecoder() callback for RED.
1133 if (!STR_CASE_CMP(codec.plname, "RED"))
1134 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001135 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 {
1137 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1138 VoEId(_instanceId,_channelId),
1139 "Channel::Init() failed to register RED (%d/%d) "
1140 "correctly",
1141 codec.pltype, codec.plfreq);
1142 }
1143 }
1144#endif
1145 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001146
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001147 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001148 LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001149 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001151 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001152 LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001153 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 }
1155
1156 return 0;
1157}
1158
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001159int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001160Channel::SetEngineInformation(Statistics& engineStatistics,
1161 OutputMixer& outputMixer,
1162 voe::TransmitMixer& transmitMixer,
1163 ProcessThread& moduleProcessThread,
1164 AudioDeviceModule& audioDeviceModule,
1165 VoiceEngineObserver* voiceEngineObserver,
1166 CriticalSectionWrapper* callbackCritSect)
1167{
1168 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1169 "Channel::SetEngineInformation()");
1170 _engineStatisticsPtr = &engineStatistics;
1171 _outputMixerPtr = &outputMixer;
1172 _transmitMixerPtr = &transmitMixer,
1173 _moduleProcessThreadPtr = &moduleProcessThread;
1174 _audioDeviceModulePtr = &audioDeviceModule;
1175 _voiceEngineObserverPtr = voiceEngineObserver;
1176 _callbackCritSectPtr = callbackCritSect;
1177 return 0;
1178}
1179
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001180int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001181Channel::UpdateLocalTimeStamp()
1182{
1183
Peter Kastingb7e50542015-06-11 12:55:50 -07001184 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 return 0;
1186}
1187
Tommif888bb52015-12-12 01:37:01 +01001188void Channel::SetSink(rtc::scoped_ptr<AudioSinkInterface> sink) {
1189 CriticalSectionScoped cs(&_callbackCritSect);
1190 audio_sink_ = std::move(sink);
1191}
1192
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001193int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001194Channel::StartPlayout()
1195{
1196 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1197 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001198 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 {
1200 return 0;
1201 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001202
1203 if (!_externalMixing) {
1204 // Add participant as candidates for mixing.
1205 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1206 {
1207 _engineStatisticsPtr->SetLastError(
1208 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1209 "StartPlayout() failed to add participant to mixer");
1210 return -1;
1211 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 }
1213
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001214 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001215 if (RegisterFilePlayingToMixer() != 0)
1216 return -1;
1217
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::StopPlayout()
1223{
1224 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1225 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001226 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 {
1228 return 0;
1229 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001230
1231 if (!_externalMixing) {
1232 // Remove participant as candidates for mixing
1233 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1234 {
1235 _engineStatisticsPtr->SetLastError(
1236 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1237 "StopPlayout() failed to remove participant from mixer");
1238 return -1;
1239 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 }
1241
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 _outputAudioLevel.Clear();
1244
1245 return 0;
1246}
1247
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001248int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001249Channel::StartSend()
1250{
1251 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1252 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001253 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001254 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001255 if (send_sequence_number_)
1256 SetInitSequenceNumber(send_sequence_number_);
1257
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001258 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001259 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001260 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001262 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001263
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001264 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001265 {
1266 _engineStatisticsPtr->SetLastError(
1267 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1268 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001269 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001270 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 return -1;
1272 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001273
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 return 0;
1275}
1276
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001277int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001278Channel::StopSend()
1279{
1280 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1281 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001282 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001284 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001285 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001286 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001287
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001288 // Store the sequence number to be able to pick up the same sequence for
1289 // the next StartSend(). This is needed for restarting device, otherwise
1290 // it might cause libSRTP to complain about packets being replayed.
1291 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1292 // CL is landed. See issue
1293 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1294 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1295
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 // Reset sending SSRC and sequence number and triggers direct transmission
1297 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001298 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 {
1300 _engineStatisticsPtr->SetLastError(
1301 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1302 "StartSend() RTP/RTCP failed to stop sending");
1303 }
1304
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 return 0;
1306}
1307
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001308int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001309Channel::StartReceiving()
1310{
1311 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1312 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001313 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 {
1315 return 0;
1316 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001317 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 _numberOfDiscardedPackets = 0;
1319 return 0;
1320}
1321
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001322int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001323Channel::StopReceiving()
1324{
1325 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1326 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001327 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 {
1329 return 0;
1330 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001331
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001332 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001333 return 0;
1334}
1335
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001336int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001337Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1338{
1339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001341 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001342
1343 if (_voiceEngineObserverPtr)
1344 {
1345 _engineStatisticsPtr->SetLastError(
1346 VE_INVALID_OPERATION, kTraceError,
1347 "RegisterVoiceEngineObserver() observer already enabled");
1348 return -1;
1349 }
1350 _voiceEngineObserverPtr = &observer;
1351 return 0;
1352}
1353
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001354int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001355Channel::DeRegisterVoiceEngineObserver()
1356{
1357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1358 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001359 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001360
1361 if (!_voiceEngineObserverPtr)
1362 {
1363 _engineStatisticsPtr->SetLastError(
1364 VE_INVALID_OPERATION, kTraceWarning,
1365 "DeRegisterVoiceEngineObserver() observer already disabled");
1366 return 0;
1367 }
1368 _voiceEngineObserverPtr = NULL;
1369 return 0;
1370}
1371
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001372int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001373Channel::GetSendCodec(CodecInst& codec)
1374{
kwiberg1fd4a4a2015-11-03 11:20:50 -08001375 auto send_codec = audio_coding_->SendCodec();
1376 if (send_codec) {
1377 codec = *send_codec;
1378 return 0;
1379 }
1380 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001381}
1382
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001383int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001384Channel::GetRecCodec(CodecInst& codec)
1385{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001386 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001387}
1388
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001389int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001390Channel::SetSendCodec(const CodecInst& codec)
1391{
1392 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1393 "Channel::SetSendCodec()");
1394
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001395 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001396 {
1397 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1398 "SetSendCodec() failed to register codec to ACM");
1399 return -1;
1400 }
1401
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001402 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001404 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1405 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 {
1407 WEBRTC_TRACE(
1408 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1409 "SetSendCodec() failed to register codec to"
1410 " RTP/RTCP module");
1411 return -1;
1412 }
1413 }
1414
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001415 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 {
1417 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1418 "SetSendCodec() failed to set audio packet size");
1419 return -1;
1420 }
1421
1422 return 0;
1423}
1424
Ivo Creusenadf89b72015-04-29 16:03:33 +02001425void Channel::SetBitRate(int bitrate_bps) {
1426 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1427 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1428 audio_coding_->SetBitRate(bitrate_bps);
1429}
1430
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001431void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001432 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001433 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1434
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001435 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001436 if (audio_coding_->SetPacketLossRate(
1437 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001438 assert(false); // This should not happen.
1439 }
1440}
1441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001442int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001443Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1444{
1445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001447 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001448 // To disable VAD, DTX must be disabled too
1449 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001450 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001451 {
1452 _engineStatisticsPtr->SetLastError(
1453 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1454 "SetVADStatus() failed to set VAD");
1455 return -1;
1456 }
1457 return 0;
1458}
1459
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001460int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001461Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1462{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001463 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 {
1465 _engineStatisticsPtr->SetLastError(
1466 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1467 "GetVADStatus() failed to get VAD status");
1468 return -1;
1469 }
1470 disabledDTX = !disabledDTX;
1471 return 0;
1472}
1473
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001474int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001475Channel::SetRecPayloadType(const CodecInst& codec)
1476{
1477 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1478 "Channel::SetRecPayloadType()");
1479
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001480 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 {
1482 _engineStatisticsPtr->SetLastError(
1483 VE_ALREADY_PLAYING, kTraceError,
1484 "SetRecPayloadType() unable to set PT while playing");
1485 return -1;
1486 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001487 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001488 {
1489 _engineStatisticsPtr->SetLastError(
1490 VE_ALREADY_LISTENING, kTraceError,
1491 "SetRecPayloadType() unable to set PT while listening");
1492 return -1;
1493 }
1494
1495 if (codec.pltype == -1)
1496 {
1497 // De-register the selected codec (RTP/RTCP module and ACM)
1498
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001499 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 CodecInst rxCodec = codec;
1501
1502 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001503 rtp_payload_registry_->ReceivePayloadType(
1504 rxCodec.plname,
1505 rxCodec.plfreq,
1506 rxCodec.channels,
1507 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1508 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001509 rxCodec.pltype = pltype;
1510
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001511 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001512 {
1513 _engineStatisticsPtr->SetLastError(
1514 VE_RTP_RTCP_MODULE_ERROR,
1515 kTraceError,
1516 "SetRecPayloadType() RTP/RTCP-module deregistration "
1517 "failed");
1518 return -1;
1519 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001520 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001521 {
1522 _engineStatisticsPtr->SetLastError(
1523 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1524 "SetRecPayloadType() ACM deregistration failed - 1");
1525 return -1;
1526 }
1527 return 0;
1528 }
1529
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001530 if (rtp_receiver_->RegisterReceivePayload(
1531 codec.plname,
1532 codec.pltype,
1533 codec.plfreq,
1534 codec.channels,
1535 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001536 {
1537 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001538 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1539 if (rtp_receiver_->RegisterReceivePayload(
1540 codec.plname,
1541 codec.pltype,
1542 codec.plfreq,
1543 codec.channels,
1544 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001545 {
1546 _engineStatisticsPtr->SetLastError(
1547 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1548 "SetRecPayloadType() RTP/RTCP-module registration failed");
1549 return -1;
1550 }
1551 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001552 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001553 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001554 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1555 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001556 {
1557 _engineStatisticsPtr->SetLastError(
1558 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1559 "SetRecPayloadType() ACM registration failed - 1");
1560 return -1;
1561 }
1562 }
1563 return 0;
1564}
1565
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001566int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001567Channel::GetRecPayloadType(CodecInst& codec)
1568{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001569 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001570 if (rtp_payload_registry_->ReceivePayloadType(
1571 codec.plname,
1572 codec.plfreq,
1573 codec.channels,
1574 (codec.rate < 0) ? 0 : codec.rate,
1575 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001576 {
1577 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001578 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001579 "GetRecPayloadType() failed to retrieve RX payload type");
1580 return -1;
1581 }
1582 codec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001583 return 0;
1584}
1585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001586int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001587Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1588{
1589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590 "Channel::SetSendCNPayloadType()");
1591
1592 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001593 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001594 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001595 if (frequency == kFreq32000Hz)
1596 samplingFreqHz = 32000;
1597 else if (frequency == kFreq16000Hz)
1598 samplingFreqHz = 16000;
1599
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001600 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001601 {
1602 _engineStatisticsPtr->SetLastError(
1603 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1604 "SetSendCNPayloadType() failed to retrieve default CN codec "
1605 "settings");
1606 return -1;
1607 }
1608
1609 // Modify the payload type (must be set to dynamic range)
1610 codec.pltype = type;
1611
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001612 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001613 {
1614 _engineStatisticsPtr->SetLastError(
1615 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1616 "SetSendCNPayloadType() failed to register CN to ACM");
1617 return -1;
1618 }
1619
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001620 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001622 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1623 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001624 {
1625 _engineStatisticsPtr->SetLastError(
1626 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1627 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1628 "module");
1629 return -1;
1630 }
1631 }
1632 return 0;
1633}
1634
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001635int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001637 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001638
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001639 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001640 _engineStatisticsPtr->SetLastError(
1641 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001642 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001643 return -1;
1644 }
1645 return 0;
1646}
1647
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001648int Channel::SetOpusDtx(bool enable_dtx) {
1649 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1650 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001651 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001652 : audio_coding_->DisableOpusDtx();
1653 if (ret != 0) {
1654 _engineStatisticsPtr->SetLastError(
1655 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1656 return -1;
1657 }
1658 return 0;
1659}
1660
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001661int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001662{
1663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1664 "Channel::RegisterExternalTransport()");
1665
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001666 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001667
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 if (_externalTransport)
1669 {
1670 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1671 kTraceError,
1672 "RegisterExternalTransport() external transport already enabled");
1673 return -1;
1674 }
1675 _externalTransport = true;
1676 _transportPtr = &transport;
1677 return 0;
1678}
1679
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001680int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001681Channel::DeRegisterExternalTransport()
1682{
1683 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1684 "Channel::DeRegisterExternalTransport()");
1685
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001686 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001687
niklase@google.com470e71d2011-07-07 08:21:25 +00001688 if (!_transportPtr)
1689 {
1690 _engineStatisticsPtr->SetLastError(
1691 VE_INVALID_OPERATION, kTraceWarning,
1692 "DeRegisterExternalTransport() external transport already "
1693 "disabled");
1694 return 0;
1695 }
1696 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001697 _transportPtr = NULL;
1698 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1699 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001700 return 0;
1701}
1702
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001703int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001704 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001705 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1706 "Channel::ReceivedRTPPacket()");
1707
1708 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001709 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001710
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001711 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001712 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001713 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1714 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1715 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001716 return -1;
1717 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001718 header.payload_type_frequency =
1719 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001720 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001721 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001722 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001723 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001724 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001725 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001726
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001727 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001728}
1729
1730bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001731 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001732 const RTPHeader& header,
1733 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001734 if (rtp_payload_registry_->IsRtx(header)) {
1735 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001736 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001737 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001738 assert(packet_length >= header.headerLength);
1739 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001740 PayloadUnion payload_specific;
1741 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001742 &payload_specific)) {
1743 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001744 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001745 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1746 payload_specific, in_order);
1747}
1748
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001749bool Channel::HandleRtxPacket(const uint8_t* packet,
1750 size_t packet_length,
1751 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001752 if (!rtp_payload_registry_->IsRtx(header))
1753 return false;
1754
1755 // Remove the RTX header and parse the original RTP header.
1756 if (packet_length < header.headerLength)
1757 return false;
1758 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1759 return false;
1760 if (restored_packet_in_use_) {
1761 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1762 "Multiple RTX headers detected, dropping packet");
1763 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001764 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001765 if (!rtp_payload_registry_->RestoreOriginalPacket(
noahric65220a72015-10-14 11:29:49 -07001766 restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
1767 header)) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001768 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1769 "Incoming RTX packet: invalid RTP header");
1770 return false;
1771 }
1772 restored_packet_in_use_ = true;
noahric65220a72015-10-14 11:29:49 -07001773 bool ret = OnRecoveredPacket(restored_packet_, packet_length);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001774 restored_packet_in_use_ = false;
1775 return ret;
1776}
1777
1778bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1779 StreamStatistician* statistician =
1780 rtp_receive_statistics_->GetStatistician(header.ssrc);
1781 if (!statistician)
1782 return false;
1783 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001784}
1785
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001786bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1787 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001788 // Retransmissions are handled separately if RTX is enabled.
1789 if (rtp_payload_registry_->RtxEnabled())
1790 return false;
1791 StreamStatistician* statistician =
1792 rtp_receive_statistics_->GetStatistician(header.ssrc);
1793 if (!statistician)
1794 return false;
1795 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001796 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001797 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001798 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001799 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001800}
1801
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001802int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001803 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1804 "Channel::ReceivedRTCPPacket()");
1805 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001806 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001807
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001808 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001809 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001810 _engineStatisticsPtr->SetLastError(
1811 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1812 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1813 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001814
Minyue2013aec2015-05-13 14:14:42 +02001815 int64_t rtt = GetRTT(true);
1816 if (rtt == 0) {
1817 // Waiting for valid RTT.
1818 return 0;
1819 }
1820 uint32_t ntp_secs = 0;
1821 uint32_t ntp_frac = 0;
1822 uint32_t rtp_timestamp = 0;
1823 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1824 &rtp_timestamp)) {
1825 // Waiting for RTCP.
1826 return 0;
1827 }
1828
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001829 {
1830 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001831 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001832 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001833 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001834}
1835
niklase@google.com470e71d2011-07-07 08:21:25 +00001836int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001837 bool loop,
1838 FileFormats format,
1839 int startPosition,
1840 float volumeScaling,
1841 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001842 const CodecInst* codecInst)
1843{
1844 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1845 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1846 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1847 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1848 startPosition, stopPosition);
1849
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001850 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001851 {
1852 _engineStatisticsPtr->SetLastError(
1853 VE_ALREADY_PLAYING, kTraceError,
1854 "StartPlayingFileLocally() is already playing");
1855 return -1;
1856 }
1857
niklase@google.com470e71d2011-07-07 08:21:25 +00001858 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001859 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001860
1861 if (_outputFilePlayerPtr)
1862 {
1863 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1864 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1865 _outputFilePlayerPtr = NULL;
1866 }
1867
1868 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1869 _outputFilePlayerId, (const FileFormats)format);
1870
1871 if (_outputFilePlayerPtr == NULL)
1872 {
1873 _engineStatisticsPtr->SetLastError(
1874 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001875 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001876 return -1;
1877 }
1878
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001879 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001880
1881 if (_outputFilePlayerPtr->StartPlayingFile(
1882 fileName,
1883 loop,
1884 startPosition,
1885 volumeScaling,
1886 notificationTime,
1887 stopPosition,
1888 (const CodecInst*)codecInst) != 0)
1889 {
1890 _engineStatisticsPtr->SetLastError(
1891 VE_BAD_FILE, kTraceError,
1892 "StartPlayingFile() failed to start file playout");
1893 _outputFilePlayerPtr->StopPlayingFile();
1894 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1895 _outputFilePlayerPtr = NULL;
1896 return -1;
1897 }
1898 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001899 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001900 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001901
1902 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001903 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001904
1905 return 0;
1906}
1907
1908int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001909 FileFormats format,
1910 int startPosition,
1911 float volumeScaling,
1912 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001913 const CodecInst* codecInst)
1914{
1915 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1916 "Channel::StartPlayingFileLocally(format=%d,"
1917 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1918 format, volumeScaling, startPosition, stopPosition);
1919
1920 if(stream == NULL)
1921 {
1922 _engineStatisticsPtr->SetLastError(
1923 VE_BAD_FILE, kTraceError,
1924 "StartPlayingFileLocally() NULL as input stream");
1925 return -1;
1926 }
1927
1928
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001929 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001930 {
1931 _engineStatisticsPtr->SetLastError(
1932 VE_ALREADY_PLAYING, kTraceError,
1933 "StartPlayingFileLocally() is already playing");
1934 return -1;
1935 }
1936
niklase@google.com470e71d2011-07-07 08:21:25 +00001937 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001938 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001939
1940 // Destroy the old instance
1941 if (_outputFilePlayerPtr)
1942 {
1943 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1944 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1945 _outputFilePlayerPtr = NULL;
1946 }
1947
1948 // Create the instance
1949 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1950 _outputFilePlayerId,
1951 (const FileFormats)format);
1952
1953 if (_outputFilePlayerPtr == NULL)
1954 {
1955 _engineStatisticsPtr->SetLastError(
1956 VE_INVALID_ARGUMENT, kTraceError,
1957 "StartPlayingFileLocally() filePlayer format isnot correct");
1958 return -1;
1959 }
1960
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001961 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001962
1963 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1964 volumeScaling,
1965 notificationTime,
1966 stopPosition, codecInst) != 0)
1967 {
1968 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1969 "StartPlayingFile() failed to "
1970 "start file playout");
1971 _outputFilePlayerPtr->StopPlayingFile();
1972 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1973 _outputFilePlayerPtr = NULL;
1974 return -1;
1975 }
1976 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001977 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001978 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001979
1980 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001981 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001982
niklase@google.com470e71d2011-07-07 08:21:25 +00001983 return 0;
1984}
1985
1986int Channel::StopPlayingFileLocally()
1987{
1988 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1989 "Channel::StopPlayingFileLocally()");
1990
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001991 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001993 return 0;
1994 }
1995
niklase@google.com470e71d2011-07-07 08:21:25 +00001996 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001997 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001998
1999 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2000 {
2001 _engineStatisticsPtr->SetLastError(
2002 VE_STOP_RECORDING_FAILED, kTraceError,
2003 "StopPlayingFile() could not stop playing");
2004 return -1;
2005 }
2006 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2007 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2008 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002009 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002010 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002011 // _fileCritSect cannot be taken while calling
2012 // SetAnonymousMixibilityStatus. Refer to comments in
2013 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002014 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2015 {
2016 _engineStatisticsPtr->SetLastError(
2017 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002018 "StopPlayingFile() failed to stop participant from playing as"
2019 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002020 return -1;
2021 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002022
2023 return 0;
2024}
2025
2026int Channel::IsPlayingFileLocally() const
2027{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002028 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002029}
2030
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002031int Channel::RegisterFilePlayingToMixer()
2032{
2033 // Return success for not registering for file playing to mixer if:
2034 // 1. playing file before playout is started on that channel.
2035 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002036 if (!channel_state_.Get().playing ||
2037 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002038 {
2039 return 0;
2040 }
2041
2042 // |_fileCritSect| cannot be taken while calling
2043 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2044 // frames can be pulled by the mixer. Since the frames are generated from
2045 // the file, _fileCritSect will be taken. This would result in a deadlock.
2046 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2047 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002048 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002049 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002050 _engineStatisticsPtr->SetLastError(
2051 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2052 "StartPlayingFile() failed to add participant as file to mixer");
2053 _outputFilePlayerPtr->StopPlayingFile();
2054 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2055 _outputFilePlayerPtr = NULL;
2056 return -1;
2057 }
2058
2059 return 0;
2060}
2061
niklase@google.com470e71d2011-07-07 08:21:25 +00002062int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002063 bool loop,
2064 FileFormats format,
2065 int startPosition,
2066 float volumeScaling,
2067 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002068 const CodecInst* codecInst)
2069{
2070 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2071 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2072 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2073 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2074 startPosition, stopPosition);
2075
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002076 CriticalSectionScoped cs(&_fileCritSect);
2077
2078 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002079 {
2080 _engineStatisticsPtr->SetLastError(
2081 VE_ALREADY_PLAYING, kTraceWarning,
2082 "StartPlayingFileAsMicrophone() filePlayer is playing");
2083 return 0;
2084 }
2085
niklase@google.com470e71d2011-07-07 08:21:25 +00002086 // Destroy the old instance
2087 if (_inputFilePlayerPtr)
2088 {
2089 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2090 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2091 _inputFilePlayerPtr = NULL;
2092 }
2093
2094 // Create the instance
2095 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2096 _inputFilePlayerId, (const FileFormats)format);
2097
2098 if (_inputFilePlayerPtr == NULL)
2099 {
2100 _engineStatisticsPtr->SetLastError(
2101 VE_INVALID_ARGUMENT, kTraceError,
2102 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2103 return -1;
2104 }
2105
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002106 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002107
2108 if (_inputFilePlayerPtr->StartPlayingFile(
2109 fileName,
2110 loop,
2111 startPosition,
2112 volumeScaling,
2113 notificationTime,
2114 stopPosition,
2115 (const CodecInst*)codecInst) != 0)
2116 {
2117 _engineStatisticsPtr->SetLastError(
2118 VE_BAD_FILE, kTraceError,
2119 "StartPlayingFile() failed to start file playout");
2120 _inputFilePlayerPtr->StopPlayingFile();
2121 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2122 _inputFilePlayerPtr = NULL;
2123 return -1;
2124 }
2125 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002126 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002127
2128 return 0;
2129}
2130
2131int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002132 FileFormats format,
2133 int startPosition,
2134 float volumeScaling,
2135 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002136 const CodecInst* codecInst)
2137{
2138 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2139 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2140 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2141 format, volumeScaling, startPosition, stopPosition);
2142
2143 if(stream == NULL)
2144 {
2145 _engineStatisticsPtr->SetLastError(
2146 VE_BAD_FILE, kTraceError,
2147 "StartPlayingFileAsMicrophone NULL as input stream");
2148 return -1;
2149 }
2150
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002151 CriticalSectionScoped cs(&_fileCritSect);
2152
2153 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002154 {
2155 _engineStatisticsPtr->SetLastError(
2156 VE_ALREADY_PLAYING, kTraceWarning,
2157 "StartPlayingFileAsMicrophone() is playing");
2158 return 0;
2159 }
2160
niklase@google.com470e71d2011-07-07 08:21:25 +00002161 // Destroy the old instance
2162 if (_inputFilePlayerPtr)
2163 {
2164 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2165 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2166 _inputFilePlayerPtr = NULL;
2167 }
2168
2169 // Create the instance
2170 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2171 _inputFilePlayerId, (const FileFormats)format);
2172
2173 if (_inputFilePlayerPtr == NULL)
2174 {
2175 _engineStatisticsPtr->SetLastError(
2176 VE_INVALID_ARGUMENT, kTraceError,
2177 "StartPlayingInputFile() filePlayer format isnot correct");
2178 return -1;
2179 }
2180
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002181 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002182
2183 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2184 volumeScaling, notificationTime,
2185 stopPosition, codecInst) != 0)
2186 {
2187 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2188 "StartPlayingFile() failed to start "
2189 "file playout");
2190 _inputFilePlayerPtr->StopPlayingFile();
2191 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2192 _inputFilePlayerPtr = NULL;
2193 return -1;
2194 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002195
niklase@google.com470e71d2011-07-07 08:21:25 +00002196 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002197 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002198
2199 return 0;
2200}
2201
2202int Channel::StopPlayingFileAsMicrophone()
2203{
2204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2205 "Channel::StopPlayingFileAsMicrophone()");
2206
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002207 CriticalSectionScoped cs(&_fileCritSect);
2208
2209 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002210 {
niklase@google.com470e71d2011-07-07 08:21:25 +00002211 return 0;
2212 }
2213
niklase@google.com470e71d2011-07-07 08:21:25 +00002214 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2215 {
2216 _engineStatisticsPtr->SetLastError(
2217 VE_STOP_RECORDING_FAILED, kTraceError,
2218 "StopPlayingFile() could not stop playing");
2219 return -1;
2220 }
2221 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2222 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2223 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002224 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002225
2226 return 0;
2227}
2228
2229int Channel::IsPlayingFileAsMicrophone() const
2230{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002231 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002232}
2233
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002234int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002235 const CodecInst* codecInst)
2236{
2237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2238 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2239
2240 if (_outputFileRecording)
2241 {
2242 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2243 "StartRecordingPlayout() is already recording");
2244 return 0;
2245 }
2246
2247 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002248 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002249 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2250
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002251 if ((codecInst != NULL) &&
2252 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002253 {
2254 _engineStatisticsPtr->SetLastError(
2255 VE_BAD_ARGUMENT, kTraceError,
2256 "StartRecordingPlayout() invalid compression");
2257 return(-1);
2258 }
2259 if(codecInst == NULL)
2260 {
2261 format = kFileFormatPcm16kHzFile;
2262 codecInst=&dummyCodec;
2263 }
2264 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2265 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2266 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2267 {
2268 format = kFileFormatWavFile;
2269 }
2270 else
2271 {
2272 format = kFileFormatCompressedFile;
2273 }
2274
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002275 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002276
2277 // Destroy the old instance
2278 if (_outputFileRecorderPtr)
2279 {
2280 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2281 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2282 _outputFileRecorderPtr = NULL;
2283 }
2284
2285 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2286 _outputFileRecorderId, (const FileFormats)format);
2287 if (_outputFileRecorderPtr == NULL)
2288 {
2289 _engineStatisticsPtr->SetLastError(
2290 VE_INVALID_ARGUMENT, kTraceError,
2291 "StartRecordingPlayout() fileRecorder format isnot correct");
2292 return -1;
2293 }
2294
2295 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2296 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2297 {
2298 _engineStatisticsPtr->SetLastError(
2299 VE_BAD_FILE, kTraceError,
2300 "StartRecordingAudioFile() failed to start file recording");
2301 _outputFileRecorderPtr->StopRecording();
2302 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2303 _outputFileRecorderPtr = NULL;
2304 return -1;
2305 }
2306 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2307 _outputFileRecording = true;
2308
2309 return 0;
2310}
2311
2312int Channel::StartRecordingPlayout(OutStream* stream,
2313 const CodecInst* codecInst)
2314{
2315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2316 "Channel::StartRecordingPlayout()");
2317
2318 if (_outputFileRecording)
2319 {
2320 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2321 "StartRecordingPlayout() is already recording");
2322 return 0;
2323 }
2324
2325 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002326 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002327 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2328
2329 if (codecInst != NULL && codecInst->channels != 1)
2330 {
2331 _engineStatisticsPtr->SetLastError(
2332 VE_BAD_ARGUMENT, kTraceError,
2333 "StartRecordingPlayout() invalid compression");
2334 return(-1);
2335 }
2336 if(codecInst == NULL)
2337 {
2338 format = kFileFormatPcm16kHzFile;
2339 codecInst=&dummyCodec;
2340 }
2341 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2342 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2343 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2344 {
2345 format = kFileFormatWavFile;
2346 }
2347 else
2348 {
2349 format = kFileFormatCompressedFile;
2350 }
2351
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002352 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002353
2354 // Destroy the old instance
2355 if (_outputFileRecorderPtr)
2356 {
2357 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2358 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2359 _outputFileRecorderPtr = NULL;
2360 }
2361
2362 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2363 _outputFileRecorderId, (const FileFormats)format);
2364 if (_outputFileRecorderPtr == NULL)
2365 {
2366 _engineStatisticsPtr->SetLastError(
2367 VE_INVALID_ARGUMENT, kTraceError,
2368 "StartRecordingPlayout() fileRecorder format isnot correct");
2369 return -1;
2370 }
2371
2372 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2373 notificationTime) != 0)
2374 {
2375 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2376 "StartRecordingPlayout() failed to "
2377 "start file recording");
2378 _outputFileRecorderPtr->StopRecording();
2379 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2380 _outputFileRecorderPtr = NULL;
2381 return -1;
2382 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002383
niklase@google.com470e71d2011-07-07 08:21:25 +00002384 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2385 _outputFileRecording = true;
2386
2387 return 0;
2388}
2389
2390int Channel::StopRecordingPlayout()
2391{
2392 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2393 "Channel::StopRecordingPlayout()");
2394
2395 if (!_outputFileRecording)
2396 {
2397 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2398 "StopRecordingPlayout() isnot recording");
2399 return -1;
2400 }
2401
2402
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002403 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002404
2405 if (_outputFileRecorderPtr->StopRecording() != 0)
2406 {
2407 _engineStatisticsPtr->SetLastError(
2408 VE_STOP_RECORDING_FAILED, kTraceError,
2409 "StopRecording() could not stop recording");
2410 return(-1);
2411 }
2412 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2413 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2414 _outputFileRecorderPtr = NULL;
2415 _outputFileRecording = false;
2416
2417 return 0;
2418}
2419
2420void
2421Channel::SetMixWithMicStatus(bool mix)
2422{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002423 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002424 _mixFileWithMicrophone=mix;
2425}
2426
2427int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002428Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002429{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002430 int8_t currentLevel = _outputAudioLevel.Level();
2431 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002432 return 0;
2433}
2434
2435int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002436Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002437{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002438 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2439 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002440 return 0;
2441}
2442
2443int
2444Channel::SetMute(bool enable)
2445{
wu@webrtc.org63420662013-10-17 18:28:55 +00002446 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2448 "Channel::SetMute(enable=%d)", enable);
2449 _mute = enable;
2450 return 0;
2451}
2452
2453bool
2454Channel::Mute() const
2455{
wu@webrtc.org63420662013-10-17 18:28:55 +00002456 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002457 return _mute;
2458}
2459
2460int
2461Channel::SetOutputVolumePan(float left, float right)
2462{
wu@webrtc.org63420662013-10-17 18:28:55 +00002463 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002464 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2465 "Channel::SetOutputVolumePan()");
2466 _panLeft = left;
2467 _panRight = right;
2468 return 0;
2469}
2470
2471int
2472Channel::GetOutputVolumePan(float& left, float& right) const
2473{
wu@webrtc.org63420662013-10-17 18:28:55 +00002474 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002475 left = _panLeft;
2476 right = _panRight;
niklase@google.com470e71d2011-07-07 08:21:25 +00002477 return 0;
2478}
2479
2480int
2481Channel::SetChannelOutputVolumeScaling(float scaling)
2482{
wu@webrtc.org63420662013-10-17 18:28:55 +00002483 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002484 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2485 "Channel::SetChannelOutputVolumeScaling()");
2486 _outputGain = scaling;
2487 return 0;
2488}
2489
2490int
2491Channel::GetChannelOutputVolumeScaling(float& scaling) const
2492{
wu@webrtc.org63420662013-10-17 18:28:55 +00002493 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002494 scaling = _outputGain;
niklase@google.com470e71d2011-07-07 08:21:25 +00002495 return 0;
2496}
2497
niklase@google.com470e71d2011-07-07 08:21:25 +00002498int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002499 int lengthMs, int attenuationDb,
2500 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002501{
2502 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2503 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2504 playDtmfEvent);
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002505 if (!Sending()) {
2506 return -1;
2507 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002508
2509 _playOutbandDtmfEvent = playDtmfEvent;
2510
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002511 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002512 attenuationDb) != 0)
2513 {
2514 _engineStatisticsPtr->SetLastError(
2515 VE_SEND_DTMF_FAILED,
2516 kTraceWarning,
2517 "SendTelephoneEventOutband() failed to send event");
2518 return -1;
2519 }
2520 return 0;
2521}
2522
2523int Channel::SendTelephoneEventInband(unsigned char eventCode,
2524 int lengthMs,
2525 int attenuationDb,
2526 bool playDtmfEvent)
2527{
2528 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2529 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2530 playDtmfEvent);
2531
2532 _playInbandDtmfEvent = playDtmfEvent;
2533 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2534
2535 return 0;
2536}
2537
2538int
niklase@google.com470e71d2011-07-07 08:21:25 +00002539Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2540{
2541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2542 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002543 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002544 {
2545 _engineStatisticsPtr->SetLastError(
2546 VE_INVALID_ARGUMENT, kTraceError,
2547 "SetSendTelephoneEventPayloadType() invalid type");
2548 return -1;
2549 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002550 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002551 codec.plfreq = 8000;
2552 codec.pltype = type;
2553 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002554 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002555 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002556 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2557 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2558 _engineStatisticsPtr->SetLastError(
2559 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2560 "SetSendTelephoneEventPayloadType() failed to register send"
2561 "payload type");
2562 return -1;
2563 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002564 }
2565 _sendTelephoneEventPayloadType = type;
2566 return 0;
2567}
2568
2569int
2570Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2571{
niklase@google.com470e71d2011-07-07 08:21:25 +00002572 type = _sendTelephoneEventPayloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002573 return 0;
2574}
2575
niklase@google.com470e71d2011-07-07 08:21:25 +00002576int
2577Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2578{
2579 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2580 "Channel::UpdateRxVadDetection()");
2581
2582 int vadDecision = 1;
2583
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002584 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002585
2586 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2587 {
2588 OnRxVadDetected(vadDecision);
2589 _oldVadDecision = vadDecision;
2590 }
2591
2592 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2593 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2594 vadDecision);
2595 return 0;
2596}
2597
2598int
2599Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2600{
2601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2602 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002603 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002604
2605 if (_rxVadObserverPtr)
2606 {
2607 _engineStatisticsPtr->SetLastError(
2608 VE_INVALID_OPERATION, kTraceError,
2609 "RegisterRxVadObserver() observer already enabled");
2610 return -1;
2611 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002612 _rxVadObserverPtr = &observer;
2613 _RxVadDetection = true;
2614 return 0;
2615}
2616
2617int
2618Channel::DeRegisterRxVadObserver()
2619{
2620 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2621 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002622 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002623
2624 if (!_rxVadObserverPtr)
2625 {
2626 _engineStatisticsPtr->SetLastError(
2627 VE_INVALID_OPERATION, kTraceWarning,
2628 "DeRegisterRxVadObserver() observer already disabled");
2629 return 0;
2630 }
2631 _rxVadObserverPtr = NULL;
2632 _RxVadDetection = false;
2633 return 0;
2634}
2635
2636int
2637Channel::VoiceActivityIndicator(int &activity)
2638{
2639 activity = _sendFrameType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002640 return 0;
2641}
2642
2643#ifdef WEBRTC_VOICE_ENGINE_AGC
2644
2645int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002646Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002647{
2648 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2649 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2650 (int)enable, (int)mode);
2651
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002652 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002653 switch (mode)
2654 {
2655 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002656 break;
2657 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002658 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002659 break;
2660 case kAgcFixedDigital:
2661 agcMode = GainControl::kFixedDigital;
2662 break;
2663 case kAgcAdaptiveDigital:
2664 agcMode =GainControl::kAdaptiveDigital;
2665 break;
2666 default:
2667 _engineStatisticsPtr->SetLastError(
2668 VE_INVALID_ARGUMENT, kTraceError,
2669 "SetRxAgcStatus() invalid Agc mode");
2670 return -1;
2671 }
2672
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002673 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002674 {
2675 _engineStatisticsPtr->SetLastError(
2676 VE_APM_ERROR, kTraceError,
2677 "SetRxAgcStatus() failed to set Agc mode");
2678 return -1;
2679 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002680 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002681 {
2682 _engineStatisticsPtr->SetLastError(
2683 VE_APM_ERROR, kTraceError,
2684 "SetRxAgcStatus() failed to set Agc state");
2685 return -1;
2686 }
2687
2688 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002689 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002690
2691 return 0;
2692}
2693
2694int
2695Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2696{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002697 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002698 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002699 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002700
2701 enabled = enable;
2702
2703 switch (agcMode)
2704 {
2705 case GainControl::kFixedDigital:
2706 mode = kAgcFixedDigital;
2707 break;
2708 case GainControl::kAdaptiveDigital:
2709 mode = kAgcAdaptiveDigital;
2710 break;
2711 default:
2712 _engineStatisticsPtr->SetLastError(
2713 VE_APM_ERROR, kTraceError,
2714 "GetRxAgcStatus() invalid Agc mode");
2715 return -1;
2716 }
2717
2718 return 0;
2719}
2720
2721int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002722Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002723{
2724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2725 "Channel::SetRxAgcConfig()");
2726
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002727 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 config.targetLeveldBOv) != 0)
2729 {
2730 _engineStatisticsPtr->SetLastError(
2731 VE_APM_ERROR, kTraceError,
2732 "SetRxAgcConfig() failed to set target peak |level|"
2733 "(or envelope) of the Agc");
2734 return -1;
2735 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002736 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002737 config.digitalCompressionGaindB) != 0)
2738 {
2739 _engineStatisticsPtr->SetLastError(
2740 VE_APM_ERROR, kTraceError,
2741 "SetRxAgcConfig() failed to set the range in |gain| the"
2742 " digital compression stage may apply");
2743 return -1;
2744 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002745 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002746 config.limiterEnable) != 0)
2747 {
2748 _engineStatisticsPtr->SetLastError(
2749 VE_APM_ERROR, kTraceError,
2750 "SetRxAgcConfig() failed to set hard limiter to the signal");
2751 return -1;
2752 }
2753
2754 return 0;
2755}
2756
2757int
2758Channel::GetRxAgcConfig(AgcConfig& config)
2759{
niklase@google.com470e71d2011-07-07 08:21:25 +00002760 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002761 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002763 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002765 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002766
niklase@google.com470e71d2011-07-07 08:21:25 +00002767 return 0;
2768}
2769
2770#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2771
2772#ifdef WEBRTC_VOICE_ENGINE_NR
2773
2774int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002775Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002776{
2777 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2778 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2779 (int)enable, (int)mode);
2780
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002781 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002782 switch (mode)
2783 {
2784
2785 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002786 break;
2787 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002788 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002789 break;
2790 case kNsConference:
2791 nsLevel = NoiseSuppression::kHigh;
2792 break;
2793 case kNsLowSuppression:
2794 nsLevel = NoiseSuppression::kLow;
2795 break;
2796 case kNsModerateSuppression:
2797 nsLevel = NoiseSuppression::kModerate;
2798 break;
2799 case kNsHighSuppression:
2800 nsLevel = NoiseSuppression::kHigh;
2801 break;
2802 case kNsVeryHighSuppression:
2803 nsLevel = NoiseSuppression::kVeryHigh;
2804 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002805 }
2806
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002807 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002808 != 0)
2809 {
2810 _engineStatisticsPtr->SetLastError(
2811 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002812 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002813 return -1;
2814 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002815 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002816 {
2817 _engineStatisticsPtr->SetLastError(
2818 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002819 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002820 return -1;
2821 }
2822
2823 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002824 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002825
2826 return 0;
2827}
2828
2829int
2830Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2831{
niklase@google.com470e71d2011-07-07 08:21:25 +00002832 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002833 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002834 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002835 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002836
2837 enabled = enable;
2838
2839 switch (ncLevel)
2840 {
2841 case NoiseSuppression::kLow:
2842 mode = kNsLowSuppression;
2843 break;
2844 case NoiseSuppression::kModerate:
2845 mode = kNsModerateSuppression;
2846 break;
2847 case NoiseSuppression::kHigh:
2848 mode = kNsHighSuppression;
2849 break;
2850 case NoiseSuppression::kVeryHigh:
2851 mode = kNsVeryHighSuppression;
2852 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002853 }
2854
niklase@google.com470e71d2011-07-07 08:21:25 +00002855 return 0;
2856}
2857
2858#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2859
2860int
niklase@google.com470e71d2011-07-07 08:21:25 +00002861Channel::SetLocalSSRC(unsigned int ssrc)
2862{
2863 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2864 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002865 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002866 {
2867 _engineStatisticsPtr->SetLastError(
2868 VE_ALREADY_SENDING, kTraceError,
2869 "SetLocalSSRC() already sending");
2870 return -1;
2871 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002872 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002873 return 0;
2874}
2875
2876int
2877Channel::GetLocalSSRC(unsigned int& ssrc)
2878{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002879 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002880 return 0;
2881}
2882
2883int
2884Channel::GetRemoteSSRC(unsigned int& ssrc)
2885{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002886 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002887 return 0;
2888}
2889
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002890int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002891 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002892 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002893}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002894
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002895int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2896 unsigned char id) {
2897 rtp_header_parser_->DeregisterRtpHeaderExtension(
2898 kRtpExtensionAudioLevel);
2899 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2900 kRtpExtensionAudioLevel, id)) {
2901 return -1;
2902 }
2903 return 0;
2904}
2905
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002906int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2907 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2908}
2909
2910int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2911 rtp_header_parser_->DeregisterRtpHeaderExtension(
2912 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002913 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2914 kRtpExtensionAbsoluteSendTime, id)) {
2915 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002916 }
2917 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002918}
2919
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002920void Channel::EnableSendTransportSequenceNumber(int id) {
2921 int ret =
2922 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2923 RTC_DCHECK_EQ(0, ret);
2924}
2925
2926void Channel::SetCongestionControlObjects(
2927 RtpPacketSender* rtp_packet_sender,
2928 TransportFeedbackObserver* transport_feedback_observer,
2929 PacketRouter* packet_router) {
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002930 RTC_DCHECK(packet_router != nullptr || packet_router_ != nullptr);
Stefan Holmer3842c5c2016-01-12 13:55:00 +01002931 if (transport_feedback_observer) {
2932 RTC_DCHECK(feedback_observer_proxy_.get());
2933 feedback_observer_proxy_->SetTransportFeedbackObserver(
2934 transport_feedback_observer);
2935 }
2936 if (rtp_packet_sender) {
2937 RTC_DCHECK(rtp_packet_sender_proxy_.get());
2938 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2939 }
2940 if (seq_num_allocator_proxy_.get()) {
2941 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2942 }
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002943 _rtpRtcpModule->SetStorePacketsStatus(rtp_packet_sender != nullptr, 600);
2944 if (packet_router != nullptr) {
2945 packet_router->AddRtpModule(_rtpRtcpModule.get());
2946 } else {
2947 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
2948 }
2949 packet_router_ = packet_router;
2950}
2951
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002952void Channel::SetRTCPStatus(bool enable) {
2953 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2954 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002955 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002956}
2957
2958int
2959Channel::GetRTCPStatus(bool& enabled)
2960{
pbosda903ea2015-10-02 02:36:56 -07002961 RtcpMode method = _rtpRtcpModule->RTCP();
2962 enabled = (method != RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002963 return 0;
2964}
2965
2966int
2967Channel::SetRTCP_CNAME(const char cName[256])
2968{
2969 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2970 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002971 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002972 {
2973 _engineStatisticsPtr->SetLastError(
2974 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2975 "SetRTCP_CNAME() failed to set RTCP CNAME");
2976 return -1;
2977 }
2978 return 0;
2979}
2980
2981int
niklase@google.com470e71d2011-07-07 08:21:25 +00002982Channel::GetRemoteRTCP_CNAME(char cName[256])
2983{
2984 if (cName == NULL)
2985 {
2986 _engineStatisticsPtr->SetLastError(
2987 VE_INVALID_ARGUMENT, kTraceError,
2988 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2989 return -1;
2990 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002991 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002992 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002993 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002994 {
2995 _engineStatisticsPtr->SetLastError(
2996 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2997 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2998 return -1;
2999 }
3000 strcpy(cName, cname);
niklase@google.com470e71d2011-07-07 08:21:25 +00003001 return 0;
3002}
3003
3004int
3005Channel::GetRemoteRTCPData(
3006 unsigned int& NTPHigh,
3007 unsigned int& NTPLow,
3008 unsigned int& timestamp,
3009 unsigned int& playoutTimestamp,
3010 unsigned int* jitter,
3011 unsigned short* fractionLost)
3012{
3013 // --- Information from sender info in received Sender Reports
3014
3015 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003016 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003017 {
3018 _engineStatisticsPtr->SetLastError(
3019 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003020 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003021 "side");
3022 return -1;
3023 }
3024
3025 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3026 // and octet count)
3027 NTPHigh = senderInfo.NTPseconds;
3028 NTPLow = senderInfo.NTPfraction;
3029 timestamp = senderInfo.RTPtimeStamp;
3030
niklase@google.com470e71d2011-07-07 08:21:25 +00003031 // --- Locally derived information
3032
3033 // This value is updated on each incoming RTCP packet (0 when no packet
3034 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003035 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003036
niklase@google.com470e71d2011-07-07 08:21:25 +00003037 if (NULL != jitter || NULL != fractionLost)
3038 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003039 // Get all RTCP receiver report blocks that have been received on this
3040 // channel. If we receive RTP packets from a remote source we know the
3041 // remote SSRC and use the report block from him.
3042 // Otherwise use the first report block.
3043 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003044 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003045 remote_stats.empty()) {
3046 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3047 VoEId(_instanceId, _channelId),
3048 "GetRemoteRTCPData() failed to measure statistics due"
3049 " to lack of received RTP and/or RTCP packets");
3050 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003051 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003052
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003053 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003054 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3055 for (; it != remote_stats.end(); ++it) {
3056 if (it->remoteSSRC == remoteSSRC)
3057 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003058 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003059
3060 if (it == remote_stats.end()) {
3061 // If we have not received any RTCP packets from this SSRC it probably
3062 // means that we have not received any RTP packets.
3063 // Use the first received report block instead.
3064 it = remote_stats.begin();
3065 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003066 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003067
xians@webrtc.org79af7342012-01-31 12:22:14 +00003068 if (jitter) {
3069 *jitter = it->jitter;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003070 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003071
xians@webrtc.org79af7342012-01-31 12:22:14 +00003072 if (fractionLost) {
3073 *fractionLost = it->fractionLost;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003074 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003075 }
3076 return 0;
3077}
3078
3079int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003080Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003081 unsigned int name,
3082 const char* data,
3083 unsigned short dataLengthInBytes)
3084{
3085 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3086 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003087 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003088 {
3089 _engineStatisticsPtr->SetLastError(
3090 VE_NOT_SENDING, kTraceError,
3091 "SendApplicationDefinedRTCPPacket() not sending");
3092 return -1;
3093 }
3094 if (NULL == data)
3095 {
3096 _engineStatisticsPtr->SetLastError(
3097 VE_INVALID_ARGUMENT, kTraceError,
3098 "SendApplicationDefinedRTCPPacket() invalid data value");
3099 return -1;
3100 }
3101 if (dataLengthInBytes % 4 != 0)
3102 {
3103 _engineStatisticsPtr->SetLastError(
3104 VE_INVALID_ARGUMENT, kTraceError,
3105 "SendApplicationDefinedRTCPPacket() invalid length value");
3106 return -1;
3107 }
pbosda903ea2015-10-02 02:36:56 -07003108 RtcpMode status = _rtpRtcpModule->RTCP();
3109 if (status == RtcpMode::kOff) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003110 _engineStatisticsPtr->SetLastError(
3111 VE_RTCP_ERROR, kTraceError,
3112 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3113 return -1;
3114 }
3115
3116 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003117 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003118 subType,
3119 name,
3120 (const unsigned char*) data,
3121 dataLengthInBytes) != 0)
3122 {
3123 _engineStatisticsPtr->SetLastError(
3124 VE_SEND_ERROR, kTraceError,
3125 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3126 return -1;
3127 }
3128 return 0;
3129}
3130
3131int
3132Channel::GetRTPStatistics(
3133 unsigned int& averageJitterMs,
3134 unsigned int& maxJitterMs,
3135 unsigned int& discardedPackets)
3136{
niklase@google.com470e71d2011-07-07 08:21:25 +00003137 // The jitter statistics is updated for each received RTP packet and is
3138 // based on received packets.
pbosda903ea2015-10-02 02:36:56 -07003139 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003140 // If RTCP is off, there is no timed thread in the RTCP module regularly
3141 // generating new stats, trigger the update manually here instead.
3142 StreamStatistician* statistician =
3143 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3144 if (statistician) {
3145 // Don't use returned statistics, use data from proxy instead so that
3146 // max jitter can be fetched atomically.
3147 RtcpStatistics s;
3148 statistician->GetStatistics(&s, true);
3149 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003150 }
3151
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003152 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003153 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003154 if (playoutFrequency > 0) {
3155 // Scale RTP statistics given the current playout frequency
3156 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3157 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003158 }
3159
3160 discardedPackets = _numberOfDiscardedPackets;
3161
niklase@google.com470e71d2011-07-07 08:21:25 +00003162 return 0;
3163}
3164
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003165int Channel::GetRemoteRTCPReportBlocks(
3166 std::vector<ReportBlock>* report_blocks) {
3167 if (report_blocks == NULL) {
3168 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3169 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3170 return -1;
3171 }
3172
3173 // Get the report blocks from the latest received RTCP Sender or Receiver
3174 // Report. Each element in the vector contains the sender's SSRC and a
3175 // report block according to RFC 3550.
3176 std::vector<RTCPReportBlock> rtcp_report_blocks;
3177 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003178 return -1;
3179 }
3180
3181 if (rtcp_report_blocks.empty())
3182 return 0;
3183
3184 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3185 for (; it != rtcp_report_blocks.end(); ++it) {
3186 ReportBlock report_block;
3187 report_block.sender_SSRC = it->remoteSSRC;
3188 report_block.source_SSRC = it->sourceSSRC;
3189 report_block.fraction_lost = it->fractionLost;
3190 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3191 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3192 report_block.interarrival_jitter = it->jitter;
3193 report_block.last_SR_timestamp = it->lastSR;
3194 report_block.delay_since_last_SR = it->delaySinceLastSR;
3195 report_blocks->push_back(report_block);
3196 }
3197 return 0;
3198}
3199
niklase@google.com470e71d2011-07-07 08:21:25 +00003200int
3201Channel::GetRTPStatistics(CallStatistics& stats)
3202{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003203 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003204
3205 // The jitter statistics is updated for each received RTP packet and is
3206 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003207 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003208 StreamStatistician* statistician =
3209 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
pbosda903ea2015-10-02 02:36:56 -07003210 if (!statistician ||
3211 !statistician->GetStatistics(
3212 &statistics, _rtpRtcpModule->RTCP() == RtcpMode::kOff)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003213 _engineStatisticsPtr->SetLastError(
3214 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3215 "GetRTPStatistics() failed to read RTP statistics from the "
3216 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003217 }
3218
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003219 stats.fractionLost = statistics.fraction_lost;
3220 stats.cumulativeLost = statistics.cumulative_lost;
3221 stats.extendedMax = statistics.extended_max_sequence_number;
3222 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003223
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003224 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003225 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003226
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003227 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003228
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003229 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003230 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003231 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003232 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003233
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003234 if (statistician) {
3235 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3236 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003237
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003238 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003239 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003240 {
3241 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3242 VoEId(_instanceId, _channelId),
3243 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003244 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003245 }
3246
3247 stats.bytesSent = bytesSent;
3248 stats.packetsSent = packetsSent;
3249 stats.bytesReceived = bytesReceived;
3250 stats.packetsReceived = packetsReceived;
3251
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003252 // --- Timestamps
3253 {
3254 CriticalSectionScoped lock(ts_stats_lock_.get());
3255 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3256 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003257 return 0;
3258}
3259
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003260int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003261 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003262 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003263
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003264 if (enable) {
3265 if (redPayloadtype < 0 || redPayloadtype > 127) {
3266 _engineStatisticsPtr->SetLastError(
3267 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003268 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003269 return -1;
3270 }
3271
3272 if (SetRedPayloadType(redPayloadtype) < 0) {
3273 _engineStatisticsPtr->SetLastError(
3274 VE_CODEC_ERROR, kTraceError,
3275 "SetSecondarySendCodec() Failed to register RED ACM");
3276 return -1;
3277 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003278 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003279
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003280 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003281 _engineStatisticsPtr->SetLastError(
3282 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003283 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003284 return -1;
3285 }
3286 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003287}
3288
3289int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003290Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003291{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003292 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003293 if (enabled)
3294 {
danilchap5c1def82015-12-10 09:51:54 -08003295 int8_t payloadType = 0;
3296 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003297 _engineStatisticsPtr->SetLastError(
3298 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003299 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003300 "module");
3301 return -1;
3302 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003303 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003304 return 0;
3305 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003306 return 0;
3307}
3308
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003309int Channel::SetCodecFECStatus(bool enable) {
3310 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3311 "Channel::SetCodecFECStatus()");
3312
3313 if (audio_coding_->SetCodecFEC(enable) != 0) {
3314 _engineStatisticsPtr->SetLastError(
3315 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3316 "SetCodecFECStatus() failed to set FEC state");
3317 return -1;
3318 }
3319 return 0;
3320}
3321
3322bool Channel::GetCodecFECStatus() {
3323 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003324 return enabled;
3325}
3326
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003327void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3328 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01003329 // If pacing is enabled we always store packets.
3330 if (!pacing_enabled_)
3331 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003332 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3333 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003334 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003335 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003336 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003337 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003338}
3339
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003340// Called when we are missing one or more packets.
3341int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003342 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3343}
3344
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003345uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003346Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003347{
3348 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003349 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003350 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003351 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003352 return 0;
3353}
3354
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003355void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003356 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003357 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003358 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003359 CodecInst codec;
3360 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003361
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07003362 // Never upsample or upmix the capture signal here. This should be done at the
3363 // end of the send chain.
3364 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3365 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3366 RemixAndResample(audio_data, number_of_frames, number_of_channels,
3367 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003368}
3369
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003370uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003371Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003372{
3373 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3374 "Channel::PrepareEncodeAndSend()");
3375
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003376 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003377 {
3378 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3379 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003380 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003381 }
3382
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003383 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003384 {
3385 MixOrReplaceAudioWithFile(mixingFrequency);
3386 }
3387
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003388 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3389 if (is_muted) {
3390 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003391 }
3392
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003393 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003394 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003395 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003396 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003397 if (_inputExternalMediaCallbackPtr)
3398 {
3399 _inputExternalMediaCallbackPtr->Process(
3400 _channelId,
3401 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003402 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003403 _audioFrame.samples_per_channel_,
3404 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003405 isStereo);
3406 }
3407 }
3408
3409 InsertInbandDtmfTone();
3410
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003411 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003412 size_t length =
3413 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003414 if (is_muted) {
3415 rms_level_.ProcessMuted(length);
3416 } else {
3417 rms_level_.Process(_audioFrame.data_, length);
3418 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003419 }
3420
niklase@google.com470e71d2011-07-07 08:21:25 +00003421 return 0;
3422}
3423
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003424uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003425Channel::EncodeAndSend()
3426{
3427 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3428 "Channel::EncodeAndSend()");
3429
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003430 assert(_audioFrame.num_channels_ <= 2);
3431 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003432 {
3433 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3434 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003435 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003436 }
3437
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003438 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003439
3440 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3441
3442 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003443 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003444 // This call will trigger AudioPacketizationCallback::SendData if encoding
3445 // is done and payload is ready for packetization and transmission.
3446 // Otherwise, it will return without invoking the callback.
3447 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003448 {
3449 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3450 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003451 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003452 }
3453
Peter Kastingb7e50542015-06-11 12:55:50 -07003454 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003455 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003456}
3457
Minyue2013aec2015-05-13 14:14:42 +02003458void Channel::DisassociateSendChannel(int channel_id) {
3459 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3460 Channel* channel = associate_send_channel_.channel();
3461 if (channel && channel->ChannelId() == channel_id) {
3462 // If this channel is associated with a send channel of the specified
3463 // Channel ID, disassociate with it.
3464 ChannelOwner ref(NULL);
3465 associate_send_channel_ = ref;
3466 }
3467}
3468
niklase@google.com470e71d2011-07-07 08:21:25 +00003469int Channel::RegisterExternalMediaProcessing(
3470 ProcessingTypes type,
3471 VoEMediaProcess& processObject)
3472{
3473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3474 "Channel::RegisterExternalMediaProcessing()");
3475
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003476 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003477
3478 if (kPlaybackPerChannel == type)
3479 {
3480 if (_outputExternalMediaCallbackPtr)
3481 {
3482 _engineStatisticsPtr->SetLastError(
3483 VE_INVALID_OPERATION, kTraceError,
3484 "Channel::RegisterExternalMediaProcessing() "
3485 "output external media already enabled");
3486 return -1;
3487 }
3488 _outputExternalMediaCallbackPtr = &processObject;
3489 _outputExternalMedia = true;
3490 }
3491 else if (kRecordingPerChannel == type)
3492 {
3493 if (_inputExternalMediaCallbackPtr)
3494 {
3495 _engineStatisticsPtr->SetLastError(
3496 VE_INVALID_OPERATION, kTraceError,
3497 "Channel::RegisterExternalMediaProcessing() "
3498 "output external media already enabled");
3499 return -1;
3500 }
3501 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003502 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003503 }
3504 return 0;
3505}
3506
3507int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3508{
3509 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3510 "Channel::DeRegisterExternalMediaProcessing()");
3511
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003512 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003513
3514 if (kPlaybackPerChannel == type)
3515 {
3516 if (!_outputExternalMediaCallbackPtr)
3517 {
3518 _engineStatisticsPtr->SetLastError(
3519 VE_INVALID_OPERATION, kTraceWarning,
3520 "Channel::DeRegisterExternalMediaProcessing() "
3521 "output external media already disabled");
3522 return 0;
3523 }
3524 _outputExternalMedia = false;
3525 _outputExternalMediaCallbackPtr = NULL;
3526 }
3527 else if (kRecordingPerChannel == type)
3528 {
3529 if (!_inputExternalMediaCallbackPtr)
3530 {
3531 _engineStatisticsPtr->SetLastError(
3532 VE_INVALID_OPERATION, kTraceWarning,
3533 "Channel::DeRegisterExternalMediaProcessing() "
3534 "input external media already disabled");
3535 return 0;
3536 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003537 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003538 _inputExternalMediaCallbackPtr = NULL;
3539 }
3540
3541 return 0;
3542}
3543
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003544int Channel::SetExternalMixing(bool enabled) {
3545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3546 "Channel::SetExternalMixing(enabled=%d)", enabled);
3547
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003548 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003549 {
3550 _engineStatisticsPtr->SetLastError(
3551 VE_INVALID_OPERATION, kTraceError,
3552 "Channel::SetExternalMixing() "
3553 "external mixing cannot be changed while playing.");
3554 return -1;
3555 }
3556
3557 _externalMixing = enabled;
3558
3559 return 0;
3560}
3561
niklase@google.com470e71d2011-07-07 08:21:25 +00003562int
niklase@google.com470e71d2011-07-07 08:21:25 +00003563Channel::GetNetworkStatistics(NetworkStatistics& stats)
3564{
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003565 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003566}
3567
wu@webrtc.org24301a62013-12-13 19:17:43 +00003568void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3569 audio_coding_->GetDecodingCallStatistics(stats);
3570}
3571
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003572bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3573 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003574 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003575 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003576 return false;
3577 }
3578 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3579 _recPacketDelayMs;
3580 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003581 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003582}
3583
solenberg358057b2015-11-27 10:46:42 -08003584uint32_t Channel::GetDelayEstimate() const {
3585 int jitter_buffer_delay_ms = 0;
3586 int playout_buffer_delay_ms = 0;
3587 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3588 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3589}
3590
deadbeef74375882015-08-13 12:09:10 -07003591int Channel::LeastRequiredDelayMs() const {
3592 return audio_coding_->LeastRequiredDelayMs();
3593}
3594
niklase@google.com470e71d2011-07-07 08:21:25 +00003595int
3596Channel::SetMinimumPlayoutDelay(int delayMs)
3597{
3598 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3599 "Channel::SetMinimumPlayoutDelay()");
3600 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3601 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3602 {
3603 _engineStatisticsPtr->SetLastError(
3604 VE_INVALID_ARGUMENT, kTraceError,
3605 "SetMinimumPlayoutDelay() invalid min delay");
3606 return -1;
3607 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003608 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003609 {
3610 _engineStatisticsPtr->SetLastError(
3611 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3612 "SetMinimumPlayoutDelay() failed to set min playout delay");
3613 return -1;
3614 }
3615 return 0;
3616}
3617
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003618int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003619 uint32_t playout_timestamp_rtp = 0;
3620 {
3621 CriticalSectionScoped cs(video_sync_lock_.get());
3622 playout_timestamp_rtp = playout_timestamp_rtp_;
3623 }
3624 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003625 _engineStatisticsPtr->SetLastError(
3626 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3627 "GetPlayoutTimestamp() failed to retrieve timestamp");
3628 return -1;
3629 }
deadbeef74375882015-08-13 12:09:10 -07003630 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003631 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003632}
3633
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003634int Channel::SetInitTimestamp(unsigned int timestamp) {
3635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003636 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003637 if (channel_state_.Get().sending) {
3638 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3639 "SetInitTimestamp() already sending");
3640 return -1;
3641 }
3642 _rtpRtcpModule->SetStartTimestamp(timestamp);
3643 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003644}
3645
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003646int Channel::SetInitSequenceNumber(short sequenceNumber) {
3647 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3648 "Channel::SetInitSequenceNumber()");
3649 if (channel_state_.Get().sending) {
3650 _engineStatisticsPtr->SetLastError(
3651 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3652 return -1;
3653 }
3654 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3655 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003656}
3657
3658int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003659Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003660{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003661 *rtpRtcpModule = _rtpRtcpModule.get();
3662 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003663 return 0;
3664}
3665
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003666// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3667// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003668int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003669Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003670{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003671 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003672 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003673
3674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003675 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003676
3677 if (_inputFilePlayerPtr == NULL)
3678 {
3679 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3680 VoEId(_instanceId, _channelId),
3681 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3682 " doesnt exist");
3683 return -1;
3684 }
3685
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003686 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003687 fileSamples,
3688 mixingFrequency) == -1)
3689 {
3690 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3691 VoEId(_instanceId, _channelId),
3692 "Channel::MixOrReplaceAudioWithFile() file mixing "
3693 "failed");
3694 return -1;
3695 }
3696 if (fileSamples == 0)
3697 {
3698 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3699 VoEId(_instanceId, _channelId),
3700 "Channel::MixOrReplaceAudioWithFile() file is ended");
3701 return 0;
3702 }
3703 }
3704
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003705 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003706
3707 if (_mixFileWithMicrophone)
3708 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003709 // Currently file stream is always mono.
3710 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003711 MixWithSat(_audioFrame.data_,
3712 _audioFrame.num_channels_,
3713 fileBuffer.get(),
3714 1,
3715 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003716 }
3717 else
3718 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003719 // Replace ACM audio with file.
3720 // Currently file stream is always mono.
3721 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003723 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003724 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003725 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003726 mixingFrequency,
3727 AudioFrame::kNormalSpeech,
3728 AudioFrame::kVadUnknown,
3729 1);
3730
3731 }
3732 return 0;
3733}
3734
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003735int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003736Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003737 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003738{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003739 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003740
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003741 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003742 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003743
3744 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003745 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003746
3747 if (_outputFilePlayerPtr == NULL)
3748 {
3749 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3750 VoEId(_instanceId, _channelId),
3751 "Channel::MixAudioWithFile() file mixing failed");
3752 return -1;
3753 }
3754
3755 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003756 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 fileSamples,
3758 mixingFrequency) == -1)
3759 {
3760 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3761 VoEId(_instanceId, _channelId),
3762 "Channel::MixAudioWithFile() file mixing failed");
3763 return -1;
3764 }
3765 }
3766
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003767 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003768 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003769 // Currently file stream is always mono.
3770 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003771 MixWithSat(audioFrame.data_,
3772 audioFrame.num_channels_,
3773 fileBuffer.get(),
3774 1,
3775 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 }
3777 else
3778 {
3779 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003780 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3781 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003782 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003783 return -1;
3784 }
3785
3786 return 0;
3787}
3788
3789int
3790Channel::InsertInbandDtmfTone()
3791{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003792 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003793 if (_inbandDtmfQueue.PendingDtmf() &&
3794 !_inbandDtmfGenerator.IsAddingTone() &&
3795 _inbandDtmfGenerator.DelaySinceLastTone() >
3796 kMinTelephoneEventSeparationMs)
3797 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003798 int8_t eventCode(0);
3799 uint16_t lengthMs(0);
3800 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003801
3802 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3803 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3804 if (_playInbandDtmfEvent)
3805 {
3806 // Add tone to output mixer using a reduced length to minimize
3807 // risk of echo.
3808 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3809 attenuationDb);
3810 }
3811 }
3812
3813 if (_inbandDtmfGenerator.IsAddingTone())
3814 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003815 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003816 _inbandDtmfGenerator.GetSampleRate(frequency);
3817
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003818 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003819 {
3820 // Update sample rate of Dtmf tone since the mixing frequency
3821 // has changed.
3822 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003823 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003824 // Reset the tone to be added taking the new sample rate into
3825 // account.
3826 _inbandDtmfGenerator.ResetTone();
3827 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003828
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003829 int16_t toneBuffer[320];
3830 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003831 // Get 10ms tone segment and set time since last tone to zero
3832 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3833 {
3834 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3835 VoEId(_instanceId, _channelId),
3836 "Channel::EncodeAndSend() inserting Dtmf failed");
3837 return -1;
3838 }
3839
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003840 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003841 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003842 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003843 sample++)
3844 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003845 for (int channel = 0;
3846 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003847 channel++)
3848 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003849 const size_t index =
3850 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003851 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003852 }
3853 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003854
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003855 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003856 } else
3857 {
3858 // Add 10ms to "delay-since-last-tone" counter
3859 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3860 }
3861 return 0;
3862}
3863
deadbeef74375882015-08-13 12:09:10 -07003864void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3865 uint32_t playout_timestamp = 0;
3866
3867 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3868 // This can happen if this channel has not been received any RTP packet. In
3869 // this case, NetEq is not capable of computing playout timestamp.
3870 return;
3871 }
3872
3873 uint16_t delay_ms = 0;
3874 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3875 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3876 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3877 " delay from the ADM");
3878 _engineStatisticsPtr->SetLastError(
3879 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3880 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3881 return;
3882 }
3883
3884 jitter_buffer_playout_timestamp_ = playout_timestamp;
3885
3886 // Remove the playout delay.
3887 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3888
3889 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3890 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3891 playout_timestamp);
3892
3893 {
3894 CriticalSectionScoped cs(video_sync_lock_.get());
3895 if (rtcp) {
3896 playout_timestamp_rtcp_ = playout_timestamp;
3897 } else {
3898 playout_timestamp_rtp_ = playout_timestamp;
3899 }
3900 playout_delay_ms_ = delay_ms;
3901 }
3902}
3903
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003904// Called for incoming RTP packets after successful RTP header parsing.
3905void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3906 uint16_t sequence_number) {
3907 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3908 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3909 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003910
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003911 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003912 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003913
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003914 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3915 // every incoming packet.
3916 uint32_t timestamp_diff_ms = (rtp_timestamp -
3917 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003918 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3919 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3920 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3921 // timestamp, the resulting difference is negative, but is set to zero.
3922 // This can happen when a network glitch causes a packet to arrive late,
3923 // and during long comfort noise periods with clock drift.
3924 timestamp_diff_ms = 0;
3925 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003926
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003927 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3928 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003929
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003930 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003931
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003932 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003933
deadbeef74375882015-08-13 12:09:10 -07003934 {
3935 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003936
deadbeef74375882015-08-13 12:09:10 -07003937 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3938 _recPacketDelayMs = packet_delay_ms;
3939 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003940
deadbeef74375882015-08-13 12:09:10 -07003941 if (_average_jitter_buffer_delay_us == 0) {
3942 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3943 return;
3944 }
3945
3946 // Filter average delay value using exponential filter (alpha is
3947 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3948 // risk of rounding error) and compensate for it in GetDelayEstimate()
3949 // later.
3950 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3951 1000 * timestamp_diff_ms + 500) / 8;
3952 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003953}
3954
3955void
3956Channel::RegisterReceiveCodecsToRTPModule()
3957{
3958 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3959 "Channel::RegisterReceiveCodecsToRTPModule()");
3960
niklase@google.com470e71d2011-07-07 08:21:25 +00003961 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003962 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003963
3964 for (int idx = 0; idx < nSupportedCodecs; idx++)
3965 {
3966 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003967 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003968 (rtp_receiver_->RegisterReceivePayload(
3969 codec.plname,
3970 codec.pltype,
3971 codec.plfreq,
3972 codec.channels,
3973 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003974 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003975 WEBRTC_TRACE(kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00003976 kTraceVoice,
3977 VoEId(_instanceId, _channelId),
3978 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3979 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
3980 codec.plname, codec.pltype, codec.plfreq,
3981 codec.channels, codec.rate);
3982 }
3983 else
3984 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003985 WEBRTC_TRACE(kTraceInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +00003986 kTraceVoice,
3987 VoEId(_instanceId, _channelId),
3988 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003989 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003990 "receiver",
3991 codec.plname, codec.pltype, codec.plfreq,
3992 codec.channels, codec.rate);
3993 }
3994 }
3995}
3996
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003997// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003998int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003999 CodecInst codec;
4000 bool found_red = false;
4001
4002 // Get default RED settings from the ACM database
4003 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4004 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004005 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004006 if (!STR_CASE_CMP(codec.plname, "RED")) {
4007 found_red = true;
4008 break;
4009 }
4010 }
4011
4012 if (!found_red) {
4013 _engineStatisticsPtr->SetLastError(
4014 VE_CODEC_ERROR, kTraceError,
4015 "SetRedPayloadType() RED is not supported");
4016 return -1;
4017 }
4018
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004019 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004020 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004021 _engineStatisticsPtr->SetLastError(
4022 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4023 "SetRedPayloadType() RED registration in ACM module failed");
4024 return -1;
4025 }
4026
4027 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4028 _engineStatisticsPtr->SetLastError(
4029 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4030 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4031 return -1;
4032 }
4033 return 0;
4034}
4035
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004036int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4037 unsigned char id) {
4038 int error = 0;
4039 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4040 if (enable) {
4041 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4042 }
4043 return error;
4044}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004045
wu@webrtc.org94454b72014-06-05 20:34:08 +00004046int32_t Channel::GetPlayoutFrequency() {
4047 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4048 CodecInst current_recive_codec;
4049 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4050 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4051 // Even though the actual sampling rate for G.722 audio is
4052 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4053 // 8,000 Hz because that value was erroneously assigned in
4054 // RFC 1890 and must remain unchanged for backward compatibility.
4055 playout_frequency = 8000;
4056 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4057 // We are resampling Opus internally to 32,000 Hz until all our
4058 // DSP routines can operate at 48,000 Hz, but the RTP clock
4059 // rate for the Opus payload format is standardized to 48,000 Hz,
4060 // because that is the maximum supported decoding sampling rate.
4061 playout_frequency = 48000;
4062 }
4063 }
4064 return playout_frequency;
4065}
4066
Minyue2013aec2015-05-13 14:14:42 +02004067int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07004068 RtcpMode method = _rtpRtcpModule->RTCP();
4069 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004070 return 0;
4071 }
4072 std::vector<RTCPReportBlock> report_blocks;
4073 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004074
4075 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004076 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004077 if (allow_associate_channel) {
4078 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4079 Channel* channel = associate_send_channel_.channel();
4080 // Tries to get RTT from an associated channel. This is important for
4081 // receive-only channels.
4082 if (channel) {
4083 // To prevent infinite recursion and deadlock, calling GetRTT of
4084 // associate channel should always use "false" for argument:
4085 // |allow_associate_channel|.
4086 rtt = channel->GetRTT(false);
4087 }
4088 }
4089 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004090 }
4091
4092 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4093 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4094 for (; it != report_blocks.end(); ++it) {
4095 if (it->remoteSSRC == remoteSSRC)
4096 break;
4097 }
4098 if (it == report_blocks.end()) {
4099 // We have not received packets with SSRC matching the report blocks.
4100 // To calculate RTT we try with the SSRC of the first report block.
4101 // This is very important for send-only channels where we don't know
4102 // the SSRC of the other end.
4103 remoteSSRC = report_blocks[0].remoteSSRC;
4104 }
Minyue2013aec2015-05-13 14:14:42 +02004105
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004106 int64_t avg_rtt = 0;
4107 int64_t max_rtt= 0;
4108 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004109 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4110 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004111 return 0;
4112 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004113 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004114}
4115
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004116} // namespace voe
4117} // namespace webrtc