blob: 18f34082765aff7f1f5232ed617f8ace83edaadd [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>
14
Ivo Creusenae856f22015-09-17 16:30:16 +020015#include "webrtc/base/checks.h"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000016#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080017#include "webrtc/base/logging.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010018#include "webrtc/base/thread_checker.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000019#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000020#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020021#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000022#include "webrtc/modules/audio_device/include/audio_device.h"
23#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010024#include "webrtc/modules/include/module_common_types.h"
Stefan Holmerb86d4e42015-12-07 10:26:18 +010025#include "webrtc/modules/pacing/packet_router.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010026#include "webrtc/modules/rtp_rtcp/include/receive_statistics.h"
27#include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
28#include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000029#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
Henrik Kjellanderff761fb2015-11-04 08:31:52 +010030#include "webrtc/modules/utility/include/audio_frame_operations.h"
31#include "webrtc/modules/utility/include/process_thread.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010032#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010033#include "webrtc/system_wrappers/include/trace.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000034#include "webrtc/voice_engine/include/voe_base.h"
35#include "webrtc/voice_engine/include/voe_external_media.h"
36#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
37#include "webrtc/voice_engine/output_mixer.h"
38#include "webrtc/voice_engine/statistics.h"
39#include "webrtc/voice_engine/transmit_mixer.h"
40#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000041
42#if defined(_WIN32)
43#include <Qos.h>
44#endif
45
andrew@webrtc.org50419b02012-11-14 19:07:54 +000046namespace webrtc {
47namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000048
Stefan Holmerb86d4e42015-12-07 10:26:18 +010049class TransportFeedbackProxy : public TransportFeedbackObserver {
50 public:
51 TransportFeedbackProxy() : feedback_observer_(nullptr) {
52 pacer_thread_.DetachFromThread();
53 network_thread_.DetachFromThread();
54 }
55
56 void SetTransportFeedbackObserver(
57 TransportFeedbackObserver* feedback_observer) {
58 RTC_DCHECK(thread_checker_.CalledOnValidThread());
59 rtc::CritScope lock(&crit_);
60 feedback_observer_ = feedback_observer;
61 }
62
63 // Implements TransportFeedbackObserver.
64 void AddPacket(uint16_t sequence_number,
65 size_t length,
66 bool was_paced) override {
67 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
68 rtc::CritScope lock(&crit_);
69 if (feedback_observer_)
70 feedback_observer_->AddPacket(sequence_number, length, was_paced);
71 }
72 void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override {
73 RTC_DCHECK(network_thread_.CalledOnValidThread());
74 rtc::CritScope lock(&crit_);
75 if (feedback_observer_)
76 feedback_observer_->OnTransportFeedback(feedback);
77 }
78
79 private:
80 rtc::CriticalSection crit_;
81 rtc::ThreadChecker thread_checker_;
82 rtc::ThreadChecker pacer_thread_;
83 rtc::ThreadChecker network_thread_;
84 TransportFeedbackObserver* feedback_observer_ GUARDED_BY(&crit_);
85};
86
87class TransportSequenceNumberProxy : public TransportSequenceNumberAllocator {
88 public:
89 TransportSequenceNumberProxy() : seq_num_allocator_(nullptr) {
90 pacer_thread_.DetachFromThread();
91 }
92
93 void SetSequenceNumberAllocator(
94 TransportSequenceNumberAllocator* seq_num_allocator) {
95 RTC_DCHECK(thread_checker_.CalledOnValidThread());
96 rtc::CritScope lock(&crit_);
97 seq_num_allocator_ = seq_num_allocator;
98 }
99
100 // Implements TransportSequenceNumberAllocator.
101 uint16_t AllocateSequenceNumber() override {
102 RTC_DCHECK(pacer_thread_.CalledOnValidThread());
103 rtc::CritScope lock(&crit_);
104 if (!seq_num_allocator_)
105 return 0;
106 return seq_num_allocator_->AllocateSequenceNumber();
107 }
108
109 private:
110 rtc::CriticalSection crit_;
111 rtc::ThreadChecker thread_checker_;
112 rtc::ThreadChecker pacer_thread_;
113 TransportSequenceNumberAllocator* seq_num_allocator_ GUARDED_BY(&crit_);
114};
115
116class RtpPacketSenderProxy : public RtpPacketSender {
117 public:
118 RtpPacketSenderProxy() : rtp_packet_sender_(nullptr) {
119 }
120
121 void SetPacketSender(RtpPacketSender* rtp_packet_sender) {
122 RTC_DCHECK(thread_checker_.CalledOnValidThread());
123 rtc::CritScope lock(&crit_);
124 rtp_packet_sender_ = rtp_packet_sender;
125 }
126
127 // Implements RtpPacketSender.
128 void InsertPacket(Priority priority,
129 uint32_t ssrc,
130 uint16_t sequence_number,
131 int64_t capture_time_ms,
132 size_t bytes,
133 bool retransmission) override {
134 rtc::CritScope lock(&crit_);
135 if (rtp_packet_sender_) {
136 rtp_packet_sender_->InsertPacket(priority, ssrc, sequence_number,
137 capture_time_ms, bytes, retransmission);
138 }
139 }
140
141 private:
142 rtc::ThreadChecker thread_checker_;
143 rtc::CriticalSection crit_;
144 RtpPacketSender* rtp_packet_sender_ GUARDED_BY(&crit_);
145};
146
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000147// Extend the default RTCP statistics struct with max_jitter, defined as the
148// maximum jitter value seen in an RTCP report block.
149struct ChannelStatistics : public RtcpStatistics {
150 ChannelStatistics() : rtcp(), max_jitter(0) {}
151
152 RtcpStatistics rtcp;
153 uint32_t max_jitter;
154};
155
156// Statistics callback, called at each generation of a new RTCP report block.
157class StatisticsProxy : public RtcpStatisticsCallback {
158 public:
159 StatisticsProxy(uint32_t ssrc)
160 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
161 ssrc_(ssrc) {}
162 virtual ~StatisticsProxy() {}
163
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000164 void StatisticsUpdated(const RtcpStatistics& statistics,
165 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000166 if (ssrc != ssrc_)
167 return;
168
169 CriticalSectionScoped cs(stats_lock_.get());
170 stats_.rtcp = statistics;
171 if (statistics.jitter > stats_.max_jitter) {
172 stats_.max_jitter = statistics.jitter;
173 }
174 }
175
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000176 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +0000177
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000178 ChannelStatistics GetStats() {
179 CriticalSectionScoped cs(stats_lock_.get());
180 return stats_;
181 }
182
183 private:
184 // StatisticsUpdated calls are triggered from threads in the RTP module,
185 // while GetStats calls can be triggered from the public voice engine API,
186 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000187 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000188 const uint32_t ssrc_;
189 ChannelStatistics stats_;
190};
191
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000192class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000193 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000194 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
195 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000196
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000197 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
198 // Not used for Voice Engine.
199 }
200
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000201 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
202 int64_t rtt,
203 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000204 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
205 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
206 // report for VoiceEngine?
207 if (report_blocks.empty())
208 return;
209
210 int fraction_lost_aggregate = 0;
211 int total_number_of_packets = 0;
212
213 // If receiving multiple report blocks, calculate the weighted average based
214 // on the number of packets a report refers to.
215 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
216 block_it != report_blocks.end(); ++block_it) {
217 // Find the previous extended high sequence number for this remote SSRC,
218 // to calculate the number of RTP packets this report refers to. Ignore if
219 // we haven't seen this SSRC before.
220 std::map<uint32_t, uint32_t>::iterator seq_num_it =
221 extended_max_sequence_number_.find(block_it->sourceSSRC);
222 int number_of_packets = 0;
223 if (seq_num_it != extended_max_sequence_number_.end()) {
224 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
225 }
226 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
227 total_number_of_packets += number_of_packets;
228
229 extended_max_sequence_number_[block_it->sourceSSRC] =
230 block_it->extendedHighSeqNum;
231 }
232 int weighted_fraction_lost = 0;
233 if (total_number_of_packets > 0) {
234 weighted_fraction_lost = (fraction_lost_aggregate +
235 total_number_of_packets / 2) / total_number_of_packets;
236 }
237 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000238 }
239
240 private:
241 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000242 // Maps remote side ssrc to extended highest sequence number received.
243 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000244};
245
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000246int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000247Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000248 uint8_t payloadType,
249 uint32_t timeStamp,
250 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000251 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 const RTPFragmentationHeader* fragmentation)
253{
254 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
255 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000256 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
257 frameType, payloadType, timeStamp,
258 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000259
260 if (_includeAudioLevelIndication)
261 {
262 // Store current audio level in the RTP/RTCP module.
263 // The level will be used in combination with voice-activity state
264 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000265 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 }
267
268 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
269 // packetization.
270 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000271 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000272 payloadType,
273 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000274 // Leaving the time when this frame was
275 // received from the capture device as
276 // undefined for voice for now.
277 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 payloadData,
279 payloadSize,
280 fragmentation) == -1)
281 {
282 _engineStatisticsPtr->SetLastError(
283 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
284 "Channel::SendData() failed to send data to RTP/RTCP module");
285 return -1;
286 }
287
288 _lastLocalTimeStamp = timeStamp;
289 _lastPayloadType = payloadType;
290
291 return 0;
292}
293
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000294int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000295Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000296{
297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000298 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000299
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000300 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000301 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000302 return 0;
303}
304
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000305int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000306Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000307{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000308 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000309 if (_rxVadObserverPtr)
310 {
311 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
312 }
313
314 return 0;
315}
316
stefan1d8a5062015-10-02 03:39:33 -0700317bool Channel::SendRtp(const uint8_t* data,
318 size_t len,
319 const PacketOptions& options) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200321 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000322
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000323 CriticalSectionScoped cs(&_callbackCritSect);
324
niklase@google.com470e71d2011-07-07 08:21:25 +0000325 if (_transportPtr == NULL)
326 {
327 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
328 "Channel::SendPacket() failed to send RTP packet due to"
329 " invalid transport object");
pbos2d566682015-09-28 09:59:31 -0700330 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 }
332
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000333 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000334 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000335
stefan1d8a5062015-10-02 03:39:33 -0700336 if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000337 std::string transport_name =
338 _externalTransport ? "external transport" : "WebRtc sockets";
339 WEBRTC_TRACE(kTraceError, kTraceVoice,
340 VoEId(_instanceId,_channelId),
341 "Channel::SendPacket() RTP transmission using %s failed",
342 transport_name.c_str());
pbos2d566682015-09-28 09:59:31 -0700343 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000344 }
pbos2d566682015-09-28 09:59:31 -0700345 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000346}
347
pbos2d566682015-09-28 09:59:31 -0700348bool
349Channel::SendRtcp(const uint8_t *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000350{
niklase@google.com470e71d2011-07-07 08:21:25 +0000351 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700352 "Channel::SendRtcp(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000353
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000354 CriticalSectionScoped cs(&_callbackCritSect);
355 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000356 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000357 WEBRTC_TRACE(kTraceError, kTraceVoice,
358 VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700359 "Channel::SendRtcp() failed to send RTCP packet"
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000360 " due to invalid transport object");
pbos2d566682015-09-28 09:59:31 -0700361 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000362 }
363
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000364 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000365 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000366
pbos2d566682015-09-28 09:59:31 -0700367 int n = _transportPtr->SendRtcp(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000368 if (n < 0) {
369 std::string transport_name =
370 _externalTransport ? "external transport" : "WebRtc sockets";
371 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
372 VoEId(_instanceId,_channelId),
pbos2d566682015-09-28 09:59:31 -0700373 "Channel::SendRtcp() transmission using %s failed",
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000374 transport_name.c_str());
pbos2d566682015-09-28 09:59:31 -0700375 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 }
pbos2d566682015-09-28 09:59:31 -0700377 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000378}
379
Peter Boströmac547a62015-09-17 23:03:57 +0200380void Channel::OnPlayTelephoneEvent(uint8_t event,
381 uint16_t lengthMs,
382 uint8_t volume) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200384 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
385 " volume=%u)", event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386
387 if (!_playOutbandDtmfEvent || (event > 15))
388 {
389 // Ignore callback since feedback is disabled or event is not a
390 // Dtmf tone event.
391 return;
392 }
393
394 assert(_outputMixerPtr != NULL);
395
396 // Start playing out the Dtmf tone (if playout is enabled).
397 // Reduce length of tone with 80ms to the reduce risk of echo.
398 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
399}
400
401void
Peter Boströmac547a62015-09-17 23:03:57 +0200402Channel::OnIncomingSSRCChanged(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000403{
404 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200405 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000406
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000407 // Update ssrc so that NTP for AV sync can be updated.
408 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000409}
410
Peter Boströmac547a62015-09-17 23:03:57 +0200411void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
412 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
413 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
414 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000415}
416
Peter Boströmac547a62015-09-17 23:03:57 +0200417int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000418 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000419 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000420 int frequency,
421 uint8_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200422 uint32_t rate) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200424 "Channel::OnInitializeDecoder(payloadType=%d, "
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
Peter Boströmac547a62015-09-17 23:03:57 +0200426 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000427
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000428 CodecInst receiveCodec = {0};
429 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000430
431 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000432 receiveCodec.plfreq = frequency;
433 receiveCodec.channels = channels;
434 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000435 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000436
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000437 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 receiveCodec.pacsize = dummyCodec.pacsize;
439
440 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000441 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 {
443 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000444 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 "Channel::OnInitializeDecoder() invalid codec ("
446 "pt=%d, name=%s) received - 1", payloadType, payloadName);
447 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
448 return -1;
449 }
450
451 return 0;
452}
453
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000454int32_t
455Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000456 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 const WebRtcRTPHeader* rtpHeader)
458{
459 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000460 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 " payloadType=%u, audioChannel=%u)",
462 payloadSize,
463 rtpHeader->header.payloadType,
464 rtpHeader->type.Audio.channel);
465
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000466 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 {
468 // Avoid inserting into NetEQ when we are not playing. Count the
469 // packet as discarded.
470 WEBRTC_TRACE(kTraceStream, kTraceVoice,
471 VoEId(_instanceId, _channelId),
472 "received packet is discarded since playing is not"
473 " activated");
474 _numberOfDiscardedPackets++;
475 return 0;
476 }
477
478 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000479 if (audio_coding_->IncomingPacket(payloadData,
480 payloadSize,
481 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 {
483 _engineStatisticsPtr->SetLastError(
484 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
485 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
486 return -1;
487 }
488
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000489 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 UpdatePacketDelay(rtpHeader->header.timestamp,
491 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000492
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000493 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000494 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
495 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000496
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000497 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000498 round_trip_time);
499 if (!nack_list.empty()) {
500 // Can't use nack_list.data() since it's not supported by all
501 // compilers.
502 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000503 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 return 0;
505}
506
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000507bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000508 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000509 RTPHeader header;
510 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
511 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
512 "IncomingPacket invalid RTP header");
513 return false;
514 }
515 header.payload_type_frequency =
516 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
517 if (header.payload_type_frequency < 0)
518 return false;
519 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
520}
521
minyuel0f4b3732015-08-31 16:04:32 +0200522int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000523{
Ivo Creusenae856f22015-09-17 16:30:16 +0200524 if (event_log_) {
525 unsigned int ssrc;
526 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
527 event_log_->LogAudioPlayout(ssrc);
528 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000529 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200530 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
531 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000532 {
533 WEBRTC_TRACE(kTraceError, kTraceVoice,
534 VoEId(_instanceId,_channelId),
535 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000536 // In all likelihood, the audio in this frame is garbage. We return an
537 // error so that the audio mixer module doesn't add it to the mix. As
538 // a result, it won't be played out and the actions skipped here are
539 // irrelevant.
540 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000541 }
542
543 if (_RxVadDetection)
544 {
minyuel0f4b3732015-08-31 16:04:32 +0200545 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 }
547
548 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200549 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200551 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000553 ChannelState::State state = channel_state_.Get();
554
555 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200556 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000557 if (err) {
558 LOG(LS_ERROR) << "ProcessStream() error: " << err;
559 assert(false);
560 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000561 }
562
wu@webrtc.org63420662013-10-17 18:28:55 +0000563 float output_gain = 1.0f;
564 float left_pan = 1.0f;
565 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000567 CriticalSectionScoped cs(&volume_settings_critsect_);
568 output_gain = _outputGain;
569 left_pan = _panLeft;
570 right_pan= _panRight;
571 }
572
573 // Output volume scaling
574 if (output_gain < 0.99f || output_gain > 1.01f)
575 {
minyuel0f4b3732015-08-31 16:04:32 +0200576 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000577 }
578
579 // Scale left and/or right channel(s) if stereo and master balance is
580 // active
581
wu@webrtc.org63420662013-10-17 18:28:55 +0000582 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 {
minyuel0f4b3732015-08-31 16:04:32 +0200584 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000585 {
586 // Emulate stereo mode since panning is active.
587 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200588 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 }
590 // For true stereo mode (when we are receiving a stereo signal), no
591 // action is needed.
592
593 // Do the panning operation (the audio frame contains stereo at this
594 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200595 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 }
597
598 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000599 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 {
minyuel0f4b3732015-08-31 16:04:32 +0200601 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 }
603
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 // External media
605 if (_outputExternalMedia)
606 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000607 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200608 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 if (_outputExternalMediaCallbackPtr)
610 {
611 _outputExternalMediaCallbackPtr->Process(
612 _channelId,
613 kPlaybackPerChannel,
minyuel0f4b3732015-08-31 16:04:32 +0200614 (int16_t*)audioFrame->data_,
615 audioFrame->samples_per_channel_,
616 audioFrame->sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 isStereo);
618 }
619 }
620
621 // Record playout if enabled
622 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000623 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
625 if (_outputFileRecording && _outputFileRecorderPtr)
626 {
minyuel0f4b3732015-08-31 16:04:32 +0200627 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 }
629 }
630
631 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200632 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000633
minyuel0f4b3732015-08-31 16:04:32 +0200634 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000635 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200636 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000637 }
638
639 if (capture_start_rtp_time_stamp_ >= 0) {
640 // audioFrame.timestamp_ should be valid from now on.
641
642 // Compute elapsed time.
643 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200644 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
645 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000646 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
647 (GetPlayoutFrequency() / 1000);
648
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000649 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000650 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000651 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200652 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
653 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000654 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200655 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000656 // Compute |capture_start_ntp_time_ms_| so that
657 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
658 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200659 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000660 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000661 }
662 }
663
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 return 0;
665}
666
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000667int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200668Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000669{
670 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
671 "Channel::NeededFrequency(id=%d)", id);
672
673 int highestNeeded = 0;
674
675 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000676 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000677
678 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000679 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000680 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000681 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 }
683 else
684 {
685 highestNeeded = receiveFrequency;
686 }
687
688 // Special case, if we're playing a file on the playout side
689 // we take that frequency into consideration as well
690 // This is not needed on sending side, since the codec will
691 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000692 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000693 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000694 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000695 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 {
697 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
698 {
699 highestNeeded=_outputFilePlayerPtr->Frequency();
700 }
701 }
702 }
703
704 return(highestNeeded);
705}
706
ivocb04965c2015-09-09 00:09:43 -0700707int32_t Channel::CreateChannel(Channel*& channel,
708 int32_t channelId,
709 uint32_t instanceId,
710 RtcEventLog* const event_log,
711 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
713 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
714 channelId, instanceId);
715
ivocb04965c2015-09-09 00:09:43 -0700716 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 if (channel == NULL)
718 {
719 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
720 VoEId(instanceId,channelId),
721 "Channel::CreateChannel() unable to allocate memory for"
722 " channel");
723 return -1;
724 }
725 return 0;
726}
727
728void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000729Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000730{
731 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
732 "Channel::PlayNotification(id=%d, durationMs=%d)",
733 id, durationMs);
734
735 // Not implement yet
736}
737
738void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000739Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000740{
741 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
742 "Channel::RecordNotification(id=%d, durationMs=%d)",
743 id, durationMs);
744
745 // Not implement yet
746}
747
748void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000749Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000750{
751 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
752 "Channel::PlayFileEnded(id=%d)", id);
753
754 if (id == _inputFilePlayerId)
755 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000756 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000757 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
758 VoEId(_instanceId,_channelId),
759 "Channel::PlayFileEnded() => input file player module is"
760 " shutdown");
761 }
762 else if (id == _outputFilePlayerId)
763 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000764 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
766 VoEId(_instanceId,_channelId),
767 "Channel::PlayFileEnded() => output file player module is"
768 " shutdown");
769 }
770}
771
772void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000773Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000774{
775 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
776 "Channel::RecordFileEnded(id=%d)", id);
777
778 assert(id == _outputFileRecorderId);
779
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000780 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000781
782 _outputFileRecording = false;
783 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
784 VoEId(_instanceId,_channelId),
785 "Channel::RecordFileEnded() => output file recorder module is"
786 " shutdown");
787}
788
pbos@webrtc.org92135212013-05-14 08:31:39 +0000789Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000790 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700791 RtcEventLog* const event_log,
792 const Config& config)
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100793 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
794 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
795 volume_settings_critsect_(
796 *CriticalSectionWrapper::CreateCriticalSection()),
797 _instanceId(instanceId),
798 _channelId(channelId),
799 event_log_(event_log),
800 rtp_header_parser_(RtpHeaderParser::Create()),
801 rtp_payload_registry_(
802 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
803 rtp_receive_statistics_(
804 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
805 rtp_receiver_(
806 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
807 this,
808 this,
809 this,
810 rtp_payload_registry_.get())),
811 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
812 _outputAudioLevel(),
813 _externalTransport(false),
814 _inputFilePlayerPtr(NULL),
815 _outputFilePlayerPtr(NULL),
816 _outputFileRecorderPtr(NULL),
817 // Avoid conflict with other channels by adding 1024 - 1026,
818 // won't use as much as 1024 channels.
819 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
820 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
821 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
822 _outputFileRecording(false),
823 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
824 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
825 _outputExternalMedia(false),
826 _inputExternalMediaCallbackPtr(NULL),
827 _outputExternalMediaCallbackPtr(NULL),
828 _timeStamp(0), // This is just an offset, RTP module will add it's own
829 // random offset
830 _sendTelephoneEventPayloadType(106),
831 ntp_estimator_(Clock::GetRealTimeClock()),
832 jitter_buffer_playout_timestamp_(0),
833 playout_timestamp_rtp_(0),
834 playout_timestamp_rtcp_(0),
835 playout_delay_ms_(0),
836 _numberOfDiscardedPackets(0),
837 send_sequence_number_(0),
838 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
839 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
840 capture_start_rtp_time_stamp_(-1),
841 capture_start_ntp_time_ms_(-1),
842 _engineStatisticsPtr(NULL),
843 _outputMixerPtr(NULL),
844 _transmitMixerPtr(NULL),
845 _moduleProcessThreadPtr(NULL),
846 _audioDeviceModulePtr(NULL),
847 _voiceEngineObserverPtr(NULL),
848 _callbackCritSectPtr(NULL),
849 _transportPtr(NULL),
850 _rxVadObserverPtr(NULL),
851 _oldVadDecision(-1),
852 _sendFrameType(0),
853 _externalMixing(false),
854 _mixFileWithMicrophone(false),
855 _mute(false),
856 _panLeft(1.0f),
857 _panRight(1.0f),
858 _outputGain(1.0f),
859 _playOutbandDtmfEvent(false),
860 _playInbandDtmfEvent(false),
861 _lastLocalTimeStamp(0),
862 _lastPayloadType(0),
863 _includeAudioLevelIndication(false),
864 _outputSpeechType(AudioFrame::kNormalSpeech),
865 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
866 _average_jitter_buffer_delay_us(0),
867 _previousTimestamp(0),
868 _recPacketDelayMs(20),
869 _RxVadDetection(false),
870 _rxAgcIsEnabled(false),
871 _rxNsIsEnabled(false),
872 restored_packet_in_use_(false),
873 rtcp_observer_(new VoERtcpObserver(this)),
874 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
875 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
876 associate_send_channel_(ChannelOwner(nullptr)),
877 pacing_enabled_(config.Get<VoicePacing>().enabled),
878 feedback_observer_proxy_(pacing_enabled_ ? new TransportFeedbackProxy()
879 : nullptr),
880 seq_num_allocator_proxy_(
881 pacing_enabled_ ? new TransportSequenceNumberProxy() : nullptr),
882 rtp_packet_sender_proxy_(pacing_enabled_ ? new RtpPacketSenderProxy()
883 : nullptr) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
885 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200886 AudioCodingModule::Config acm_config;
887 acm_config.id = VoEModuleId(instanceId, channelId);
888 if (config.Get<NetEqCapacityConfig>().enabled) {
889 // Clamping the buffer capacity at 20 packets. While going lower will
890 // probably work, it makes little sense.
891 acm_config.neteq_config.max_packets_in_buffer =
892 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
893 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200894 acm_config.neteq_config.enable_fast_accelerate =
895 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200896 audio_coding_.reset(AudioCodingModule::Create(acm_config));
897
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 _inbandDtmfQueue.ResetDtmf();
899 _inbandDtmfGenerator.Init();
900 _outputAudioLevel.Clear();
901
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000902 RtpRtcp::Configuration configuration;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000903 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000904 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000905 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000906 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000907 configuration.bandwidth_callback = rtcp_observer_.get();
Stefan Holmerb86d4e42015-12-07 10:26:18 +0100908 configuration.paced_sender = rtp_packet_sender_proxy_.get();
909 configuration.transport_sequence_number_allocator =
910 seq_num_allocator_proxy_.get();
911 configuration.transport_feedback_callback = feedback_observer_proxy_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000912
913 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000914
915 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
916 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
917 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000918
919 Config audioproc_config;
920 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
921 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000922}
923
924Channel::~Channel()
925{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000926 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
928 "Channel::~Channel() - dtor");
929
930 if (_outputExternalMedia)
931 {
932 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
933 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000934 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 {
936 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
937 }
938 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000939 StopPlayout();
940
941 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000942 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 if (_inputFilePlayerPtr)
944 {
945 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
946 _inputFilePlayerPtr->StopPlayingFile();
947 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
948 _inputFilePlayerPtr = NULL;
949 }
950 if (_outputFilePlayerPtr)
951 {
952 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
953 _outputFilePlayerPtr->StopPlayingFile();
954 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
955 _outputFilePlayerPtr = NULL;
956 }
957 if (_outputFileRecorderPtr)
958 {
959 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
960 _outputFileRecorderPtr->StopRecording();
961 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
962 _outputFileRecorderPtr = NULL;
963 }
964 }
965
966 // The order to safely shutdown modules in a channel is:
967 // 1. De-register callbacks in modules
968 // 2. De-register modules in process thread
969 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000970 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 {
972 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
973 VoEId(_instanceId,_channelId),
974 "~Channel() failed to de-register transport callback"
975 " (Audio coding module)");
976 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000977 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 {
979 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
980 VoEId(_instanceId,_channelId),
981 "~Channel() failed to de-register VAD callback"
982 " (Audio coding module)");
983 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000985 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
986
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 // End of modules shutdown
988
989 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000992 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000993}
994
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000995int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000996Channel::Init()
997{
998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
999 "Channel::Init()");
1000
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001001 channel_state_.Reset();
1002
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 // --- Initial sanity
1004
1005 if ((_engineStatisticsPtr == NULL) ||
1006 (_moduleProcessThreadPtr == NULL))
1007 {
1008 WEBRTC_TRACE(kTraceError, kTraceVoice,
1009 VoEId(_instanceId,_channelId),
1010 "Channel::Init() must call SetEngineInformation() first");
1011 return -1;
1012 }
1013
1014 // --- Add modules to process thread (for periodic schedulation)
1015
tommi@webrtc.org3985f012015-02-27 13:36:34 +00001016 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
1017
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001018 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001019
henrik.lundin061b79a2015-09-18 01:29:11 -07001020 if (audio_coding_->InitializeReceiver() == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 _engineStatisticsPtr->SetLastError(
1022 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1023 "Channel::Init() unable to initialize the ACM - 1");
1024 return -1;
1025 }
1026
1027 // --- RTP/RTCP module initialization
1028
1029 // Ensure that RTCP is enabled by default for the created channel.
1030 // Note that, the module will keep generating RTCP until it is explicitly
1031 // disabled by the user.
1032 // After StopListen (when no sockets exists), RTCP packets will no longer
1033 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001034 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1035 // RTCP is enabled by default.
pbosda903ea2015-10-02 02:36:56 -07001036 _rtpRtcpModule->SetRTCPStatus(RtcpMode::kCompound);
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001037 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001039 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1040 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001041
1042 if (fail)
1043 {
1044 _engineStatisticsPtr->SetLastError(
1045 VE_CANNOT_INIT_CHANNEL, kTraceError,
1046 "Channel::Init() callbacks not registered");
1047 return -1;
1048 }
1049
1050 // --- Register all supported codecs to the receiving side of the
1051 // RTP/RTCP module
1052
1053 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001054 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001055
1056 for (int idx = 0; idx < nSupportedCodecs; idx++)
1057 {
1058 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001059 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001060 (rtp_receiver_->RegisterReceivePayload(
1061 codec.plname,
1062 codec.pltype,
1063 codec.plfreq,
1064 codec.channels,
1065 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 {
1067 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1068 VoEId(_instanceId,_channelId),
1069 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1070 "to RTP/RTCP receiver",
1071 codec.plname, codec.pltype, codec.plfreq,
1072 codec.channels, codec.rate);
1073 }
1074 else
1075 {
1076 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1077 VoEId(_instanceId,_channelId),
1078 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1079 "the RTP/RTCP receiver",
1080 codec.plname, codec.pltype, codec.plfreq,
1081 codec.channels, codec.rate);
1082 }
1083
1084 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001085 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001086 {
1087 SetSendCodec(codec);
1088 }
1089
1090 // Register default PT for outband 'telephone-event'
1091 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1092 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001093 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001094 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001095 {
1096 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1097 VoEId(_instanceId,_channelId),
1098 "Channel::Init() failed to register outband "
1099 "'telephone-event' (%d/%d) correctly",
1100 codec.pltype, codec.plfreq);
1101 }
1102 }
1103
1104 if (!STR_CASE_CMP(codec.plname, "CN"))
1105 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001106 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1107 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001108 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 {
1110 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1111 VoEId(_instanceId,_channelId),
1112 "Channel::Init() failed to register CN (%d/%d) "
1113 "correctly - 1",
1114 codec.pltype, codec.plfreq);
1115 }
1116 }
1117#ifdef WEBRTC_CODEC_RED
1118 // Register RED to the receiving side of the ACM.
1119 // We will not receive an OnInitializeDecoder() callback for RED.
1120 if (!STR_CASE_CMP(codec.plname, "RED"))
1121 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001122 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 {
1124 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1125 VoEId(_instanceId,_channelId),
1126 "Channel::Init() failed to register RED (%d/%d) "
1127 "correctly",
1128 codec.pltype, codec.plfreq);
1129 }
1130 }
1131#endif
1132 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001133
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001134 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001135 LOG(LS_ERROR) << "noise_suppression()->set_level(kDefaultNsMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001136 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001138 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
pbosad856222015-11-27 09:48:36 -08001139 LOG(LS_ERROR) << "gain_control()->set_mode(kDefaultRxAgcMode) failed.";
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001140 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 }
1142
1143 return 0;
1144}
1145
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001146int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001147Channel::SetEngineInformation(Statistics& engineStatistics,
1148 OutputMixer& outputMixer,
1149 voe::TransmitMixer& transmitMixer,
1150 ProcessThread& moduleProcessThread,
1151 AudioDeviceModule& audioDeviceModule,
1152 VoiceEngineObserver* voiceEngineObserver,
1153 CriticalSectionWrapper* callbackCritSect)
1154{
1155 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1156 "Channel::SetEngineInformation()");
1157 _engineStatisticsPtr = &engineStatistics;
1158 _outputMixerPtr = &outputMixer;
1159 _transmitMixerPtr = &transmitMixer,
1160 _moduleProcessThreadPtr = &moduleProcessThread;
1161 _audioDeviceModulePtr = &audioDeviceModule;
1162 _voiceEngineObserverPtr = voiceEngineObserver;
1163 _callbackCritSectPtr = callbackCritSect;
1164 return 0;
1165}
1166
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001167int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001168Channel::UpdateLocalTimeStamp()
1169{
1170
Peter Kastingb7e50542015-06-11 12:55:50 -07001171 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 return 0;
1173}
1174
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001175int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001176Channel::StartPlayout()
1177{
1178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1179 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001180 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 {
1182 return 0;
1183 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001184
1185 if (!_externalMixing) {
1186 // Add participant as candidates for mixing.
1187 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1188 {
1189 _engineStatisticsPtr->SetLastError(
1190 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1191 "StartPlayout() failed to add participant to mixer");
1192 return -1;
1193 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 }
1195
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001196 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001197 if (RegisterFilePlayingToMixer() != 0)
1198 return -1;
1199
niklase@google.com470e71d2011-07-07 08:21:25 +00001200 return 0;
1201}
1202
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001203int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001204Channel::StopPlayout()
1205{
1206 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1207 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001208 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 {
1210 return 0;
1211 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001212
1213 if (!_externalMixing) {
1214 // Remove participant as candidates for mixing
1215 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1216 {
1217 _engineStatisticsPtr->SetLastError(
1218 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1219 "StopPlayout() failed to remove participant from mixer");
1220 return -1;
1221 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 }
1223
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001224 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 _outputAudioLevel.Clear();
1226
1227 return 0;
1228}
1229
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001230int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001231Channel::StartSend()
1232{
1233 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1234 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001235 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001236 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001237 if (send_sequence_number_)
1238 SetInitSequenceNumber(send_sequence_number_);
1239
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001240 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001244 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001245
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001246 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 {
1248 _engineStatisticsPtr->SetLastError(
1249 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1250 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001251 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001252 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 return -1;
1254 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001255
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 return 0;
1257}
1258
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001259int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001260Channel::StopSend()
1261{
1262 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1263 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001264 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001265 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001266 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001267 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001268 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001269
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001270 // Store the sequence number to be able to pick up the same sequence for
1271 // the next StartSend(). This is needed for restarting device, otherwise
1272 // it might cause libSRTP to complain about packets being replayed.
1273 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1274 // CL is landed. See issue
1275 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1276 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1277
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 // Reset sending SSRC and sequence number and triggers direct transmission
1279 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001280 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 {
1282 _engineStatisticsPtr->SetLastError(
1283 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1284 "StartSend() RTP/RTCP failed to stop sending");
1285 }
1286
niklase@google.com470e71d2011-07-07 08:21:25 +00001287 return 0;
1288}
1289
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001290int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001291Channel::StartReceiving()
1292{
1293 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1294 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001295 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 {
1297 return 0;
1298 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001299 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 _numberOfDiscardedPackets = 0;
1301 return 0;
1302}
1303
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001304int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001305Channel::StopReceiving()
1306{
1307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1308 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001309 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001310 {
1311 return 0;
1312 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001313
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001314 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 return 0;
1316}
1317
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001318int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001319Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1320{
1321 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1322 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001323 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001324
1325 if (_voiceEngineObserverPtr)
1326 {
1327 _engineStatisticsPtr->SetLastError(
1328 VE_INVALID_OPERATION, kTraceError,
1329 "RegisterVoiceEngineObserver() observer already enabled");
1330 return -1;
1331 }
1332 _voiceEngineObserverPtr = &observer;
1333 return 0;
1334}
1335
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001336int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001337Channel::DeRegisterVoiceEngineObserver()
1338{
1339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "Channel::DeRegisterVoiceEngineObserver()");
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, kTraceWarning,
1347 "DeRegisterVoiceEngineObserver() observer already disabled");
1348 return 0;
1349 }
1350 _voiceEngineObserverPtr = NULL;
1351 return 0;
1352}
1353
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001354int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001355Channel::GetSendCodec(CodecInst& codec)
1356{
kwiberg1fd4a4a2015-11-03 11:20:50 -08001357 auto send_codec = audio_coding_->SendCodec();
1358 if (send_codec) {
1359 codec = *send_codec;
1360 return 0;
1361 }
1362 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001363}
1364
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001365int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001366Channel::GetRecCodec(CodecInst& codec)
1367{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001368 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001369}
1370
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001371int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001372Channel::SetSendCodec(const CodecInst& codec)
1373{
1374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1375 "Channel::SetSendCodec()");
1376
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001377 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 {
1379 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1380 "SetSendCodec() failed to register codec to ACM");
1381 return -1;
1382 }
1383
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001384 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001385 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001386 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1387 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 {
1389 WEBRTC_TRACE(
1390 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1391 "SetSendCodec() failed to register codec to"
1392 " RTP/RTCP module");
1393 return -1;
1394 }
1395 }
1396
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001397 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001398 {
1399 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1400 "SetSendCodec() failed to set audio packet size");
1401 return -1;
1402 }
1403
1404 return 0;
1405}
1406
Ivo Creusenadf89b72015-04-29 16:03:33 +02001407void Channel::SetBitRate(int bitrate_bps) {
1408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1409 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1410 audio_coding_->SetBitRate(bitrate_bps);
1411}
1412
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001413void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001414 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001415 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1416
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001417 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001418 if (audio_coding_->SetPacketLossRate(
1419 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001420 assert(false); // This should not happen.
1421 }
1422}
1423
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001424int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001425Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1426{
1427 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1428 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001429 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 // To disable VAD, DTX must be disabled too
1431 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001432 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001433 {
1434 _engineStatisticsPtr->SetLastError(
1435 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1436 "SetVADStatus() failed to set VAD");
1437 return -1;
1438 }
1439 return 0;
1440}
1441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001442int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001443Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1444{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001445 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 {
1447 _engineStatisticsPtr->SetLastError(
1448 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1449 "GetVADStatus() failed to get VAD status");
1450 return -1;
1451 }
1452 disabledDTX = !disabledDTX;
1453 return 0;
1454}
1455
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001456int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001457Channel::SetRecPayloadType(const CodecInst& codec)
1458{
1459 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1460 "Channel::SetRecPayloadType()");
1461
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001462 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001463 {
1464 _engineStatisticsPtr->SetLastError(
1465 VE_ALREADY_PLAYING, kTraceError,
1466 "SetRecPayloadType() unable to set PT while playing");
1467 return -1;
1468 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001469 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001470 {
1471 _engineStatisticsPtr->SetLastError(
1472 VE_ALREADY_LISTENING, kTraceError,
1473 "SetRecPayloadType() unable to set PT while listening");
1474 return -1;
1475 }
1476
1477 if (codec.pltype == -1)
1478 {
1479 // De-register the selected codec (RTP/RTCP module and ACM)
1480
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001481 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 CodecInst rxCodec = codec;
1483
1484 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001485 rtp_payload_registry_->ReceivePayloadType(
1486 rxCodec.plname,
1487 rxCodec.plfreq,
1488 rxCodec.channels,
1489 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1490 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001491 rxCodec.pltype = pltype;
1492
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001493 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001494 {
1495 _engineStatisticsPtr->SetLastError(
1496 VE_RTP_RTCP_MODULE_ERROR,
1497 kTraceError,
1498 "SetRecPayloadType() RTP/RTCP-module deregistration "
1499 "failed");
1500 return -1;
1501 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001502 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001503 {
1504 _engineStatisticsPtr->SetLastError(
1505 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1506 "SetRecPayloadType() ACM deregistration failed - 1");
1507 return -1;
1508 }
1509 return 0;
1510 }
1511
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001512 if (rtp_receiver_->RegisterReceivePayload(
1513 codec.plname,
1514 codec.pltype,
1515 codec.plfreq,
1516 codec.channels,
1517 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001518 {
1519 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001520 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1521 if (rtp_receiver_->RegisterReceivePayload(
1522 codec.plname,
1523 codec.pltype,
1524 codec.plfreq,
1525 codec.channels,
1526 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 {
1528 _engineStatisticsPtr->SetLastError(
1529 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1530 "SetRecPayloadType() RTP/RTCP-module registration failed");
1531 return -1;
1532 }
1533 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001534 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001536 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1537 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001538 {
1539 _engineStatisticsPtr->SetLastError(
1540 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1541 "SetRecPayloadType() ACM registration failed - 1");
1542 return -1;
1543 }
1544 }
1545 return 0;
1546}
1547
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001548int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001549Channel::GetRecPayloadType(CodecInst& codec)
1550{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001551 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001552 if (rtp_payload_registry_->ReceivePayloadType(
1553 codec.plname,
1554 codec.plfreq,
1555 codec.channels,
1556 (codec.rate < 0) ? 0 : codec.rate,
1557 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001558 {
1559 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001560 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001561 "GetRecPayloadType() failed to retrieve RX payload type");
1562 return -1;
1563 }
1564 codec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001565 return 0;
1566}
1567
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001568int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001569Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1570{
1571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1572 "Channel::SetSendCNPayloadType()");
1573
1574 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001575 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001576 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001577 if (frequency == kFreq32000Hz)
1578 samplingFreqHz = 32000;
1579 else if (frequency == kFreq16000Hz)
1580 samplingFreqHz = 16000;
1581
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001582 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001583 {
1584 _engineStatisticsPtr->SetLastError(
1585 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1586 "SetSendCNPayloadType() failed to retrieve default CN codec "
1587 "settings");
1588 return -1;
1589 }
1590
1591 // Modify the payload type (must be set to dynamic range)
1592 codec.pltype = type;
1593
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001594 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001595 {
1596 _engineStatisticsPtr->SetLastError(
1597 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1598 "SetSendCNPayloadType() failed to register CN to ACM");
1599 return -1;
1600 }
1601
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001602 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001603 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001604 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1605 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 {
1607 _engineStatisticsPtr->SetLastError(
1608 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1609 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1610 "module");
1611 return -1;
1612 }
1613 }
1614 return 0;
1615}
1616
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001617int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001618 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001619 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001620
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001621 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001622 _engineStatisticsPtr->SetLastError(
1623 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001624 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001625 return -1;
1626 }
1627 return 0;
1628}
1629
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001630int Channel::SetOpusDtx(bool enable_dtx) {
1631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1632 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001633 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001634 : audio_coding_->DisableOpusDtx();
1635 if (ret != 0) {
1636 _engineStatisticsPtr->SetLastError(
1637 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1638 return -1;
1639 }
1640 return 0;
1641}
1642
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001643int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001644{
1645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1646 "Channel::RegisterExternalTransport()");
1647
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001648 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001649
niklase@google.com470e71d2011-07-07 08:21:25 +00001650 if (_externalTransport)
1651 {
1652 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1653 kTraceError,
1654 "RegisterExternalTransport() external transport already enabled");
1655 return -1;
1656 }
1657 _externalTransport = true;
1658 _transportPtr = &transport;
1659 return 0;
1660}
1661
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001662int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001663Channel::DeRegisterExternalTransport()
1664{
1665 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1666 "Channel::DeRegisterExternalTransport()");
1667
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001668 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001669
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 if (!_transportPtr)
1671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_INVALID_OPERATION, kTraceWarning,
1674 "DeRegisterExternalTransport() external transport already "
1675 "disabled");
1676 return 0;
1677 }
1678 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001679 _transportPtr = NULL;
1680 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1681 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001682 return 0;
1683}
1684
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001685int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001686 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001687 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1688 "Channel::ReceivedRTPPacket()");
1689
1690 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001691 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001692
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001693 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001694 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001695 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1696 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1697 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001698 return -1;
1699 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001700 header.payload_type_frequency =
1701 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001702 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001703 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001704 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001705 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001706 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001707 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001708
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001709 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001710}
1711
1712bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001713 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001714 const RTPHeader& header,
1715 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001716 if (rtp_payload_registry_->IsRtx(header)) {
1717 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001718 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001719 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001720 assert(packet_length >= header.headerLength);
1721 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001722 PayloadUnion payload_specific;
1723 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001724 &payload_specific)) {
1725 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001726 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001727 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1728 payload_specific, in_order);
1729}
1730
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001731bool Channel::HandleRtxPacket(const uint8_t* packet,
1732 size_t packet_length,
1733 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001734 if (!rtp_payload_registry_->IsRtx(header))
1735 return false;
1736
1737 // Remove the RTX header and parse the original RTP header.
1738 if (packet_length < header.headerLength)
1739 return false;
1740 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1741 return false;
1742 if (restored_packet_in_use_) {
1743 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1744 "Multiple RTX headers detected, dropping packet");
1745 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001746 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001747 if (!rtp_payload_registry_->RestoreOriginalPacket(
noahric65220a72015-10-14 11:29:49 -07001748 restored_packet_, packet, &packet_length, rtp_receiver_->SSRC(),
1749 header)) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001750 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1751 "Incoming RTX packet: invalid RTP header");
1752 return false;
1753 }
1754 restored_packet_in_use_ = true;
noahric65220a72015-10-14 11:29:49 -07001755 bool ret = OnRecoveredPacket(restored_packet_, packet_length);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001756 restored_packet_in_use_ = false;
1757 return ret;
1758}
1759
1760bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1761 StreamStatistician* statistician =
1762 rtp_receive_statistics_->GetStatistician(header.ssrc);
1763 if (!statistician)
1764 return false;
1765 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001766}
1767
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001768bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1769 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001770 // Retransmissions are handled separately if RTX is enabled.
1771 if (rtp_payload_registry_->RtxEnabled())
1772 return false;
1773 StreamStatistician* statistician =
1774 rtp_receive_statistics_->GetStatistician(header.ssrc);
1775 if (!statistician)
1776 return false;
1777 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001778 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001779 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001780 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001781 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001782}
1783
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001784int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001785 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1786 "Channel::ReceivedRTCPPacket()");
1787 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001788 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001789
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001790 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001791 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001792 _engineStatisticsPtr->SetLastError(
1793 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1794 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1795 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001796
Minyue2013aec2015-05-13 14:14:42 +02001797 int64_t rtt = GetRTT(true);
1798 if (rtt == 0) {
1799 // Waiting for valid RTT.
1800 return 0;
1801 }
1802 uint32_t ntp_secs = 0;
1803 uint32_t ntp_frac = 0;
1804 uint32_t rtp_timestamp = 0;
1805 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1806 &rtp_timestamp)) {
1807 // Waiting for RTCP.
1808 return 0;
1809 }
1810
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001811 {
1812 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001813 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001814 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001815 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001816}
1817
niklase@google.com470e71d2011-07-07 08:21:25 +00001818int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001819 bool loop,
1820 FileFormats format,
1821 int startPosition,
1822 float volumeScaling,
1823 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001824 const CodecInst* codecInst)
1825{
1826 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1827 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1828 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1829 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1830 startPosition, stopPosition);
1831
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001832 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001833 {
1834 _engineStatisticsPtr->SetLastError(
1835 VE_ALREADY_PLAYING, kTraceError,
1836 "StartPlayingFileLocally() is already playing");
1837 return -1;
1838 }
1839
niklase@google.com470e71d2011-07-07 08:21:25 +00001840 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001841 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001842
1843 if (_outputFilePlayerPtr)
1844 {
1845 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1846 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1847 _outputFilePlayerPtr = NULL;
1848 }
1849
1850 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1851 _outputFilePlayerId, (const FileFormats)format);
1852
1853 if (_outputFilePlayerPtr == NULL)
1854 {
1855 _engineStatisticsPtr->SetLastError(
1856 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001857 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001858 return -1;
1859 }
1860
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001861 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001862
1863 if (_outputFilePlayerPtr->StartPlayingFile(
1864 fileName,
1865 loop,
1866 startPosition,
1867 volumeScaling,
1868 notificationTime,
1869 stopPosition,
1870 (const CodecInst*)codecInst) != 0)
1871 {
1872 _engineStatisticsPtr->SetLastError(
1873 VE_BAD_FILE, kTraceError,
1874 "StartPlayingFile() failed to start file playout");
1875 _outputFilePlayerPtr->StopPlayingFile();
1876 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1877 _outputFilePlayerPtr = NULL;
1878 return -1;
1879 }
1880 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001881 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001882 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001883
1884 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001885 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001886
1887 return 0;
1888}
1889
1890int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001891 FileFormats format,
1892 int startPosition,
1893 float volumeScaling,
1894 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001895 const CodecInst* codecInst)
1896{
1897 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1898 "Channel::StartPlayingFileLocally(format=%d,"
1899 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1900 format, volumeScaling, startPosition, stopPosition);
1901
1902 if(stream == NULL)
1903 {
1904 _engineStatisticsPtr->SetLastError(
1905 VE_BAD_FILE, kTraceError,
1906 "StartPlayingFileLocally() NULL as input stream");
1907 return -1;
1908 }
1909
1910
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001911 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001912 {
1913 _engineStatisticsPtr->SetLastError(
1914 VE_ALREADY_PLAYING, kTraceError,
1915 "StartPlayingFileLocally() is already playing");
1916 return -1;
1917 }
1918
niklase@google.com470e71d2011-07-07 08:21:25 +00001919 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001920 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001921
1922 // Destroy the old instance
1923 if (_outputFilePlayerPtr)
1924 {
1925 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1926 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1927 _outputFilePlayerPtr = NULL;
1928 }
1929
1930 // Create the instance
1931 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1932 _outputFilePlayerId,
1933 (const FileFormats)format);
1934
1935 if (_outputFilePlayerPtr == NULL)
1936 {
1937 _engineStatisticsPtr->SetLastError(
1938 VE_INVALID_ARGUMENT, kTraceError,
1939 "StartPlayingFileLocally() filePlayer format isnot correct");
1940 return -1;
1941 }
1942
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001943 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001944
1945 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1946 volumeScaling,
1947 notificationTime,
1948 stopPosition, codecInst) != 0)
1949 {
1950 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1951 "StartPlayingFile() failed to "
1952 "start file playout");
1953 _outputFilePlayerPtr->StopPlayingFile();
1954 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1955 _outputFilePlayerPtr = NULL;
1956 return -1;
1957 }
1958 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001959 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001960 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001961
1962 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001963 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001964
niklase@google.com470e71d2011-07-07 08:21:25 +00001965 return 0;
1966}
1967
1968int Channel::StopPlayingFileLocally()
1969{
1970 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1971 "Channel::StopPlayingFileLocally()");
1972
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001973 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001974 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001975 return 0;
1976 }
1977
niklase@google.com470e71d2011-07-07 08:21:25 +00001978 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001979 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001980
1981 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1982 {
1983 _engineStatisticsPtr->SetLastError(
1984 VE_STOP_RECORDING_FAILED, kTraceError,
1985 "StopPlayingFile() could not stop playing");
1986 return -1;
1987 }
1988 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1989 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1990 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001991 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001993 // _fileCritSect cannot be taken while calling
1994 // SetAnonymousMixibilityStatus. Refer to comments in
1995 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001996 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1997 {
1998 _engineStatisticsPtr->SetLastError(
1999 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002000 "StopPlayingFile() failed to stop participant from playing as"
2001 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002002 return -1;
2003 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002004
2005 return 0;
2006}
2007
2008int Channel::IsPlayingFileLocally() const
2009{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002010 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002011}
2012
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002013int Channel::RegisterFilePlayingToMixer()
2014{
2015 // Return success for not registering for file playing to mixer if:
2016 // 1. playing file before playout is started on that channel.
2017 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002018 if (!channel_state_.Get().playing ||
2019 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002020 {
2021 return 0;
2022 }
2023
2024 // |_fileCritSect| cannot be taken while calling
2025 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2026 // frames can be pulled by the mixer. Since the frames are generated from
2027 // the file, _fileCritSect will be taken. This would result in a deadlock.
2028 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2029 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002030 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002031 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002032 _engineStatisticsPtr->SetLastError(
2033 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2034 "StartPlayingFile() failed to add participant as file to mixer");
2035 _outputFilePlayerPtr->StopPlayingFile();
2036 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2037 _outputFilePlayerPtr = NULL;
2038 return -1;
2039 }
2040
2041 return 0;
2042}
2043
niklase@google.com470e71d2011-07-07 08:21:25 +00002044int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002045 bool loop,
2046 FileFormats format,
2047 int startPosition,
2048 float volumeScaling,
2049 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002050 const CodecInst* codecInst)
2051{
2052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2053 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2054 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2055 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2056 startPosition, stopPosition);
2057
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002058 CriticalSectionScoped cs(&_fileCritSect);
2059
2060 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002061 {
2062 _engineStatisticsPtr->SetLastError(
2063 VE_ALREADY_PLAYING, kTraceWarning,
2064 "StartPlayingFileAsMicrophone() filePlayer is playing");
2065 return 0;
2066 }
2067
niklase@google.com470e71d2011-07-07 08:21:25 +00002068 // Destroy the old instance
2069 if (_inputFilePlayerPtr)
2070 {
2071 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2072 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2073 _inputFilePlayerPtr = NULL;
2074 }
2075
2076 // Create the instance
2077 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2078 _inputFilePlayerId, (const FileFormats)format);
2079
2080 if (_inputFilePlayerPtr == NULL)
2081 {
2082 _engineStatisticsPtr->SetLastError(
2083 VE_INVALID_ARGUMENT, kTraceError,
2084 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2085 return -1;
2086 }
2087
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002088 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002089
2090 if (_inputFilePlayerPtr->StartPlayingFile(
2091 fileName,
2092 loop,
2093 startPosition,
2094 volumeScaling,
2095 notificationTime,
2096 stopPosition,
2097 (const CodecInst*)codecInst) != 0)
2098 {
2099 _engineStatisticsPtr->SetLastError(
2100 VE_BAD_FILE, kTraceError,
2101 "StartPlayingFile() failed to start file playout");
2102 _inputFilePlayerPtr->StopPlayingFile();
2103 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2104 _inputFilePlayerPtr = NULL;
2105 return -1;
2106 }
2107 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002108 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002109
2110 return 0;
2111}
2112
2113int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002114 FileFormats format,
2115 int startPosition,
2116 float volumeScaling,
2117 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002118 const CodecInst* codecInst)
2119{
2120 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2121 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2122 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2123 format, volumeScaling, startPosition, stopPosition);
2124
2125 if(stream == NULL)
2126 {
2127 _engineStatisticsPtr->SetLastError(
2128 VE_BAD_FILE, kTraceError,
2129 "StartPlayingFileAsMicrophone NULL as input stream");
2130 return -1;
2131 }
2132
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002133 CriticalSectionScoped cs(&_fileCritSect);
2134
2135 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002136 {
2137 _engineStatisticsPtr->SetLastError(
2138 VE_ALREADY_PLAYING, kTraceWarning,
2139 "StartPlayingFileAsMicrophone() is playing");
2140 return 0;
2141 }
2142
niklase@google.com470e71d2011-07-07 08:21:25 +00002143 // Destroy the old instance
2144 if (_inputFilePlayerPtr)
2145 {
2146 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2147 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2148 _inputFilePlayerPtr = NULL;
2149 }
2150
2151 // Create the instance
2152 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2153 _inputFilePlayerId, (const FileFormats)format);
2154
2155 if (_inputFilePlayerPtr == NULL)
2156 {
2157 _engineStatisticsPtr->SetLastError(
2158 VE_INVALID_ARGUMENT, kTraceError,
2159 "StartPlayingInputFile() filePlayer format isnot correct");
2160 return -1;
2161 }
2162
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002163 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002164
2165 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2166 volumeScaling, notificationTime,
2167 stopPosition, codecInst) != 0)
2168 {
2169 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2170 "StartPlayingFile() failed to start "
2171 "file playout");
2172 _inputFilePlayerPtr->StopPlayingFile();
2173 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2174 _inputFilePlayerPtr = NULL;
2175 return -1;
2176 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002177
niklase@google.com470e71d2011-07-07 08:21:25 +00002178 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002179 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002180
2181 return 0;
2182}
2183
2184int Channel::StopPlayingFileAsMicrophone()
2185{
2186 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2187 "Channel::StopPlayingFileAsMicrophone()");
2188
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002189 CriticalSectionScoped cs(&_fileCritSect);
2190
2191 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002192 {
niklase@google.com470e71d2011-07-07 08:21:25 +00002193 return 0;
2194 }
2195
niklase@google.com470e71d2011-07-07 08:21:25 +00002196 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2197 {
2198 _engineStatisticsPtr->SetLastError(
2199 VE_STOP_RECORDING_FAILED, kTraceError,
2200 "StopPlayingFile() could not stop playing");
2201 return -1;
2202 }
2203 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2204 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2205 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002206 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002207
2208 return 0;
2209}
2210
2211int Channel::IsPlayingFileAsMicrophone() const
2212{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002213 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002214}
2215
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002216int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002217 const CodecInst* codecInst)
2218{
2219 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2220 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2221
2222 if (_outputFileRecording)
2223 {
2224 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2225 "StartRecordingPlayout() is already recording");
2226 return 0;
2227 }
2228
2229 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002230 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002231 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2232
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002233 if ((codecInst != NULL) &&
2234 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002235 {
2236 _engineStatisticsPtr->SetLastError(
2237 VE_BAD_ARGUMENT, kTraceError,
2238 "StartRecordingPlayout() invalid compression");
2239 return(-1);
2240 }
2241 if(codecInst == NULL)
2242 {
2243 format = kFileFormatPcm16kHzFile;
2244 codecInst=&dummyCodec;
2245 }
2246 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2247 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2248 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2249 {
2250 format = kFileFormatWavFile;
2251 }
2252 else
2253 {
2254 format = kFileFormatCompressedFile;
2255 }
2256
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002257 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002258
2259 // Destroy the old instance
2260 if (_outputFileRecorderPtr)
2261 {
2262 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2263 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2264 _outputFileRecorderPtr = NULL;
2265 }
2266
2267 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2268 _outputFileRecorderId, (const FileFormats)format);
2269 if (_outputFileRecorderPtr == NULL)
2270 {
2271 _engineStatisticsPtr->SetLastError(
2272 VE_INVALID_ARGUMENT, kTraceError,
2273 "StartRecordingPlayout() fileRecorder format isnot correct");
2274 return -1;
2275 }
2276
2277 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2278 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2279 {
2280 _engineStatisticsPtr->SetLastError(
2281 VE_BAD_FILE, kTraceError,
2282 "StartRecordingAudioFile() failed to start file recording");
2283 _outputFileRecorderPtr->StopRecording();
2284 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2285 _outputFileRecorderPtr = NULL;
2286 return -1;
2287 }
2288 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2289 _outputFileRecording = true;
2290
2291 return 0;
2292}
2293
2294int Channel::StartRecordingPlayout(OutStream* stream,
2295 const CodecInst* codecInst)
2296{
2297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2298 "Channel::StartRecordingPlayout()");
2299
2300 if (_outputFileRecording)
2301 {
2302 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2303 "StartRecordingPlayout() is already recording");
2304 return 0;
2305 }
2306
2307 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002308 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002309 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2310
2311 if (codecInst != NULL && codecInst->channels != 1)
2312 {
2313 _engineStatisticsPtr->SetLastError(
2314 VE_BAD_ARGUMENT, kTraceError,
2315 "StartRecordingPlayout() invalid compression");
2316 return(-1);
2317 }
2318 if(codecInst == NULL)
2319 {
2320 format = kFileFormatPcm16kHzFile;
2321 codecInst=&dummyCodec;
2322 }
2323 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2324 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2325 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2326 {
2327 format = kFileFormatWavFile;
2328 }
2329 else
2330 {
2331 format = kFileFormatCompressedFile;
2332 }
2333
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002334 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002335
2336 // Destroy the old instance
2337 if (_outputFileRecorderPtr)
2338 {
2339 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2340 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2341 _outputFileRecorderPtr = NULL;
2342 }
2343
2344 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2345 _outputFileRecorderId, (const FileFormats)format);
2346 if (_outputFileRecorderPtr == NULL)
2347 {
2348 _engineStatisticsPtr->SetLastError(
2349 VE_INVALID_ARGUMENT, kTraceError,
2350 "StartRecordingPlayout() fileRecorder format isnot correct");
2351 return -1;
2352 }
2353
2354 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2355 notificationTime) != 0)
2356 {
2357 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2358 "StartRecordingPlayout() failed to "
2359 "start file recording");
2360 _outputFileRecorderPtr->StopRecording();
2361 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2362 _outputFileRecorderPtr = NULL;
2363 return -1;
2364 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002365
niklase@google.com470e71d2011-07-07 08:21:25 +00002366 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2367 _outputFileRecording = true;
2368
2369 return 0;
2370}
2371
2372int Channel::StopRecordingPlayout()
2373{
2374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2375 "Channel::StopRecordingPlayout()");
2376
2377 if (!_outputFileRecording)
2378 {
2379 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2380 "StopRecordingPlayout() isnot recording");
2381 return -1;
2382 }
2383
2384
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002385 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002386
2387 if (_outputFileRecorderPtr->StopRecording() != 0)
2388 {
2389 _engineStatisticsPtr->SetLastError(
2390 VE_STOP_RECORDING_FAILED, kTraceError,
2391 "StopRecording() could not stop recording");
2392 return(-1);
2393 }
2394 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2395 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2396 _outputFileRecorderPtr = NULL;
2397 _outputFileRecording = false;
2398
2399 return 0;
2400}
2401
2402void
2403Channel::SetMixWithMicStatus(bool mix)
2404{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002405 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002406 _mixFileWithMicrophone=mix;
2407}
2408
2409int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002410Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002411{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002412 int8_t currentLevel = _outputAudioLevel.Level();
2413 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002414 return 0;
2415}
2416
2417int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002418Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002419{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002420 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2421 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002422 return 0;
2423}
2424
2425int
2426Channel::SetMute(bool enable)
2427{
wu@webrtc.org63420662013-10-17 18:28:55 +00002428 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2430 "Channel::SetMute(enable=%d)", enable);
2431 _mute = enable;
2432 return 0;
2433}
2434
2435bool
2436Channel::Mute() const
2437{
wu@webrtc.org63420662013-10-17 18:28:55 +00002438 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002439 return _mute;
2440}
2441
2442int
2443Channel::SetOutputVolumePan(float left, float right)
2444{
wu@webrtc.org63420662013-10-17 18:28:55 +00002445 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2447 "Channel::SetOutputVolumePan()");
2448 _panLeft = left;
2449 _panRight = right;
2450 return 0;
2451}
2452
2453int
2454Channel::GetOutputVolumePan(float& left, float& right) 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 left = _panLeft;
2458 right = _panRight;
niklase@google.com470e71d2011-07-07 08:21:25 +00002459 return 0;
2460}
2461
2462int
2463Channel::SetChannelOutputVolumeScaling(float scaling)
2464{
wu@webrtc.org63420662013-10-17 18:28:55 +00002465 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002466 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2467 "Channel::SetChannelOutputVolumeScaling()");
2468 _outputGain = scaling;
2469 return 0;
2470}
2471
2472int
2473Channel::GetChannelOutputVolumeScaling(float& scaling) const
2474{
wu@webrtc.org63420662013-10-17 18:28:55 +00002475 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 scaling = _outputGain;
niklase@google.com470e71d2011-07-07 08:21:25 +00002477 return 0;
2478}
2479
niklase@google.com470e71d2011-07-07 08:21:25 +00002480int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002481 int lengthMs, int attenuationDb,
2482 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002483{
2484 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2485 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2486 playDtmfEvent);
Fredrik Solenbergb5727682015-12-04 15:22:19 +01002487 if (!Sending()) {
2488 return -1;
2489 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002490
2491 _playOutbandDtmfEvent = playDtmfEvent;
2492
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002493 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002494 attenuationDb) != 0)
2495 {
2496 _engineStatisticsPtr->SetLastError(
2497 VE_SEND_DTMF_FAILED,
2498 kTraceWarning,
2499 "SendTelephoneEventOutband() failed to send event");
2500 return -1;
2501 }
2502 return 0;
2503}
2504
2505int Channel::SendTelephoneEventInband(unsigned char eventCode,
2506 int lengthMs,
2507 int attenuationDb,
2508 bool playDtmfEvent)
2509{
2510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2511 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2512 playDtmfEvent);
2513
2514 _playInbandDtmfEvent = playDtmfEvent;
2515 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2516
2517 return 0;
2518}
2519
2520int
niklase@google.com470e71d2011-07-07 08:21:25 +00002521Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2522{
2523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2524 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002525 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002526 {
2527 _engineStatisticsPtr->SetLastError(
2528 VE_INVALID_ARGUMENT, kTraceError,
2529 "SetSendTelephoneEventPayloadType() invalid type");
2530 return -1;
2531 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002532 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002533 codec.plfreq = 8000;
2534 codec.pltype = type;
2535 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002536 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002537 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002538 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2539 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2540 _engineStatisticsPtr->SetLastError(
2541 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2542 "SetSendTelephoneEventPayloadType() failed to register send"
2543 "payload type");
2544 return -1;
2545 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002546 }
2547 _sendTelephoneEventPayloadType = type;
2548 return 0;
2549}
2550
2551int
2552Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2553{
niklase@google.com470e71d2011-07-07 08:21:25 +00002554 type = _sendTelephoneEventPayloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002555 return 0;
2556}
2557
niklase@google.com470e71d2011-07-07 08:21:25 +00002558int
2559Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2560{
2561 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2562 "Channel::UpdateRxVadDetection()");
2563
2564 int vadDecision = 1;
2565
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002566 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002567
2568 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2569 {
2570 OnRxVadDetected(vadDecision);
2571 _oldVadDecision = vadDecision;
2572 }
2573
2574 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2575 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2576 vadDecision);
2577 return 0;
2578}
2579
2580int
2581Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2582{
2583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2584 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002585 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002586
2587 if (_rxVadObserverPtr)
2588 {
2589 _engineStatisticsPtr->SetLastError(
2590 VE_INVALID_OPERATION, kTraceError,
2591 "RegisterRxVadObserver() observer already enabled");
2592 return -1;
2593 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002594 _rxVadObserverPtr = &observer;
2595 _RxVadDetection = true;
2596 return 0;
2597}
2598
2599int
2600Channel::DeRegisterRxVadObserver()
2601{
2602 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2603 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002604 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002605
2606 if (!_rxVadObserverPtr)
2607 {
2608 _engineStatisticsPtr->SetLastError(
2609 VE_INVALID_OPERATION, kTraceWarning,
2610 "DeRegisterRxVadObserver() observer already disabled");
2611 return 0;
2612 }
2613 _rxVadObserverPtr = NULL;
2614 _RxVadDetection = false;
2615 return 0;
2616}
2617
2618int
2619Channel::VoiceActivityIndicator(int &activity)
2620{
2621 activity = _sendFrameType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002622 return 0;
2623}
2624
2625#ifdef WEBRTC_VOICE_ENGINE_AGC
2626
2627int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002628Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002629{
2630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2631 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2632 (int)enable, (int)mode);
2633
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002634 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002635 switch (mode)
2636 {
2637 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002638 break;
2639 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002640 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002641 break;
2642 case kAgcFixedDigital:
2643 agcMode = GainControl::kFixedDigital;
2644 break;
2645 case kAgcAdaptiveDigital:
2646 agcMode =GainControl::kAdaptiveDigital;
2647 break;
2648 default:
2649 _engineStatisticsPtr->SetLastError(
2650 VE_INVALID_ARGUMENT, kTraceError,
2651 "SetRxAgcStatus() invalid Agc mode");
2652 return -1;
2653 }
2654
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002655 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002656 {
2657 _engineStatisticsPtr->SetLastError(
2658 VE_APM_ERROR, kTraceError,
2659 "SetRxAgcStatus() failed to set Agc mode");
2660 return -1;
2661 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002662 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002663 {
2664 _engineStatisticsPtr->SetLastError(
2665 VE_APM_ERROR, kTraceError,
2666 "SetRxAgcStatus() failed to set Agc state");
2667 return -1;
2668 }
2669
2670 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002671 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002672
2673 return 0;
2674}
2675
2676int
2677Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2678{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002679 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002681 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002682
2683 enabled = enable;
2684
2685 switch (agcMode)
2686 {
2687 case GainControl::kFixedDigital:
2688 mode = kAgcFixedDigital;
2689 break;
2690 case GainControl::kAdaptiveDigital:
2691 mode = kAgcAdaptiveDigital;
2692 break;
2693 default:
2694 _engineStatisticsPtr->SetLastError(
2695 VE_APM_ERROR, kTraceError,
2696 "GetRxAgcStatus() invalid Agc mode");
2697 return -1;
2698 }
2699
2700 return 0;
2701}
2702
2703int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002704Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002705{
2706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2707 "Channel::SetRxAgcConfig()");
2708
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002709 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002710 config.targetLeveldBOv) != 0)
2711 {
2712 _engineStatisticsPtr->SetLastError(
2713 VE_APM_ERROR, kTraceError,
2714 "SetRxAgcConfig() failed to set target peak |level|"
2715 "(or envelope) of the Agc");
2716 return -1;
2717 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002718 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002719 config.digitalCompressionGaindB) != 0)
2720 {
2721 _engineStatisticsPtr->SetLastError(
2722 VE_APM_ERROR, kTraceError,
2723 "SetRxAgcConfig() failed to set the range in |gain| the"
2724 " digital compression stage may apply");
2725 return -1;
2726 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002727 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 config.limiterEnable) != 0)
2729 {
2730 _engineStatisticsPtr->SetLastError(
2731 VE_APM_ERROR, kTraceError,
2732 "SetRxAgcConfig() failed to set hard limiter to the signal");
2733 return -1;
2734 }
2735
2736 return 0;
2737}
2738
2739int
2740Channel::GetRxAgcConfig(AgcConfig& config)
2741{
niklase@google.com470e71d2011-07-07 08:21:25 +00002742 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002743 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002744 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002745 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002746 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002747 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002748
niklase@google.com470e71d2011-07-07 08:21:25 +00002749 return 0;
2750}
2751
2752#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2753
2754#ifdef WEBRTC_VOICE_ENGINE_NR
2755
2756int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002757Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002758{
2759 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2760 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2761 (int)enable, (int)mode);
2762
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002763 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 switch (mode)
2765 {
2766
2767 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002768 break;
2769 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002770 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002771 break;
2772 case kNsConference:
2773 nsLevel = NoiseSuppression::kHigh;
2774 break;
2775 case kNsLowSuppression:
2776 nsLevel = NoiseSuppression::kLow;
2777 break;
2778 case kNsModerateSuppression:
2779 nsLevel = NoiseSuppression::kModerate;
2780 break;
2781 case kNsHighSuppression:
2782 nsLevel = NoiseSuppression::kHigh;
2783 break;
2784 case kNsVeryHighSuppression:
2785 nsLevel = NoiseSuppression::kVeryHigh;
2786 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002787 }
2788
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002789 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002790 != 0)
2791 {
2792 _engineStatisticsPtr->SetLastError(
2793 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002794 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002795 return -1;
2796 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002797 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002798 {
2799 _engineStatisticsPtr->SetLastError(
2800 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002801 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 return -1;
2803 }
2804
2805 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002806 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002807
2808 return 0;
2809}
2810
2811int
2812Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2813{
niklase@google.com470e71d2011-07-07 08:21:25 +00002814 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002815 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002816 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002817 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002818
2819 enabled = enable;
2820
2821 switch (ncLevel)
2822 {
2823 case NoiseSuppression::kLow:
2824 mode = kNsLowSuppression;
2825 break;
2826 case NoiseSuppression::kModerate:
2827 mode = kNsModerateSuppression;
2828 break;
2829 case NoiseSuppression::kHigh:
2830 mode = kNsHighSuppression;
2831 break;
2832 case NoiseSuppression::kVeryHigh:
2833 mode = kNsVeryHighSuppression;
2834 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002835 }
2836
niklase@google.com470e71d2011-07-07 08:21:25 +00002837 return 0;
2838}
2839
2840#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2841
2842int
niklase@google.com470e71d2011-07-07 08:21:25 +00002843Channel::SetLocalSSRC(unsigned int ssrc)
2844{
2845 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2846 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002847 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002848 {
2849 _engineStatisticsPtr->SetLastError(
2850 VE_ALREADY_SENDING, kTraceError,
2851 "SetLocalSSRC() already sending");
2852 return -1;
2853 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002854 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002855 return 0;
2856}
2857
2858int
2859Channel::GetLocalSSRC(unsigned int& ssrc)
2860{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002861 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002862 return 0;
2863}
2864
2865int
2866Channel::GetRemoteSSRC(unsigned int& ssrc)
2867{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002868 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002869 return 0;
2870}
2871
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002872int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002873 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002874 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002875}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002876
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002877int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2878 unsigned char id) {
2879 rtp_header_parser_->DeregisterRtpHeaderExtension(
2880 kRtpExtensionAudioLevel);
2881 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2882 kRtpExtensionAudioLevel, id)) {
2883 return -1;
2884 }
2885 return 0;
2886}
2887
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002888int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2889 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2890}
2891
2892int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2893 rtp_header_parser_->DeregisterRtpHeaderExtension(
2894 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002895 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2896 kRtpExtensionAbsoluteSendTime, id)) {
2897 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002898 }
2899 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002900}
2901
Stefan Holmerb86d4e42015-12-07 10:26:18 +01002902void Channel::EnableSendTransportSequenceNumber(int id) {
2903 int ret =
2904 SetSendRtpHeaderExtension(true, kRtpExtensionTransportSequenceNumber, id);
2905 RTC_DCHECK_EQ(0, ret);
2906}
2907
2908void Channel::SetCongestionControlObjects(
2909 RtpPacketSender* rtp_packet_sender,
2910 TransportFeedbackObserver* transport_feedback_observer,
2911 PacketRouter* packet_router) {
2912 RTC_DCHECK(feedback_observer_proxy_.get());
2913 RTC_DCHECK(seq_num_allocator_proxy_.get());
2914 RTC_DCHECK(rtp_packet_sender_proxy_.get());
2915 RTC_DCHECK(packet_router != nullptr || packet_router_ != nullptr);
2916 feedback_observer_proxy_->SetTransportFeedbackObserver(
2917 transport_feedback_observer);
2918 seq_num_allocator_proxy_->SetSequenceNumberAllocator(packet_router);
2919 rtp_packet_sender_proxy_->SetPacketSender(rtp_packet_sender);
2920 _rtpRtcpModule->SetStorePacketsStatus(rtp_packet_sender != nullptr, 600);
2921 if (packet_router != nullptr) {
2922 packet_router->AddRtpModule(_rtpRtcpModule.get());
2923 } else {
2924 packet_router_->RemoveRtpModule(_rtpRtcpModule.get());
2925 }
2926 packet_router_ = packet_router;
2927}
2928
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002929void Channel::SetRTCPStatus(bool enable) {
2930 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2931 "Channel::SetRTCPStatus()");
pbosda903ea2015-10-02 02:36:56 -07002932 _rtpRtcpModule->SetRTCPStatus(enable ? RtcpMode::kCompound : RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002933}
2934
2935int
2936Channel::GetRTCPStatus(bool& enabled)
2937{
pbosda903ea2015-10-02 02:36:56 -07002938 RtcpMode method = _rtpRtcpModule->RTCP();
2939 enabled = (method != RtcpMode::kOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002940 return 0;
2941}
2942
2943int
2944Channel::SetRTCP_CNAME(const char cName[256])
2945{
2946 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2947 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002948 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002949 {
2950 _engineStatisticsPtr->SetLastError(
2951 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2952 "SetRTCP_CNAME() failed to set RTCP CNAME");
2953 return -1;
2954 }
2955 return 0;
2956}
2957
2958int
niklase@google.com470e71d2011-07-07 08:21:25 +00002959Channel::GetRemoteRTCP_CNAME(char cName[256])
2960{
2961 if (cName == NULL)
2962 {
2963 _engineStatisticsPtr->SetLastError(
2964 VE_INVALID_ARGUMENT, kTraceError,
2965 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2966 return -1;
2967 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002968 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002969 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002970 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002971 {
2972 _engineStatisticsPtr->SetLastError(
2973 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2974 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2975 return -1;
2976 }
2977 strcpy(cName, cname);
niklase@google.com470e71d2011-07-07 08:21:25 +00002978 return 0;
2979}
2980
2981int
2982Channel::GetRemoteRTCPData(
2983 unsigned int& NTPHigh,
2984 unsigned int& NTPLow,
2985 unsigned int& timestamp,
2986 unsigned int& playoutTimestamp,
2987 unsigned int* jitter,
2988 unsigned short* fractionLost)
2989{
2990 // --- Information from sender info in received Sender Reports
2991
2992 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002993 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002994 {
2995 _engineStatisticsPtr->SetLastError(
2996 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002997 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002998 "side");
2999 return -1;
3000 }
3001
3002 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3003 // and octet count)
3004 NTPHigh = senderInfo.NTPseconds;
3005 NTPLow = senderInfo.NTPfraction;
3006 timestamp = senderInfo.RTPtimeStamp;
3007
niklase@google.com470e71d2011-07-07 08:21:25 +00003008 // --- Locally derived information
3009
3010 // This value is updated on each incoming RTCP packet (0 when no packet
3011 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003012 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003013
niklase@google.com470e71d2011-07-07 08:21:25 +00003014 if (NULL != jitter || NULL != fractionLost)
3015 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003016 // Get all RTCP receiver report blocks that have been received on this
3017 // channel. If we receive RTP packets from a remote source we know the
3018 // remote SSRC and use the report block from him.
3019 // Otherwise use the first report block.
3020 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003021 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003022 remote_stats.empty()) {
3023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3024 VoEId(_instanceId, _channelId),
3025 "GetRemoteRTCPData() failed to measure statistics due"
3026 " to lack of received RTP and/or RTCP packets");
3027 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003028 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003029
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003030 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003031 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3032 for (; it != remote_stats.end(); ++it) {
3033 if (it->remoteSSRC == remoteSSRC)
3034 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003035 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003036
3037 if (it == remote_stats.end()) {
3038 // If we have not received any RTCP packets from this SSRC it probably
3039 // means that we have not received any RTP packets.
3040 // Use the first received report block instead.
3041 it = remote_stats.begin();
3042 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003043 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003044
xians@webrtc.org79af7342012-01-31 12:22:14 +00003045 if (jitter) {
3046 *jitter = it->jitter;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003047 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003048
xians@webrtc.org79af7342012-01-31 12:22:14 +00003049 if (fractionLost) {
3050 *fractionLost = it->fractionLost;
xians@webrtc.org79af7342012-01-31 12:22:14 +00003051 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003052 }
3053 return 0;
3054}
3055
3056int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003057Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003058 unsigned int name,
3059 const char* data,
3060 unsigned short dataLengthInBytes)
3061{
3062 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3063 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003064 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003065 {
3066 _engineStatisticsPtr->SetLastError(
3067 VE_NOT_SENDING, kTraceError,
3068 "SendApplicationDefinedRTCPPacket() not sending");
3069 return -1;
3070 }
3071 if (NULL == data)
3072 {
3073 _engineStatisticsPtr->SetLastError(
3074 VE_INVALID_ARGUMENT, kTraceError,
3075 "SendApplicationDefinedRTCPPacket() invalid data value");
3076 return -1;
3077 }
3078 if (dataLengthInBytes % 4 != 0)
3079 {
3080 _engineStatisticsPtr->SetLastError(
3081 VE_INVALID_ARGUMENT, kTraceError,
3082 "SendApplicationDefinedRTCPPacket() invalid length value");
3083 return -1;
3084 }
pbosda903ea2015-10-02 02:36:56 -07003085 RtcpMode status = _rtpRtcpModule->RTCP();
3086 if (status == RtcpMode::kOff) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003087 _engineStatisticsPtr->SetLastError(
3088 VE_RTCP_ERROR, kTraceError,
3089 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3090 return -1;
3091 }
3092
3093 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003094 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003095 subType,
3096 name,
3097 (const unsigned char*) data,
3098 dataLengthInBytes) != 0)
3099 {
3100 _engineStatisticsPtr->SetLastError(
3101 VE_SEND_ERROR, kTraceError,
3102 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3103 return -1;
3104 }
3105 return 0;
3106}
3107
3108int
3109Channel::GetRTPStatistics(
3110 unsigned int& averageJitterMs,
3111 unsigned int& maxJitterMs,
3112 unsigned int& discardedPackets)
3113{
niklase@google.com470e71d2011-07-07 08:21:25 +00003114 // The jitter statistics is updated for each received RTP packet and is
3115 // based on received packets.
pbosda903ea2015-10-02 02:36:56 -07003116 if (_rtpRtcpModule->RTCP() == RtcpMode::kOff) {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003117 // If RTCP is off, there is no timed thread in the RTCP module regularly
3118 // generating new stats, trigger the update manually here instead.
3119 StreamStatistician* statistician =
3120 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3121 if (statistician) {
3122 // Don't use returned statistics, use data from proxy instead so that
3123 // max jitter can be fetched atomically.
3124 RtcpStatistics s;
3125 statistician->GetStatistics(&s, true);
3126 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 }
3128
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003129 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003130 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003131 if (playoutFrequency > 0) {
3132 // Scale RTP statistics given the current playout frequency
3133 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3134 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003135 }
3136
3137 discardedPackets = _numberOfDiscardedPackets;
3138
niklase@google.com470e71d2011-07-07 08:21:25 +00003139 return 0;
3140}
3141
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003142int Channel::GetRemoteRTCPReportBlocks(
3143 std::vector<ReportBlock>* report_blocks) {
3144 if (report_blocks == NULL) {
3145 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3146 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3147 return -1;
3148 }
3149
3150 // Get the report blocks from the latest received RTCP Sender or Receiver
3151 // Report. Each element in the vector contains the sender's SSRC and a
3152 // report block according to RFC 3550.
3153 std::vector<RTCPReportBlock> rtcp_report_blocks;
3154 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003155 return -1;
3156 }
3157
3158 if (rtcp_report_blocks.empty())
3159 return 0;
3160
3161 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3162 for (; it != rtcp_report_blocks.end(); ++it) {
3163 ReportBlock report_block;
3164 report_block.sender_SSRC = it->remoteSSRC;
3165 report_block.source_SSRC = it->sourceSSRC;
3166 report_block.fraction_lost = it->fractionLost;
3167 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3168 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3169 report_block.interarrival_jitter = it->jitter;
3170 report_block.last_SR_timestamp = it->lastSR;
3171 report_block.delay_since_last_SR = it->delaySinceLastSR;
3172 report_blocks->push_back(report_block);
3173 }
3174 return 0;
3175}
3176
niklase@google.com470e71d2011-07-07 08:21:25 +00003177int
3178Channel::GetRTPStatistics(CallStatistics& stats)
3179{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003180 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003181
3182 // The jitter statistics is updated for each received RTP packet and is
3183 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003184 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003185 StreamStatistician* statistician =
3186 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
pbosda903ea2015-10-02 02:36:56 -07003187 if (!statistician ||
3188 !statistician->GetStatistics(
3189 &statistics, _rtpRtcpModule->RTCP() == RtcpMode::kOff)) {
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003190 _engineStatisticsPtr->SetLastError(
3191 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3192 "GetRTPStatistics() failed to read RTP statistics from the "
3193 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003194 }
3195
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003196 stats.fractionLost = statistics.fraction_lost;
3197 stats.cumulativeLost = statistics.cumulative_lost;
3198 stats.extendedMax = statistics.extended_max_sequence_number;
3199 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003200
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003201 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003202 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003203
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003204 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003205
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003206 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003207 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003208 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003209 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003210
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003211 if (statistician) {
3212 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3213 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003214
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003215 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003216 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003217 {
3218 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3219 VoEId(_instanceId, _channelId),
3220 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003221 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003222 }
3223
3224 stats.bytesSent = bytesSent;
3225 stats.packetsSent = packetsSent;
3226 stats.bytesReceived = bytesReceived;
3227 stats.packetsReceived = packetsReceived;
3228
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003229 // --- Timestamps
3230 {
3231 CriticalSectionScoped lock(ts_stats_lock_.get());
3232 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3233 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003234 return 0;
3235}
3236
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003237int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003238 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003239 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003240
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003241 if (enable) {
3242 if (redPayloadtype < 0 || redPayloadtype > 127) {
3243 _engineStatisticsPtr->SetLastError(
3244 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003245 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003246 return -1;
3247 }
3248
3249 if (SetRedPayloadType(redPayloadtype) < 0) {
3250 _engineStatisticsPtr->SetLastError(
3251 VE_CODEC_ERROR, kTraceError,
3252 "SetSecondarySendCodec() Failed to register RED ACM");
3253 return -1;
3254 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003255 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003256
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003257 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003258 _engineStatisticsPtr->SetLastError(
3259 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003260 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003261 return -1;
3262 }
3263 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003264}
3265
3266int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003267Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003268{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003269 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 if (enabled)
3271 {
danilchap5c1def82015-12-10 09:51:54 -08003272 int8_t payloadType = 0;
3273 if (_rtpRtcpModule->SendREDPayloadType(&payloadType) != 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003274 _engineStatisticsPtr->SetLastError(
3275 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003276 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 "module");
3278 return -1;
3279 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003280 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 return 0;
3282 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003283 return 0;
3284}
3285
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003286int Channel::SetCodecFECStatus(bool enable) {
3287 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3288 "Channel::SetCodecFECStatus()");
3289
3290 if (audio_coding_->SetCodecFEC(enable) != 0) {
3291 _engineStatisticsPtr->SetLastError(
3292 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3293 "SetCodecFECStatus() failed to set FEC state");
3294 return -1;
3295 }
3296 return 0;
3297}
3298
3299bool Channel::GetCodecFECStatus() {
3300 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003301 return enabled;
3302}
3303
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003304void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3305 // None of these functions can fail.
Stefan Holmerb86d4e42015-12-07 10:26:18 +01003306 // If pacing is enabled we always store packets.
3307 if (!pacing_enabled_)
3308 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003309 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3310 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003311 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003312 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003313 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003314 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003315}
3316
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003317// Called when we are missing one or more packets.
3318int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003319 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3320}
3321
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003322uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003323Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003324{
3325 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003326 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003327 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003328 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003329 return 0;
3330}
3331
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003332void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003333 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003334 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003335 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003336 CodecInst codec;
3337 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003338
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07003339 // Never upsample or upmix the capture signal here. This should be done at the
3340 // end of the send chain.
3341 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3342 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3343 RemixAndResample(audio_data, number_of_frames, number_of_channels,
3344 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003345}
3346
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003347uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003348Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003349{
3350 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3351 "Channel::PrepareEncodeAndSend()");
3352
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003353 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003354 {
3355 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3356 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003357 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003358 }
3359
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003360 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003361 {
3362 MixOrReplaceAudioWithFile(mixingFrequency);
3363 }
3364
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003365 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3366 if (is_muted) {
3367 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003368 }
3369
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003370 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003371 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003372 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003373 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003374 if (_inputExternalMediaCallbackPtr)
3375 {
3376 _inputExternalMediaCallbackPtr->Process(
3377 _channelId,
3378 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003379 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003380 _audioFrame.samples_per_channel_,
3381 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003382 isStereo);
3383 }
3384 }
3385
3386 InsertInbandDtmfTone();
3387
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003388 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003389 size_t length =
3390 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003391 if (is_muted) {
3392 rms_level_.ProcessMuted(length);
3393 } else {
3394 rms_level_.Process(_audioFrame.data_, length);
3395 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003396 }
3397
niklase@google.com470e71d2011-07-07 08:21:25 +00003398 return 0;
3399}
3400
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003401uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003402Channel::EncodeAndSend()
3403{
3404 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3405 "Channel::EncodeAndSend()");
3406
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003407 assert(_audioFrame.num_channels_ <= 2);
3408 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003409 {
3410 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3411 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003412 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003413 }
3414
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003415 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003416
3417 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3418
3419 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003420 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003421 // This call will trigger AudioPacketizationCallback::SendData if encoding
3422 // is done and payload is ready for packetization and transmission.
3423 // Otherwise, it will return without invoking the callback.
3424 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003425 {
3426 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3427 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003428 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003429 }
3430
Peter Kastingb7e50542015-06-11 12:55:50 -07003431 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003432 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003433}
3434
Minyue2013aec2015-05-13 14:14:42 +02003435void Channel::DisassociateSendChannel(int channel_id) {
3436 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3437 Channel* channel = associate_send_channel_.channel();
3438 if (channel && channel->ChannelId() == channel_id) {
3439 // If this channel is associated with a send channel of the specified
3440 // Channel ID, disassociate with it.
3441 ChannelOwner ref(NULL);
3442 associate_send_channel_ = ref;
3443 }
3444}
3445
niklase@google.com470e71d2011-07-07 08:21:25 +00003446int Channel::RegisterExternalMediaProcessing(
3447 ProcessingTypes type,
3448 VoEMediaProcess& processObject)
3449{
3450 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3451 "Channel::RegisterExternalMediaProcessing()");
3452
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003453 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003454
3455 if (kPlaybackPerChannel == type)
3456 {
3457 if (_outputExternalMediaCallbackPtr)
3458 {
3459 _engineStatisticsPtr->SetLastError(
3460 VE_INVALID_OPERATION, kTraceError,
3461 "Channel::RegisterExternalMediaProcessing() "
3462 "output external media already enabled");
3463 return -1;
3464 }
3465 _outputExternalMediaCallbackPtr = &processObject;
3466 _outputExternalMedia = true;
3467 }
3468 else if (kRecordingPerChannel == type)
3469 {
3470 if (_inputExternalMediaCallbackPtr)
3471 {
3472 _engineStatisticsPtr->SetLastError(
3473 VE_INVALID_OPERATION, kTraceError,
3474 "Channel::RegisterExternalMediaProcessing() "
3475 "output external media already enabled");
3476 return -1;
3477 }
3478 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003479 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003480 }
3481 return 0;
3482}
3483
3484int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3485{
3486 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3487 "Channel::DeRegisterExternalMediaProcessing()");
3488
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003489 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003490
3491 if (kPlaybackPerChannel == type)
3492 {
3493 if (!_outputExternalMediaCallbackPtr)
3494 {
3495 _engineStatisticsPtr->SetLastError(
3496 VE_INVALID_OPERATION, kTraceWarning,
3497 "Channel::DeRegisterExternalMediaProcessing() "
3498 "output external media already disabled");
3499 return 0;
3500 }
3501 _outputExternalMedia = false;
3502 _outputExternalMediaCallbackPtr = NULL;
3503 }
3504 else if (kRecordingPerChannel == type)
3505 {
3506 if (!_inputExternalMediaCallbackPtr)
3507 {
3508 _engineStatisticsPtr->SetLastError(
3509 VE_INVALID_OPERATION, kTraceWarning,
3510 "Channel::DeRegisterExternalMediaProcessing() "
3511 "input external media already disabled");
3512 return 0;
3513 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003514 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003515 _inputExternalMediaCallbackPtr = NULL;
3516 }
3517
3518 return 0;
3519}
3520
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003521int Channel::SetExternalMixing(bool enabled) {
3522 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3523 "Channel::SetExternalMixing(enabled=%d)", enabled);
3524
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003525 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003526 {
3527 _engineStatisticsPtr->SetLastError(
3528 VE_INVALID_OPERATION, kTraceError,
3529 "Channel::SetExternalMixing() "
3530 "external mixing cannot be changed while playing.");
3531 return -1;
3532 }
3533
3534 _externalMixing = enabled;
3535
3536 return 0;
3537}
3538
niklase@google.com470e71d2011-07-07 08:21:25 +00003539int
niklase@google.com470e71d2011-07-07 08:21:25 +00003540Channel::GetNetworkStatistics(NetworkStatistics& stats)
3541{
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003542 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003543}
3544
wu@webrtc.org24301a62013-12-13 19:17:43 +00003545void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3546 audio_coding_->GetDecodingCallStatistics(stats);
3547}
3548
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003549bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3550 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003551 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003552 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003553 return false;
3554 }
3555 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3556 _recPacketDelayMs;
3557 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003558 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003559}
3560
solenberg358057b2015-11-27 10:46:42 -08003561uint32_t Channel::GetDelayEstimate() const {
3562 int jitter_buffer_delay_ms = 0;
3563 int playout_buffer_delay_ms = 0;
3564 GetDelayEstimate(&jitter_buffer_delay_ms, &playout_buffer_delay_ms);
3565 return jitter_buffer_delay_ms + playout_buffer_delay_ms;
3566}
3567
deadbeef74375882015-08-13 12:09:10 -07003568int Channel::LeastRequiredDelayMs() const {
3569 return audio_coding_->LeastRequiredDelayMs();
3570}
3571
niklase@google.com470e71d2011-07-07 08:21:25 +00003572int
3573Channel::SetMinimumPlayoutDelay(int delayMs)
3574{
3575 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3576 "Channel::SetMinimumPlayoutDelay()");
3577 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3578 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3579 {
3580 _engineStatisticsPtr->SetLastError(
3581 VE_INVALID_ARGUMENT, kTraceError,
3582 "SetMinimumPlayoutDelay() invalid min delay");
3583 return -1;
3584 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003585 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003586 {
3587 _engineStatisticsPtr->SetLastError(
3588 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3589 "SetMinimumPlayoutDelay() failed to set min playout delay");
3590 return -1;
3591 }
3592 return 0;
3593}
3594
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003595int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003596 uint32_t playout_timestamp_rtp = 0;
3597 {
3598 CriticalSectionScoped cs(video_sync_lock_.get());
3599 playout_timestamp_rtp = playout_timestamp_rtp_;
3600 }
3601 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003602 _engineStatisticsPtr->SetLastError(
3603 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3604 "GetPlayoutTimestamp() failed to retrieve timestamp");
3605 return -1;
3606 }
deadbeef74375882015-08-13 12:09:10 -07003607 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003608 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003609}
3610
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003611int Channel::SetInitTimestamp(unsigned int timestamp) {
3612 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003613 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003614 if (channel_state_.Get().sending) {
3615 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3616 "SetInitTimestamp() already sending");
3617 return -1;
3618 }
3619 _rtpRtcpModule->SetStartTimestamp(timestamp);
3620 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003621}
3622
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003623int Channel::SetInitSequenceNumber(short sequenceNumber) {
3624 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3625 "Channel::SetInitSequenceNumber()");
3626 if (channel_state_.Get().sending) {
3627 _engineStatisticsPtr->SetLastError(
3628 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3629 return -1;
3630 }
3631 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3632 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003633}
3634
3635int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003636Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003637{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003638 *rtpRtcpModule = _rtpRtcpModule.get();
3639 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003640 return 0;
3641}
3642
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003643// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3644// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003645int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003646Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003647{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003648 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003649 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003650
3651 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003652 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003653
3654 if (_inputFilePlayerPtr == NULL)
3655 {
3656 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3657 VoEId(_instanceId, _channelId),
3658 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3659 " doesnt exist");
3660 return -1;
3661 }
3662
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003663 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003664 fileSamples,
3665 mixingFrequency) == -1)
3666 {
3667 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3668 VoEId(_instanceId, _channelId),
3669 "Channel::MixOrReplaceAudioWithFile() file mixing "
3670 "failed");
3671 return -1;
3672 }
3673 if (fileSamples == 0)
3674 {
3675 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3676 VoEId(_instanceId, _channelId),
3677 "Channel::MixOrReplaceAudioWithFile() file is ended");
3678 return 0;
3679 }
3680 }
3681
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003682 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003683
3684 if (_mixFileWithMicrophone)
3685 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003686 // Currently file stream is always mono.
3687 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003688 MixWithSat(_audioFrame.data_,
3689 _audioFrame.num_channels_,
3690 fileBuffer.get(),
3691 1,
3692 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003693 }
3694 else
3695 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003696 // Replace ACM audio with file.
3697 // Currently file stream is always mono.
3698 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003699 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003700 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003701 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003702 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003703 mixingFrequency,
3704 AudioFrame::kNormalSpeech,
3705 AudioFrame::kVadUnknown,
3706 1);
3707
3708 }
3709 return 0;
3710}
3711
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003712int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003713Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003714 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003715{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003716 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003717
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003718 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003719 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003720
3721 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003722 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003723
3724 if (_outputFilePlayerPtr == NULL)
3725 {
3726 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3727 VoEId(_instanceId, _channelId),
3728 "Channel::MixAudioWithFile() file mixing failed");
3729 return -1;
3730 }
3731
3732 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003733 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003734 fileSamples,
3735 mixingFrequency) == -1)
3736 {
3737 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3738 VoEId(_instanceId, _channelId),
3739 "Channel::MixAudioWithFile() file mixing failed");
3740 return -1;
3741 }
3742 }
3743
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003744 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003746 // Currently file stream is always mono.
3747 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003748 MixWithSat(audioFrame.data_,
3749 audioFrame.num_channels_,
3750 fileBuffer.get(),
3751 1,
3752 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003753 }
3754 else
3755 {
3756 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003757 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3758 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003759 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003760 return -1;
3761 }
3762
3763 return 0;
3764}
3765
3766int
3767Channel::InsertInbandDtmfTone()
3768{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003769 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003770 if (_inbandDtmfQueue.PendingDtmf() &&
3771 !_inbandDtmfGenerator.IsAddingTone() &&
3772 _inbandDtmfGenerator.DelaySinceLastTone() >
3773 kMinTelephoneEventSeparationMs)
3774 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003775 int8_t eventCode(0);
3776 uint16_t lengthMs(0);
3777 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003778
3779 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3780 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3781 if (_playInbandDtmfEvent)
3782 {
3783 // Add tone to output mixer using a reduced length to minimize
3784 // risk of echo.
3785 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3786 attenuationDb);
3787 }
3788 }
3789
3790 if (_inbandDtmfGenerator.IsAddingTone())
3791 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003792 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003793 _inbandDtmfGenerator.GetSampleRate(frequency);
3794
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003795 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003796 {
3797 // Update sample rate of Dtmf tone since the mixing frequency
3798 // has changed.
3799 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003800 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003801 // Reset the tone to be added taking the new sample rate into
3802 // account.
3803 _inbandDtmfGenerator.ResetTone();
3804 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003805
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003806 int16_t toneBuffer[320];
3807 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003808 // Get 10ms tone segment and set time since last tone to zero
3809 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3810 {
3811 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3812 VoEId(_instanceId, _channelId),
3813 "Channel::EncodeAndSend() inserting Dtmf failed");
3814 return -1;
3815 }
3816
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003817 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003818 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003819 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003820 sample++)
3821 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003822 for (int channel = 0;
3823 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003824 channel++)
3825 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003826 const size_t index =
3827 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003828 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003829 }
3830 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003831
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003832 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003833 } else
3834 {
3835 // Add 10ms to "delay-since-last-tone" counter
3836 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3837 }
3838 return 0;
3839}
3840
deadbeef74375882015-08-13 12:09:10 -07003841void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3842 uint32_t playout_timestamp = 0;
3843
3844 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3845 // This can happen if this channel has not been received any RTP packet. In
3846 // this case, NetEq is not capable of computing playout timestamp.
3847 return;
3848 }
3849
3850 uint16_t delay_ms = 0;
3851 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3852 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3853 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3854 " delay from the ADM");
3855 _engineStatisticsPtr->SetLastError(
3856 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3857 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3858 return;
3859 }
3860
3861 jitter_buffer_playout_timestamp_ = playout_timestamp;
3862
3863 // Remove the playout delay.
3864 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3865
3866 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3867 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3868 playout_timestamp);
3869
3870 {
3871 CriticalSectionScoped cs(video_sync_lock_.get());
3872 if (rtcp) {
3873 playout_timestamp_rtcp_ = playout_timestamp;
3874 } else {
3875 playout_timestamp_rtp_ = playout_timestamp;
3876 }
3877 playout_delay_ms_ = delay_ms;
3878 }
3879}
3880
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003881// Called for incoming RTP packets after successful RTP header parsing.
3882void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3883 uint16_t sequence_number) {
3884 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3885 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3886 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003887
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003888 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003889 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003890
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003891 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3892 // every incoming packet.
3893 uint32_t timestamp_diff_ms = (rtp_timestamp -
3894 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003895 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3896 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3897 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3898 // timestamp, the resulting difference is negative, but is set to zero.
3899 // This can happen when a network glitch causes a packet to arrive late,
3900 // and during long comfort noise periods with clock drift.
3901 timestamp_diff_ms = 0;
3902 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003903
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003904 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3905 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003906
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003907 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003908
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003909 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003910
deadbeef74375882015-08-13 12:09:10 -07003911 {
3912 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003913
deadbeef74375882015-08-13 12:09:10 -07003914 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3915 _recPacketDelayMs = packet_delay_ms;
3916 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003917
deadbeef74375882015-08-13 12:09:10 -07003918 if (_average_jitter_buffer_delay_us == 0) {
3919 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3920 return;
3921 }
3922
3923 // Filter average delay value using exponential filter (alpha is
3924 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3925 // risk of rounding error) and compensate for it in GetDelayEstimate()
3926 // later.
3927 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3928 1000 * timestamp_diff_ms + 500) / 8;
3929 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003930}
3931
3932void
3933Channel::RegisterReceiveCodecsToRTPModule()
3934{
3935 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3936 "Channel::RegisterReceiveCodecsToRTPModule()");
3937
niklase@google.com470e71d2011-07-07 08:21:25 +00003938 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003939 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003940
3941 for (int idx = 0; idx < nSupportedCodecs; idx++)
3942 {
3943 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003944 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003945 (rtp_receiver_->RegisterReceivePayload(
3946 codec.plname,
3947 codec.pltype,
3948 codec.plfreq,
3949 codec.channels,
3950 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003951 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003952 WEBRTC_TRACE(kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00003953 kTraceVoice,
3954 VoEId(_instanceId, _channelId),
3955 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3956 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
3957 codec.plname, codec.pltype, codec.plfreq,
3958 codec.channels, codec.rate);
3959 }
3960 else
3961 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003962 WEBRTC_TRACE(kTraceInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +00003963 kTraceVoice,
3964 VoEId(_instanceId, _channelId),
3965 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003966 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003967 "receiver",
3968 codec.plname, codec.pltype, codec.plfreq,
3969 codec.channels, codec.rate);
3970 }
3971 }
3972}
3973
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003974// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003975int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003976 CodecInst codec;
3977 bool found_red = false;
3978
3979 // Get default RED settings from the ACM database
3980 const int num_codecs = AudioCodingModule::NumberOfCodecs();
3981 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003982 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003983 if (!STR_CASE_CMP(codec.plname, "RED")) {
3984 found_red = true;
3985 break;
3986 }
3987 }
3988
3989 if (!found_red) {
3990 _engineStatisticsPtr->SetLastError(
3991 VE_CODEC_ERROR, kTraceError,
3992 "SetRedPayloadType() RED is not supported");
3993 return -1;
3994 }
3995
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00003996 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003997 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003998 _engineStatisticsPtr->SetLastError(
3999 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4000 "SetRedPayloadType() RED registration in ACM module failed");
4001 return -1;
4002 }
4003
4004 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4005 _engineStatisticsPtr->SetLastError(
4006 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4007 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4008 return -1;
4009 }
4010 return 0;
4011}
4012
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004013int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4014 unsigned char id) {
4015 int error = 0;
4016 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4017 if (enable) {
4018 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4019 }
4020 return error;
4021}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004022
wu@webrtc.org94454b72014-06-05 20:34:08 +00004023int32_t Channel::GetPlayoutFrequency() {
4024 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4025 CodecInst current_recive_codec;
4026 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4027 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4028 // Even though the actual sampling rate for G.722 audio is
4029 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4030 // 8,000 Hz because that value was erroneously assigned in
4031 // RFC 1890 and must remain unchanged for backward compatibility.
4032 playout_frequency = 8000;
4033 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4034 // We are resampling Opus internally to 32,000 Hz until all our
4035 // DSP routines can operate at 48,000 Hz, but the RTP clock
4036 // rate for the Opus payload format is standardized to 48,000 Hz,
4037 // because that is the maximum supported decoding sampling rate.
4038 playout_frequency = 48000;
4039 }
4040 }
4041 return playout_frequency;
4042}
4043
Minyue2013aec2015-05-13 14:14:42 +02004044int64_t Channel::GetRTT(bool allow_associate_channel) const {
pbosda903ea2015-10-02 02:36:56 -07004045 RtcpMode method = _rtpRtcpModule->RTCP();
4046 if (method == RtcpMode::kOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004047 return 0;
4048 }
4049 std::vector<RTCPReportBlock> report_blocks;
4050 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004051
4052 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004053 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004054 if (allow_associate_channel) {
4055 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4056 Channel* channel = associate_send_channel_.channel();
4057 // Tries to get RTT from an associated channel. This is important for
4058 // receive-only channels.
4059 if (channel) {
4060 // To prevent infinite recursion and deadlock, calling GetRTT of
4061 // associate channel should always use "false" for argument:
4062 // |allow_associate_channel|.
4063 rtt = channel->GetRTT(false);
4064 }
4065 }
4066 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004067 }
4068
4069 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4070 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4071 for (; it != report_blocks.end(); ++it) {
4072 if (it->remoteSSRC == remoteSSRC)
4073 break;
4074 }
4075 if (it == report_blocks.end()) {
4076 // We have not received packets with SSRC matching the report blocks.
4077 // To calculate RTT we try with the SSRC of the first report block.
4078 // This is very important for send-only channels where we don't know
4079 // the SSRC of the other end.
4080 remoteSSRC = report_blocks[0].remoteSSRC;
4081 }
Minyue2013aec2015-05-13 14:14:42 +02004082
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004083 int64_t avg_rtt = 0;
4084 int64_t max_rtt= 0;
4085 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004086 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4087 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004088 return 0;
4089 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004090 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004091}
4092
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004093} // namespace voe
4094} // namespace webrtc