blob: fa44785344b222ed834710edce4df83151a6005a [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"
wu@webrtc.org94454b72014-06-05 20:34:08 +000017#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000018#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020019#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/audio_device/include/audio_device.h"
21#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000022#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000023#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
24#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
25#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
26#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000027#include "webrtc/modules/utility/interface/audio_frame_operations.h"
28#include "webrtc/modules/utility/interface/process_thread.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000029#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
30#include "webrtc/system_wrappers/interface/logging.h"
31#include "webrtc/system_wrappers/interface/trace.h"
32#include "webrtc/voice_engine/include/voe_base.h"
33#include "webrtc/voice_engine/include/voe_external_media.h"
34#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
35#include "webrtc/voice_engine/output_mixer.h"
36#include "webrtc/voice_engine/statistics.h"
37#include "webrtc/voice_engine/transmit_mixer.h"
38#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000039
40#if defined(_WIN32)
41#include <Qos.h>
42#endif
43
andrew@webrtc.org50419b02012-11-14 19:07:54 +000044namespace webrtc {
45namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000046
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000047// Extend the default RTCP statistics struct with max_jitter, defined as the
48// maximum jitter value seen in an RTCP report block.
49struct ChannelStatistics : public RtcpStatistics {
50 ChannelStatistics() : rtcp(), max_jitter(0) {}
51
52 RtcpStatistics rtcp;
53 uint32_t max_jitter;
54};
55
56// Statistics callback, called at each generation of a new RTCP report block.
57class StatisticsProxy : public RtcpStatisticsCallback {
58 public:
59 StatisticsProxy(uint32_t ssrc)
60 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
61 ssrc_(ssrc) {}
62 virtual ~StatisticsProxy() {}
63
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000064 void StatisticsUpdated(const RtcpStatistics& statistics,
65 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000066 if (ssrc != ssrc_)
67 return;
68
69 CriticalSectionScoped cs(stats_lock_.get());
70 stats_.rtcp = statistics;
71 if (statistics.jitter > stats_.max_jitter) {
72 stats_.max_jitter = statistics.jitter;
73 }
74 }
75
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000076 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +000077
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000078 ChannelStatistics GetStats() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 return stats_;
81 }
82
83 private:
84 // StatisticsUpdated calls are triggered from threads in the RTP module,
85 // while GetStats calls can be triggered from the public voice engine API,
86 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000087 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000088 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000092class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000093 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000094 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
95 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000096
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000097 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
98 // Not used for Voice Engine.
99 }
100
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000101 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
102 int64_t rtt,
103 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000104 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
105 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
106 // report for VoiceEngine?
107 if (report_blocks.empty())
108 return;
109
110 int fraction_lost_aggregate = 0;
111 int total_number_of_packets = 0;
112
113 // If receiving multiple report blocks, calculate the weighted average based
114 // on the number of packets a report refers to.
115 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
116 block_it != report_blocks.end(); ++block_it) {
117 // Find the previous extended high sequence number for this remote SSRC,
118 // to calculate the number of RTP packets this report refers to. Ignore if
119 // we haven't seen this SSRC before.
120 std::map<uint32_t, uint32_t>::iterator seq_num_it =
121 extended_max_sequence_number_.find(block_it->sourceSSRC);
122 int number_of_packets = 0;
123 if (seq_num_it != extended_max_sequence_number_.end()) {
124 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
125 }
126 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
127 total_number_of_packets += number_of_packets;
128
129 extended_max_sequence_number_[block_it->sourceSSRC] =
130 block_it->extendedHighSeqNum;
131 }
132 int weighted_fraction_lost = 0;
133 if (total_number_of_packets > 0) {
134 weighted_fraction_lost = (fraction_lost_aggregate +
135 total_number_of_packets / 2) / total_number_of_packets;
136 }
137 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000138 }
139
140 private:
141 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000142 // Maps remote side ssrc to extended highest sequence number received.
143 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000144};
145
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000146int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000147Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000148 uint8_t payloadType,
149 uint32_t timeStamp,
150 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000151 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 const RTPFragmentationHeader* fragmentation)
153{
154 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
155 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000156 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
157 frameType, payloadType, timeStamp,
158 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
160 if (_includeAudioLevelIndication)
161 {
162 // Store current audio level in the RTP/RTCP module.
163 // The level will be used in combination with voice-activity state
164 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000165 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 }
167
168 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
169 // packetization.
170 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000171 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 payloadType,
173 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000174 // Leaving the time when this frame was
175 // received from the capture device as
176 // undefined for voice for now.
177 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 payloadData,
179 payloadSize,
180 fragmentation) == -1)
181 {
182 _engineStatisticsPtr->SetLastError(
183 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
184 "Channel::SendData() failed to send data to RTP/RTCP module");
185 return -1;
186 }
187
188 _lastLocalTimeStamp = timeStamp;
189 _lastPayloadType = payloadType;
190
191 return 0;
192}
193
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000194int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000195Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000196{
197 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000198 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000200 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000201 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 return 0;
203}
204
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000205int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000206Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000207{
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000208 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 if (_rxVadObserverPtr)
210 {
211 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
212 }
213
214 return 0;
215}
216
217int
Peter Boströmac547a62015-09-17 23:03:57 +0200218Channel::SendPacket(const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000219{
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200221 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000222
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000223 CriticalSectionScoped cs(&_callbackCritSect);
224
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 if (_transportPtr == NULL)
226 {
227 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
228 "Channel::SendPacket() failed to send RTP packet due to"
229 " invalid transport object");
230 return -1;
231 }
232
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000233 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000234 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000235
Peter Boströmac547a62015-09-17 23:03:57 +0200236 int n = _transportPtr->SendPacket(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000237 if (n < 0) {
238 std::string transport_name =
239 _externalTransport ? "external transport" : "WebRtc sockets";
240 WEBRTC_TRACE(kTraceError, kTraceVoice,
241 VoEId(_instanceId,_channelId),
242 "Channel::SendPacket() RTP transmission using %s failed",
243 transport_name.c_str());
244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000246 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247}
248
249int
Peter Boströmac547a62015-09-17 23:03:57 +0200250Channel::SendRTCPPacket(const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000251{
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200253 "Channel::SendRTCPPacket(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000254
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000255 CriticalSectionScoped cs(&_callbackCritSect);
256 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 WEBRTC_TRACE(kTraceError, kTraceVoice,
259 VoEId(_instanceId,_channelId),
260 "Channel::SendRTCPPacket() failed to send RTCP packet"
261 " due to invalid transport object");
262 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000263 }
264
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000265 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000266 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000267
Peter Boströmac547a62015-09-17 23:03:57 +0200268 int n = _transportPtr->SendRTCPPacket(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000269 if (n < 0) {
270 std::string transport_name =
271 _externalTransport ? "external transport" : "WebRtc sockets";
272 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
273 VoEId(_instanceId,_channelId),
274 "Channel::SendRTCPPacket() transmission using %s failed",
275 transport_name.c_str());
276 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000277 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000278 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000279}
280
Peter Boströmac547a62015-09-17 23:03:57 +0200281void Channel::OnPlayTelephoneEvent(uint8_t event,
282 uint16_t lengthMs,
283 uint8_t volume) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200285 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
286 " volume=%u)", event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000287
288 if (!_playOutbandDtmfEvent || (event > 15))
289 {
290 // Ignore callback since feedback is disabled or event is not a
291 // Dtmf tone event.
292 return;
293 }
294
295 assert(_outputMixerPtr != NULL);
296
297 // Start playing out the Dtmf tone (if playout is enabled).
298 // Reduce length of tone with 80ms to the reduce risk of echo.
299 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
300}
301
302void
Peter Boströmac547a62015-09-17 23:03:57 +0200303Channel::OnIncomingSSRCChanged(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000304{
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200306 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000308 // Update ssrc so that NTP for AV sync can be updated.
309 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310}
311
Peter Boströmac547a62015-09-17 23:03:57 +0200312void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
313 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
314 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
315 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
Peter Boströmac547a62015-09-17 23:03:57 +0200318int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000319 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000320 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000321 int frequency,
322 uint8_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200323 uint32_t rate) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200325 "Channel::OnInitializeDecoder(payloadType=%d, "
niklase@google.com470e71d2011-07-07 08:21:25 +0000326 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
Peter Boströmac547a62015-09-17 23:03:57 +0200327 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000328
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000329 CodecInst receiveCodec = {0};
330 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000331
332 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333 receiveCodec.plfreq = frequency;
334 receiveCodec.channels = channels;
335 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000336 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000337
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000338 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 receiveCodec.pacsize = dummyCodec.pacsize;
340
341 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000342 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000343 {
344 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000345 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 "Channel::OnInitializeDecoder() invalid codec ("
347 "pt=%d, name=%s) received - 1", payloadType, payloadName);
348 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
349 return -1;
350 }
351
352 return 0;
353}
354
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000355int32_t
356Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000357 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 const WebRtcRTPHeader* rtpHeader)
359{
360 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000361 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000362 " payloadType=%u, audioChannel=%u)",
363 payloadSize,
364 rtpHeader->header.payloadType,
365 rtpHeader->type.Audio.channel);
366
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000367 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 {
369 // Avoid inserting into NetEQ when we are not playing. Count the
370 // packet as discarded.
371 WEBRTC_TRACE(kTraceStream, kTraceVoice,
372 VoEId(_instanceId, _channelId),
373 "received packet is discarded since playing is not"
374 " activated");
375 _numberOfDiscardedPackets++;
376 return 0;
377 }
378
379 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000380 if (audio_coding_->IncomingPacket(payloadData,
381 payloadSize,
382 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 {
384 _engineStatisticsPtr->SetLastError(
385 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
386 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
387 return -1;
388 }
389
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000390 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 UpdatePacketDelay(rtpHeader->header.timestamp,
392 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000393
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000394 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000395 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
396 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000397
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000398 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000399 round_trip_time);
400 if (!nack_list.empty()) {
401 // Can't use nack_list.data() since it's not supported by all
402 // compilers.
403 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000404 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 return 0;
406}
407
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000408bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000409 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000410 RTPHeader header;
411 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
412 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
413 "IncomingPacket invalid RTP header");
414 return false;
415 }
416 header.payload_type_frequency =
417 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
418 if (header.payload_type_frequency < 0)
419 return false;
420 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
421}
422
minyuel0f4b3732015-08-31 16:04:32 +0200423int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000424{
Ivo Creusenae856f22015-09-17 16:30:16 +0200425 if (event_log_) {
426 unsigned int ssrc;
427 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
428 event_log_->LogAudioPlayout(ssrc);
429 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200431 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
432 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 {
434 WEBRTC_TRACE(kTraceError, kTraceVoice,
435 VoEId(_instanceId,_channelId),
436 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000437 // In all likelihood, the audio in this frame is garbage. We return an
438 // error so that the audio mixer module doesn't add it to the mix. As
439 // a result, it won't be played out and the actions skipped here are
440 // irrelevant.
441 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 }
443
444 if (_RxVadDetection)
445 {
minyuel0f4b3732015-08-31 16:04:32 +0200446 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 }
448
449 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200450 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200452 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000454 ChannelState::State state = channel_state_.Get();
455
456 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200457 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000458 if (err) {
459 LOG(LS_ERROR) << "ProcessStream() error: " << err;
460 assert(false);
461 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000462 }
463
wu@webrtc.org63420662013-10-17 18:28:55 +0000464 float output_gain = 1.0f;
465 float left_pan = 1.0f;
466 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000468 CriticalSectionScoped cs(&volume_settings_critsect_);
469 output_gain = _outputGain;
470 left_pan = _panLeft;
471 right_pan= _panRight;
472 }
473
474 // Output volume scaling
475 if (output_gain < 0.99f || output_gain > 1.01f)
476 {
minyuel0f4b3732015-08-31 16:04:32 +0200477 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 }
479
480 // Scale left and/or right channel(s) if stereo and master balance is
481 // active
482
wu@webrtc.org63420662013-10-17 18:28:55 +0000483 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 {
minyuel0f4b3732015-08-31 16:04:32 +0200485 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 {
487 // Emulate stereo mode since panning is active.
488 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200489 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 }
491 // For true stereo mode (when we are receiving a stereo signal), no
492 // action is needed.
493
494 // Do the panning operation (the audio frame contains stereo at this
495 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200496 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 }
498
499 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000500 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 {
minyuel0f4b3732015-08-31 16:04:32 +0200502 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 }
504
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 // External media
506 if (_outputExternalMedia)
507 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000508 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200509 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000510 if (_outputExternalMediaCallbackPtr)
511 {
512 _outputExternalMediaCallbackPtr->Process(
513 _channelId,
514 kPlaybackPerChannel,
minyuel0f4b3732015-08-31 16:04:32 +0200515 (int16_t*)audioFrame->data_,
516 audioFrame->samples_per_channel_,
517 audioFrame->sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 isStereo);
519 }
520 }
521
522 // Record playout if enabled
523 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000524 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000525
526 if (_outputFileRecording && _outputFileRecorderPtr)
527 {
minyuel0f4b3732015-08-31 16:04:32 +0200528 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000529 }
530 }
531
532 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200533 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534
minyuel0f4b3732015-08-31 16:04:32 +0200535 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000536 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200537 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000538 }
539
540 if (capture_start_rtp_time_stamp_ >= 0) {
541 // audioFrame.timestamp_ should be valid from now on.
542
543 // Compute elapsed time.
544 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200545 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
546 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000547 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
548 (GetPlayoutFrequency() / 1000);
549
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000550 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000551 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000552 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200553 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
554 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000555 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200556 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000557 // Compute |capture_start_ntp_time_ms_| so that
558 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
559 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200560 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000561 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000562 }
563 }
564
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 return 0;
566}
567
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000568int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200569Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000570{
571 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
572 "Channel::NeededFrequency(id=%d)", id);
573
574 int highestNeeded = 0;
575
576 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000577 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000578
579 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000580 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000581 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000582 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }
584 else
585 {
586 highestNeeded = receiveFrequency;
587 }
588
589 // Special case, if we're playing a file on the playout side
590 // we take that frequency into consideration as well
591 // This is not needed on sending side, since the codec will
592 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000593 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000595 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000596 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 {
598 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
599 {
600 highestNeeded=_outputFilePlayerPtr->Frequency();
601 }
602 }
603 }
604
605 return(highestNeeded);
606}
607
ivocb04965c2015-09-09 00:09:43 -0700608int32_t Channel::CreateChannel(Channel*& channel,
609 int32_t channelId,
610 uint32_t instanceId,
611 RtcEventLog* const event_log,
612 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
614 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
615 channelId, instanceId);
616
ivocb04965c2015-09-09 00:09:43 -0700617 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 if (channel == NULL)
619 {
620 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
621 VoEId(instanceId,channelId),
622 "Channel::CreateChannel() unable to allocate memory for"
623 " channel");
624 return -1;
625 }
626 return 0;
627}
628
629void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000630Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631{
632 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
633 "Channel::PlayNotification(id=%d, durationMs=%d)",
634 id, durationMs);
635
636 // Not implement yet
637}
638
639void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000640Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000641{
642 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
643 "Channel::RecordNotification(id=%d, durationMs=%d)",
644 id, durationMs);
645
646 // Not implement yet
647}
648
649void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000650Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000651{
652 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
653 "Channel::PlayFileEnded(id=%d)", id);
654
655 if (id == _inputFilePlayerId)
656 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000657 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
659 VoEId(_instanceId,_channelId),
660 "Channel::PlayFileEnded() => input file player module is"
661 " shutdown");
662 }
663 else if (id == _outputFilePlayerId)
664 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000665 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
667 VoEId(_instanceId,_channelId),
668 "Channel::PlayFileEnded() => output file player module is"
669 " shutdown");
670 }
671}
672
673void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000674Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000675{
676 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
677 "Channel::RecordFileEnded(id=%d)", id);
678
679 assert(id == _outputFileRecorderId);
680
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000681 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000682
683 _outputFileRecording = false;
684 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
685 VoEId(_instanceId,_channelId),
686 "Channel::RecordFileEnded() => output file recorder module is"
687 " shutdown");
688}
689
pbos@webrtc.org92135212013-05-14 08:31:39 +0000690Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000691 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700692 RtcEventLog* const event_log,
693 const Config& config)
694 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000696 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000697 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000698 _channelId(channelId),
Ivo Creusenae856f22015-09-17 16:30:16 +0200699 event_log_(event_log),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000700 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000701 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000702 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
ivocb04965c2015-09-09 00:09:43 -0700703 rtp_receive_statistics_(
704 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
705 rtp_receiver_(
Peter Boströmac547a62015-09-17 23:03:57 +0200706 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
ivocb04965c2015-09-09 00:09:43 -0700707 this,
708 this,
709 this,
710 rtp_payload_registry_.get())),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000711 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000712 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000713 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 _inputFilePlayerPtr(NULL),
715 _outputFilePlayerPtr(NULL),
716 _outputFileRecorderPtr(NULL),
717 // Avoid conflict with other channels by adding 1024 - 1026,
718 // won't use as much as 1024 channels.
719 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
720 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
721 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000723 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
724 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000725 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 _inputExternalMediaCallbackPtr(NULL),
727 _outputExternalMediaCallbackPtr(NULL),
ivocb04965c2015-09-09 00:09:43 -0700728 _timeStamp(0), // This is just an offset, RTP module will add it's own
729 // random offset
xians@google.com22963ab2011-08-03 12:40:23 +0000730 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000731 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000732 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000733 playout_timestamp_rtp_(0),
734 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000735 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000736 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000737 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000738 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000739 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
740 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000741 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000742 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000743 _outputMixerPtr(NULL),
744 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000745 _moduleProcessThreadPtr(NULL),
746 _audioDeviceModulePtr(NULL),
747 _voiceEngineObserverPtr(NULL),
748 _callbackCritSectPtr(NULL),
749 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000750 _rxVadObserverPtr(NULL),
751 _oldVadDecision(-1),
752 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000753 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000754 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000755 _mute(false),
756 _panLeft(1.0f),
757 _panRight(1.0f),
758 _outputGain(1.0f),
759 _playOutbandDtmfEvent(false),
760 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 _lastLocalTimeStamp(0),
762 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000763 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000764 _outputSpeechType(AudioFrame::kNormalSpeech),
deadbeef74375882015-08-13 12:09:10 -0700765 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000766 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 _previousTimestamp(0),
768 _recPacketDelayMs(20),
769 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000771 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000772 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000773 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200774 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
775 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
ivocb04965c2015-09-09 00:09:43 -0700776 associate_send_channel_(ChannelOwner(nullptr)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000777 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
778 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200779 AudioCodingModule::Config acm_config;
780 acm_config.id = VoEModuleId(instanceId, channelId);
781 if (config.Get<NetEqCapacityConfig>().enabled) {
782 // Clamping the buffer capacity at 20 packets. While going lower will
783 // probably work, it makes little sense.
784 acm_config.neteq_config.max_packets_in_buffer =
785 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
786 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200787 acm_config.neteq_config.enable_fast_accelerate =
788 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200789 audio_coding_.reset(AudioCodingModule::Create(acm_config));
790
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 _inbandDtmfQueue.ResetDtmf();
792 _inbandDtmfGenerator.Init();
793 _outputAudioLevel.Clear();
794
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000795 RtpRtcp::Configuration configuration;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000796 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000797 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000798 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000799 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000800 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000801
802 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000803
804 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
805 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
806 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000807
808 Config audioproc_config;
809 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
810 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000811}
812
813Channel::~Channel()
814{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000815 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
817 "Channel::~Channel() - dtor");
818
819 if (_outputExternalMedia)
820 {
821 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
822 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000823 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000824 {
825 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
826 }
827 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000828 StopPlayout();
829
830 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000831 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000832 if (_inputFilePlayerPtr)
833 {
834 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
835 _inputFilePlayerPtr->StopPlayingFile();
836 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
837 _inputFilePlayerPtr = NULL;
838 }
839 if (_outputFilePlayerPtr)
840 {
841 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
842 _outputFilePlayerPtr->StopPlayingFile();
843 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
844 _outputFilePlayerPtr = NULL;
845 }
846 if (_outputFileRecorderPtr)
847 {
848 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
849 _outputFileRecorderPtr->StopRecording();
850 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
851 _outputFileRecorderPtr = NULL;
852 }
853 }
854
855 // The order to safely shutdown modules in a channel is:
856 // 1. De-register callbacks in modules
857 // 2. De-register modules in process thread
858 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000859 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000860 {
861 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
862 VoEId(_instanceId,_channelId),
863 "~Channel() failed to de-register transport callback"
864 " (Audio coding module)");
865 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000866 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 {
868 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
869 VoEId(_instanceId,_channelId),
870 "~Channel() failed to de-register VAD callback"
871 " (Audio coding module)");
872 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000874 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
875
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 // End of modules shutdown
877
878 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000880 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000881 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000882}
883
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000884int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000885Channel::Init()
886{
887 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
888 "Channel::Init()");
889
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000890 channel_state_.Reset();
891
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 // --- Initial sanity
893
894 if ((_engineStatisticsPtr == NULL) ||
895 (_moduleProcessThreadPtr == NULL))
896 {
897 WEBRTC_TRACE(kTraceError, kTraceVoice,
898 VoEId(_instanceId,_channelId),
899 "Channel::Init() must call SetEngineInformation() first");
900 return -1;
901 }
902
903 // --- Add modules to process thread (for periodic schedulation)
904
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000905 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
906
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000907 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000908
henrik.lundin061b79a2015-09-18 01:29:11 -0700909 if (audio_coding_->InitializeReceiver() == -1) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 _engineStatisticsPtr->SetLastError(
911 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
912 "Channel::Init() unable to initialize the ACM - 1");
913 return -1;
914 }
915
916 // --- RTP/RTCP module initialization
917
918 // Ensure that RTCP is enabled by default for the created channel.
919 // Note that, the module will keep generating RTCP until it is explicitly
920 // disabled by the user.
921 // After StopListen (when no sockets exists), RTCP packets will no longer
922 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000923 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
924 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000925 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
926 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000928 (audio_coding_->RegisterTransportCallback(this) == -1) ||
929 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000930
931 if (fail)
932 {
933 _engineStatisticsPtr->SetLastError(
934 VE_CANNOT_INIT_CHANNEL, kTraceError,
935 "Channel::Init() callbacks not registered");
936 return -1;
937 }
938
939 // --- Register all supported codecs to the receiving side of the
940 // RTP/RTCP module
941
942 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000943 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000944
945 for (int idx = 0; idx < nSupportedCodecs; idx++)
946 {
947 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000948 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000949 (rtp_receiver_->RegisterReceivePayload(
950 codec.plname,
951 codec.pltype,
952 codec.plfreq,
953 codec.channels,
954 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000955 {
956 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
957 VoEId(_instanceId,_channelId),
958 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
959 "to RTP/RTCP receiver",
960 codec.plname, codec.pltype, codec.plfreq,
961 codec.channels, codec.rate);
962 }
963 else
964 {
965 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
966 VoEId(_instanceId,_channelId),
967 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
968 "the RTP/RTCP receiver",
969 codec.plname, codec.pltype, codec.plfreq,
970 codec.channels, codec.rate);
971 }
972
973 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000974 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000975 {
976 SetSendCodec(codec);
977 }
978
979 // Register default PT for outband 'telephone-event'
980 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
981 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000982 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000983 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 {
985 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
986 VoEId(_instanceId,_channelId),
987 "Channel::Init() failed to register outband "
988 "'telephone-event' (%d/%d) correctly",
989 codec.pltype, codec.plfreq);
990 }
991 }
992
993 if (!STR_CASE_CMP(codec.plname, "CN"))
994 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000995 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
996 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000997 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 {
999 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1000 VoEId(_instanceId,_channelId),
1001 "Channel::Init() failed to register CN (%d/%d) "
1002 "correctly - 1",
1003 codec.pltype, codec.plfreq);
1004 }
1005 }
1006#ifdef WEBRTC_CODEC_RED
1007 // Register RED to the receiving side of the ACM.
1008 // We will not receive an OnInitializeDecoder() callback for RED.
1009 if (!STR_CASE_CMP(codec.plname, "RED"))
1010 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001011 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 {
1013 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1014 VoEId(_instanceId,_channelId),
1015 "Channel::Init() failed to register RED (%d/%d) "
1016 "correctly",
1017 codec.pltype, codec.plfreq);
1018 }
1019 }
1020#endif
1021 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001022
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001023 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1024 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1025 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001027 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1028 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1029 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 }
1031
1032 return 0;
1033}
1034
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001035int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001036Channel::SetEngineInformation(Statistics& engineStatistics,
1037 OutputMixer& outputMixer,
1038 voe::TransmitMixer& transmitMixer,
1039 ProcessThread& moduleProcessThread,
1040 AudioDeviceModule& audioDeviceModule,
1041 VoiceEngineObserver* voiceEngineObserver,
1042 CriticalSectionWrapper* callbackCritSect)
1043{
1044 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1045 "Channel::SetEngineInformation()");
1046 _engineStatisticsPtr = &engineStatistics;
1047 _outputMixerPtr = &outputMixer;
1048 _transmitMixerPtr = &transmitMixer,
1049 _moduleProcessThreadPtr = &moduleProcessThread;
1050 _audioDeviceModulePtr = &audioDeviceModule;
1051 _voiceEngineObserverPtr = voiceEngineObserver;
1052 _callbackCritSectPtr = callbackCritSect;
1053 return 0;
1054}
1055
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001056int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001057Channel::UpdateLocalTimeStamp()
1058{
1059
Peter Kastingb7e50542015-06-11 12:55:50 -07001060 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 return 0;
1062}
1063
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001064int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001065Channel::StartPlayout()
1066{
1067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1068 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001069 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 {
1071 return 0;
1072 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001073
1074 if (!_externalMixing) {
1075 // Add participant as candidates for mixing.
1076 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1077 {
1078 _engineStatisticsPtr->SetLastError(
1079 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1080 "StartPlayout() failed to add participant to mixer");
1081 return -1;
1082 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 }
1084
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001085 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001086 if (RegisterFilePlayingToMixer() != 0)
1087 return -1;
1088
niklase@google.com470e71d2011-07-07 08:21:25 +00001089 return 0;
1090}
1091
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001092int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001093Channel::StopPlayout()
1094{
1095 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1096 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001097 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 {
1099 return 0;
1100 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001101
1102 if (!_externalMixing) {
1103 // Remove participant as candidates for mixing
1104 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1108 "StopPlayout() failed to remove participant from mixer");
1109 return -1;
1110 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001111 }
1112
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001113 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 _outputAudioLevel.Clear();
1115
1116 return 0;
1117}
1118
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001119int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001120Channel::StartSend()
1121{
1122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1123 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001124 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001125 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001126 if (send_sequence_number_)
1127 SetInitSequenceNumber(send_sequence_number_);
1128
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001129 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001130 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001131 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001133 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001134
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001135 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 {
1137 _engineStatisticsPtr->SetLastError(
1138 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1139 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001140 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001141 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 return -1;
1143 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001144
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 return 0;
1146}
1147
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001148int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001149Channel::StopSend()
1150{
1151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1152 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001153 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001155 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001156 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001157 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001158
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001159 // Store the sequence number to be able to pick up the same sequence for
1160 // the next StartSend(). This is needed for restarting device, otherwise
1161 // it might cause libSRTP to complain about packets being replayed.
1162 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1163 // CL is landed. See issue
1164 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1165 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1166
niklase@google.com470e71d2011-07-07 08:21:25 +00001167 // Reset sending SSRC and sequence number and triggers direct transmission
1168 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001169 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 {
1171 _engineStatisticsPtr->SetLastError(
1172 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1173 "StartSend() RTP/RTCP failed to stop sending");
1174 }
1175
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 return 0;
1177}
1178
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001179int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001180Channel::StartReceiving()
1181{
1182 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1183 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001184 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
1186 return 0;
1187 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 _numberOfDiscardedPackets = 0;
1190 return 0;
1191}
1192
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001193int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001194Channel::StopReceiving()
1195{
1196 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1197 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001198 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 {
1200 return 0;
1201 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001202
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001203 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001204 return 0;
1205}
1206
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001207int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001208Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1209{
1210 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1211 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001212 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001213
1214 if (_voiceEngineObserverPtr)
1215 {
1216 _engineStatisticsPtr->SetLastError(
1217 VE_INVALID_OPERATION, kTraceError,
1218 "RegisterVoiceEngineObserver() observer already enabled");
1219 return -1;
1220 }
1221 _voiceEngineObserverPtr = &observer;
1222 return 0;
1223}
1224
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001225int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001226Channel::DeRegisterVoiceEngineObserver()
1227{
1228 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1229 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001230 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001231
1232 if (!_voiceEngineObserverPtr)
1233 {
1234 _engineStatisticsPtr->SetLastError(
1235 VE_INVALID_OPERATION, kTraceWarning,
1236 "DeRegisterVoiceEngineObserver() observer already disabled");
1237 return 0;
1238 }
1239 _voiceEngineObserverPtr = NULL;
1240 return 0;
1241}
1242
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001243int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001244Channel::GetSendCodec(CodecInst& codec)
1245{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001246 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001247}
1248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001249int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001250Channel::GetRecCodec(CodecInst& codec)
1251{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001252 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001253}
1254
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001255int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001256Channel::SetSendCodec(const CodecInst& codec)
1257{
1258 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1259 "Channel::SetSendCodec()");
1260
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001261 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 {
1263 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1264 "SetSendCodec() failed to register codec to ACM");
1265 return -1;
1266 }
1267
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001268 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001270 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1271 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 {
1273 WEBRTC_TRACE(
1274 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1275 "SetSendCodec() failed to register codec to"
1276 " RTP/RTCP module");
1277 return -1;
1278 }
1279 }
1280
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001281 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001282 {
1283 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1284 "SetSendCodec() failed to set audio packet size");
1285 return -1;
1286 }
1287
1288 return 0;
1289}
1290
Ivo Creusenadf89b72015-04-29 16:03:33 +02001291void Channel::SetBitRate(int bitrate_bps) {
1292 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1293 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1294 audio_coding_->SetBitRate(bitrate_bps);
1295}
1296
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001297void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001298 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001299 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1300
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001301 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001302 if (audio_coding_->SetPacketLossRate(
1303 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001304 assert(false); // This should not happen.
1305 }
1306}
1307
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001308int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001309Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1310{
1311 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1312 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001313 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 // To disable VAD, DTX must be disabled too
1315 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001316 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001317 {
1318 _engineStatisticsPtr->SetLastError(
1319 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1320 "SetVADStatus() failed to set VAD");
1321 return -1;
1322 }
1323 return 0;
1324}
1325
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001326int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001327Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1328{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001329 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 {
1331 _engineStatisticsPtr->SetLastError(
1332 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1333 "GetVADStatus() failed to get VAD status");
1334 return -1;
1335 }
1336 disabledDTX = !disabledDTX;
1337 return 0;
1338}
1339
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001340int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001341Channel::SetRecPayloadType(const CodecInst& codec)
1342{
1343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1344 "Channel::SetRecPayloadType()");
1345
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001346 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 {
1348 _engineStatisticsPtr->SetLastError(
1349 VE_ALREADY_PLAYING, kTraceError,
1350 "SetRecPayloadType() unable to set PT while playing");
1351 return -1;
1352 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001353 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001354 {
1355 _engineStatisticsPtr->SetLastError(
1356 VE_ALREADY_LISTENING, kTraceError,
1357 "SetRecPayloadType() unable to set PT while listening");
1358 return -1;
1359 }
1360
1361 if (codec.pltype == -1)
1362 {
1363 // De-register the selected codec (RTP/RTCP module and ACM)
1364
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001365 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001366 CodecInst rxCodec = codec;
1367
1368 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001369 rtp_payload_registry_->ReceivePayloadType(
1370 rxCodec.plname,
1371 rxCodec.plfreq,
1372 rxCodec.channels,
1373 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1374 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001375 rxCodec.pltype = pltype;
1376
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001377 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 {
1379 _engineStatisticsPtr->SetLastError(
1380 VE_RTP_RTCP_MODULE_ERROR,
1381 kTraceError,
1382 "SetRecPayloadType() RTP/RTCP-module deregistration "
1383 "failed");
1384 return -1;
1385 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001386 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001387 {
1388 _engineStatisticsPtr->SetLastError(
1389 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1390 "SetRecPayloadType() ACM deregistration failed - 1");
1391 return -1;
1392 }
1393 return 0;
1394 }
1395
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001396 if (rtp_receiver_->RegisterReceivePayload(
1397 codec.plname,
1398 codec.pltype,
1399 codec.plfreq,
1400 codec.channels,
1401 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001402 {
1403 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001404 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1405 if (rtp_receiver_->RegisterReceivePayload(
1406 codec.plname,
1407 codec.pltype,
1408 codec.plfreq,
1409 codec.channels,
1410 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 {
1412 _engineStatisticsPtr->SetLastError(
1413 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1414 "SetRecPayloadType() RTP/RTCP-module registration failed");
1415 return -1;
1416 }
1417 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001418 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001420 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1421 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001422 {
1423 _engineStatisticsPtr->SetLastError(
1424 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1425 "SetRecPayloadType() ACM registration failed - 1");
1426 return -1;
1427 }
1428 }
1429 return 0;
1430}
1431
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001432int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001433Channel::GetRecPayloadType(CodecInst& codec)
1434{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001435 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001436 if (rtp_payload_registry_->ReceivePayloadType(
1437 codec.plname,
1438 codec.plfreq,
1439 codec.channels,
1440 (codec.rate < 0) ? 0 : codec.rate,
1441 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 {
1443 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001444 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001445 "GetRecPayloadType() failed to retrieve RX payload type");
1446 return -1;
1447 }
1448 codec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 return 0;
1450}
1451
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001452int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001453Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1454{
1455 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1456 "Channel::SetSendCNPayloadType()");
1457
1458 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001459 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001460 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001461 if (frequency == kFreq32000Hz)
1462 samplingFreqHz = 32000;
1463 else if (frequency == kFreq16000Hz)
1464 samplingFreqHz = 16000;
1465
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001466 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001467 {
1468 _engineStatisticsPtr->SetLastError(
1469 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1470 "SetSendCNPayloadType() failed to retrieve default CN codec "
1471 "settings");
1472 return -1;
1473 }
1474
1475 // Modify the payload type (must be set to dynamic range)
1476 codec.pltype = type;
1477
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001478 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001479 {
1480 _engineStatisticsPtr->SetLastError(
1481 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1482 "SetSendCNPayloadType() failed to register CN to ACM");
1483 return -1;
1484 }
1485
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001486 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001487 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001488 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1489 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001490 {
1491 _engineStatisticsPtr->SetLastError(
1492 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1493 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1494 "module");
1495 return -1;
1496 }
1497 }
1498 return 0;
1499}
1500
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001501int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001502 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001503 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001504
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001505 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001506 _engineStatisticsPtr->SetLastError(
1507 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001508 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001509 return -1;
1510 }
1511 return 0;
1512}
1513
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001514int Channel::SetOpusDtx(bool enable_dtx) {
1515 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1516 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001517 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001518 : audio_coding_->DisableOpusDtx();
1519 if (ret != 0) {
1520 _engineStatisticsPtr->SetLastError(
1521 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1522 return -1;
1523 }
1524 return 0;
1525}
1526
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001527int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001528{
1529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1530 "Channel::RegisterExternalTransport()");
1531
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001532 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001533
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 if (_externalTransport)
1535 {
1536 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1537 kTraceError,
1538 "RegisterExternalTransport() external transport already enabled");
1539 return -1;
1540 }
1541 _externalTransport = true;
1542 _transportPtr = &transport;
1543 return 0;
1544}
1545
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001546int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001547Channel::DeRegisterExternalTransport()
1548{
1549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1550 "Channel::DeRegisterExternalTransport()");
1551
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001552 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001553
niklase@google.com470e71d2011-07-07 08:21:25 +00001554 if (!_transportPtr)
1555 {
1556 _engineStatisticsPtr->SetLastError(
1557 VE_INVALID_OPERATION, kTraceWarning,
1558 "DeRegisterExternalTransport() external transport already "
1559 "disabled");
1560 return 0;
1561 }
1562 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001563 _transportPtr = NULL;
1564 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1565 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 return 0;
1567}
1568
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001569int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001570 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001571 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1572 "Channel::ReceivedRTPPacket()");
1573
1574 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001575 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001576
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001577 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001578 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001579 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1580 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1581 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001582 return -1;
1583 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001584 header.payload_type_frequency =
1585 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001586 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001587 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001588 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001589 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001590 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001591 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001592
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001593 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001594}
1595
1596bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001597 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001598 const RTPHeader& header,
1599 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001600 if (rtp_payload_registry_->IsRtx(header)) {
1601 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001602 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001603 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001604 assert(packet_length >= header.headerLength);
1605 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001606 PayloadUnion payload_specific;
1607 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001608 &payload_specific)) {
1609 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001610 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001611 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1612 payload_specific, in_order);
1613}
1614
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001615bool Channel::HandleRtxPacket(const uint8_t* packet,
1616 size_t packet_length,
1617 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001618 if (!rtp_payload_registry_->IsRtx(header))
1619 return false;
1620
1621 // Remove the RTX header and parse the original RTP header.
1622 if (packet_length < header.headerLength)
1623 return false;
1624 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1625 return false;
1626 if (restored_packet_in_use_) {
1627 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1628 "Multiple RTX headers detected, dropping packet");
1629 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001630 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001631 uint8_t* restored_packet_ptr = restored_packet_;
1632 if (!rtp_payload_registry_->RestoreOriginalPacket(
1633 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1634 header)) {
1635 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1636 "Incoming RTX packet: invalid RTP header");
1637 return false;
1638 }
1639 restored_packet_in_use_ = true;
1640 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1641 restored_packet_in_use_ = false;
1642 return ret;
1643}
1644
1645bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1646 StreamStatistician* statistician =
1647 rtp_receive_statistics_->GetStatistician(header.ssrc);
1648 if (!statistician)
1649 return false;
1650 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001651}
1652
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001653bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1654 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001655 // Retransmissions are handled separately if RTX is enabled.
1656 if (rtp_payload_registry_->RtxEnabled())
1657 return false;
1658 StreamStatistician* statistician =
1659 rtp_receive_statistics_->GetStatistician(header.ssrc);
1660 if (!statistician)
1661 return false;
1662 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001663 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001664 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001665 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001666 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001667}
1668
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001669int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001670 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1671 "Channel::ReceivedRTCPPacket()");
1672 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001673 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001674
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001675 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001676 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001677 _engineStatisticsPtr->SetLastError(
1678 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1679 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1680 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001681
Minyue2013aec2015-05-13 14:14:42 +02001682 int64_t rtt = GetRTT(true);
1683 if (rtt == 0) {
1684 // Waiting for valid RTT.
1685 return 0;
1686 }
1687 uint32_t ntp_secs = 0;
1688 uint32_t ntp_frac = 0;
1689 uint32_t rtp_timestamp = 0;
1690 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1691 &rtp_timestamp)) {
1692 // Waiting for RTCP.
1693 return 0;
1694 }
1695
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001696 {
1697 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001698 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001699 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001700 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001701}
1702
niklase@google.com470e71d2011-07-07 08:21:25 +00001703int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001704 bool loop,
1705 FileFormats format,
1706 int startPosition,
1707 float volumeScaling,
1708 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001709 const CodecInst* codecInst)
1710{
1711 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1712 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1713 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1714 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1715 startPosition, stopPosition);
1716
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001717 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001718 {
1719 _engineStatisticsPtr->SetLastError(
1720 VE_ALREADY_PLAYING, kTraceError,
1721 "StartPlayingFileLocally() is already playing");
1722 return -1;
1723 }
1724
niklase@google.com470e71d2011-07-07 08:21:25 +00001725 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001726 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001727
1728 if (_outputFilePlayerPtr)
1729 {
1730 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1731 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1732 _outputFilePlayerPtr = NULL;
1733 }
1734
1735 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1736 _outputFilePlayerId, (const FileFormats)format);
1737
1738 if (_outputFilePlayerPtr == NULL)
1739 {
1740 _engineStatisticsPtr->SetLastError(
1741 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001742 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001743 return -1;
1744 }
1745
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001746 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001747
1748 if (_outputFilePlayerPtr->StartPlayingFile(
1749 fileName,
1750 loop,
1751 startPosition,
1752 volumeScaling,
1753 notificationTime,
1754 stopPosition,
1755 (const CodecInst*)codecInst) != 0)
1756 {
1757 _engineStatisticsPtr->SetLastError(
1758 VE_BAD_FILE, kTraceError,
1759 "StartPlayingFile() failed to start file playout");
1760 _outputFilePlayerPtr->StopPlayingFile();
1761 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1762 _outputFilePlayerPtr = NULL;
1763 return -1;
1764 }
1765 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001766 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001767 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001768
1769 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001770 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001771
1772 return 0;
1773}
1774
1775int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001776 FileFormats format,
1777 int startPosition,
1778 float volumeScaling,
1779 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001780 const CodecInst* codecInst)
1781{
1782 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1783 "Channel::StartPlayingFileLocally(format=%d,"
1784 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1785 format, volumeScaling, startPosition, stopPosition);
1786
1787 if(stream == NULL)
1788 {
1789 _engineStatisticsPtr->SetLastError(
1790 VE_BAD_FILE, kTraceError,
1791 "StartPlayingFileLocally() NULL as input stream");
1792 return -1;
1793 }
1794
1795
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001796 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001797 {
1798 _engineStatisticsPtr->SetLastError(
1799 VE_ALREADY_PLAYING, kTraceError,
1800 "StartPlayingFileLocally() is already playing");
1801 return -1;
1802 }
1803
niklase@google.com470e71d2011-07-07 08:21:25 +00001804 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001805 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001806
1807 // Destroy the old instance
1808 if (_outputFilePlayerPtr)
1809 {
1810 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1811 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1812 _outputFilePlayerPtr = NULL;
1813 }
1814
1815 // Create the instance
1816 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1817 _outputFilePlayerId,
1818 (const FileFormats)format);
1819
1820 if (_outputFilePlayerPtr == NULL)
1821 {
1822 _engineStatisticsPtr->SetLastError(
1823 VE_INVALID_ARGUMENT, kTraceError,
1824 "StartPlayingFileLocally() filePlayer format isnot correct");
1825 return -1;
1826 }
1827
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001828 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001829
1830 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1831 volumeScaling,
1832 notificationTime,
1833 stopPosition, codecInst) != 0)
1834 {
1835 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1836 "StartPlayingFile() failed to "
1837 "start file playout");
1838 _outputFilePlayerPtr->StopPlayingFile();
1839 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1840 _outputFilePlayerPtr = NULL;
1841 return -1;
1842 }
1843 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001844 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001845 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001846
1847 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001848 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001849
niklase@google.com470e71d2011-07-07 08:21:25 +00001850 return 0;
1851}
1852
1853int Channel::StopPlayingFileLocally()
1854{
1855 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1856 "Channel::StopPlayingFileLocally()");
1857
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001858 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001859 {
niklase@google.com470e71d2011-07-07 08:21:25 +00001860 return 0;
1861 }
1862
niklase@google.com470e71d2011-07-07 08:21:25 +00001863 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001864 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001865
1866 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1867 {
1868 _engineStatisticsPtr->SetLastError(
1869 VE_STOP_RECORDING_FAILED, kTraceError,
1870 "StopPlayingFile() could not stop playing");
1871 return -1;
1872 }
1873 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1874 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1875 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001876 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001877 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001878 // _fileCritSect cannot be taken while calling
1879 // SetAnonymousMixibilityStatus. Refer to comments in
1880 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001881 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1882 {
1883 _engineStatisticsPtr->SetLastError(
1884 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001885 "StopPlayingFile() failed to stop participant from playing as"
1886 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001887 return -1;
1888 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001889
1890 return 0;
1891}
1892
1893int Channel::IsPlayingFileLocally() const
1894{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001895 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001896}
1897
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001898int Channel::RegisterFilePlayingToMixer()
1899{
1900 // Return success for not registering for file playing to mixer if:
1901 // 1. playing file before playout is started on that channel.
1902 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001903 if (!channel_state_.Get().playing ||
1904 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001905 {
1906 return 0;
1907 }
1908
1909 // |_fileCritSect| cannot be taken while calling
1910 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1911 // frames can be pulled by the mixer. Since the frames are generated from
1912 // the file, _fileCritSect will be taken. This would result in a deadlock.
1913 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1914 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001915 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001916 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001917 _engineStatisticsPtr->SetLastError(
1918 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1919 "StartPlayingFile() failed to add participant as file to mixer");
1920 _outputFilePlayerPtr->StopPlayingFile();
1921 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1922 _outputFilePlayerPtr = NULL;
1923 return -1;
1924 }
1925
1926 return 0;
1927}
1928
niklase@google.com470e71d2011-07-07 08:21:25 +00001929int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001930 bool loop,
1931 FileFormats format,
1932 int startPosition,
1933 float volumeScaling,
1934 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 const CodecInst* codecInst)
1936{
1937 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1938 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1939 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1940 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1941 startPosition, stopPosition);
1942
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001943 CriticalSectionScoped cs(&_fileCritSect);
1944
1945 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001946 {
1947 _engineStatisticsPtr->SetLastError(
1948 VE_ALREADY_PLAYING, kTraceWarning,
1949 "StartPlayingFileAsMicrophone() filePlayer is playing");
1950 return 0;
1951 }
1952
niklase@google.com470e71d2011-07-07 08:21:25 +00001953 // Destroy the old instance
1954 if (_inputFilePlayerPtr)
1955 {
1956 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1957 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1958 _inputFilePlayerPtr = NULL;
1959 }
1960
1961 // Create the instance
1962 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1963 _inputFilePlayerId, (const FileFormats)format);
1964
1965 if (_inputFilePlayerPtr == NULL)
1966 {
1967 _engineStatisticsPtr->SetLastError(
1968 VE_INVALID_ARGUMENT, kTraceError,
1969 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
1970 return -1;
1971 }
1972
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001973 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001974
1975 if (_inputFilePlayerPtr->StartPlayingFile(
1976 fileName,
1977 loop,
1978 startPosition,
1979 volumeScaling,
1980 notificationTime,
1981 stopPosition,
1982 (const CodecInst*)codecInst) != 0)
1983 {
1984 _engineStatisticsPtr->SetLastError(
1985 VE_BAD_FILE, kTraceError,
1986 "StartPlayingFile() failed to start file playout");
1987 _inputFilePlayerPtr->StopPlayingFile();
1988 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1989 _inputFilePlayerPtr = NULL;
1990 return -1;
1991 }
1992 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001993 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001994
1995 return 0;
1996}
1997
1998int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001999 FileFormats format,
2000 int startPosition,
2001 float volumeScaling,
2002 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002003 const CodecInst* codecInst)
2004{
2005 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2006 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2007 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2008 format, volumeScaling, startPosition, stopPosition);
2009
2010 if(stream == NULL)
2011 {
2012 _engineStatisticsPtr->SetLastError(
2013 VE_BAD_FILE, kTraceError,
2014 "StartPlayingFileAsMicrophone NULL as input stream");
2015 return -1;
2016 }
2017
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002018 CriticalSectionScoped cs(&_fileCritSect);
2019
2020 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 {
2022 _engineStatisticsPtr->SetLastError(
2023 VE_ALREADY_PLAYING, kTraceWarning,
2024 "StartPlayingFileAsMicrophone() is playing");
2025 return 0;
2026 }
2027
niklase@google.com470e71d2011-07-07 08:21:25 +00002028 // Destroy the old instance
2029 if (_inputFilePlayerPtr)
2030 {
2031 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2032 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2033 _inputFilePlayerPtr = NULL;
2034 }
2035
2036 // Create the instance
2037 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2038 _inputFilePlayerId, (const FileFormats)format);
2039
2040 if (_inputFilePlayerPtr == NULL)
2041 {
2042 _engineStatisticsPtr->SetLastError(
2043 VE_INVALID_ARGUMENT, kTraceError,
2044 "StartPlayingInputFile() filePlayer format isnot correct");
2045 return -1;
2046 }
2047
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002048 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002049
2050 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2051 volumeScaling, notificationTime,
2052 stopPosition, codecInst) != 0)
2053 {
2054 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2055 "StartPlayingFile() failed to start "
2056 "file playout");
2057 _inputFilePlayerPtr->StopPlayingFile();
2058 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2059 _inputFilePlayerPtr = NULL;
2060 return -1;
2061 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002062
niklase@google.com470e71d2011-07-07 08:21:25 +00002063 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002064 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002065
2066 return 0;
2067}
2068
2069int Channel::StopPlayingFileAsMicrophone()
2070{
2071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2072 "Channel::StopPlayingFileAsMicrophone()");
2073
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002074 CriticalSectionScoped cs(&_fileCritSect);
2075
2076 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002077 {
niklase@google.com470e71d2011-07-07 08:21:25 +00002078 return 0;
2079 }
2080
niklase@google.com470e71d2011-07-07 08:21:25 +00002081 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2082 {
2083 _engineStatisticsPtr->SetLastError(
2084 VE_STOP_RECORDING_FAILED, kTraceError,
2085 "StopPlayingFile() could not stop playing");
2086 return -1;
2087 }
2088 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2089 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2090 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002091 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002092
2093 return 0;
2094}
2095
2096int Channel::IsPlayingFileAsMicrophone() const
2097{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002098 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002099}
2100
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002101int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002102 const CodecInst* codecInst)
2103{
2104 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2105 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2106
2107 if (_outputFileRecording)
2108 {
2109 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2110 "StartRecordingPlayout() is already recording");
2111 return 0;
2112 }
2113
2114 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002115 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002116 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2117
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002118 if ((codecInst != NULL) &&
2119 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002120 {
2121 _engineStatisticsPtr->SetLastError(
2122 VE_BAD_ARGUMENT, kTraceError,
2123 "StartRecordingPlayout() invalid compression");
2124 return(-1);
2125 }
2126 if(codecInst == NULL)
2127 {
2128 format = kFileFormatPcm16kHzFile;
2129 codecInst=&dummyCodec;
2130 }
2131 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2132 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2133 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2134 {
2135 format = kFileFormatWavFile;
2136 }
2137 else
2138 {
2139 format = kFileFormatCompressedFile;
2140 }
2141
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002142 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002143
2144 // Destroy the old instance
2145 if (_outputFileRecorderPtr)
2146 {
2147 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2148 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2149 _outputFileRecorderPtr = NULL;
2150 }
2151
2152 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2153 _outputFileRecorderId, (const FileFormats)format);
2154 if (_outputFileRecorderPtr == NULL)
2155 {
2156 _engineStatisticsPtr->SetLastError(
2157 VE_INVALID_ARGUMENT, kTraceError,
2158 "StartRecordingPlayout() fileRecorder format isnot correct");
2159 return -1;
2160 }
2161
2162 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2163 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2164 {
2165 _engineStatisticsPtr->SetLastError(
2166 VE_BAD_FILE, kTraceError,
2167 "StartRecordingAudioFile() failed to start file recording");
2168 _outputFileRecorderPtr->StopRecording();
2169 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2170 _outputFileRecorderPtr = NULL;
2171 return -1;
2172 }
2173 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2174 _outputFileRecording = true;
2175
2176 return 0;
2177}
2178
2179int Channel::StartRecordingPlayout(OutStream* stream,
2180 const CodecInst* codecInst)
2181{
2182 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2183 "Channel::StartRecordingPlayout()");
2184
2185 if (_outputFileRecording)
2186 {
2187 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2188 "StartRecordingPlayout() is already recording");
2189 return 0;
2190 }
2191
2192 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002193 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002194 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2195
2196 if (codecInst != NULL && codecInst->channels != 1)
2197 {
2198 _engineStatisticsPtr->SetLastError(
2199 VE_BAD_ARGUMENT, kTraceError,
2200 "StartRecordingPlayout() invalid compression");
2201 return(-1);
2202 }
2203 if(codecInst == NULL)
2204 {
2205 format = kFileFormatPcm16kHzFile;
2206 codecInst=&dummyCodec;
2207 }
2208 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2209 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2210 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2211 {
2212 format = kFileFormatWavFile;
2213 }
2214 else
2215 {
2216 format = kFileFormatCompressedFile;
2217 }
2218
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002219 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002220
2221 // Destroy the old instance
2222 if (_outputFileRecorderPtr)
2223 {
2224 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2225 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2226 _outputFileRecorderPtr = NULL;
2227 }
2228
2229 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2230 _outputFileRecorderId, (const FileFormats)format);
2231 if (_outputFileRecorderPtr == NULL)
2232 {
2233 _engineStatisticsPtr->SetLastError(
2234 VE_INVALID_ARGUMENT, kTraceError,
2235 "StartRecordingPlayout() fileRecorder format isnot correct");
2236 return -1;
2237 }
2238
2239 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2240 notificationTime) != 0)
2241 {
2242 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2243 "StartRecordingPlayout() failed to "
2244 "start file recording");
2245 _outputFileRecorderPtr->StopRecording();
2246 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2247 _outputFileRecorderPtr = NULL;
2248 return -1;
2249 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002250
niklase@google.com470e71d2011-07-07 08:21:25 +00002251 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2252 _outputFileRecording = true;
2253
2254 return 0;
2255}
2256
2257int Channel::StopRecordingPlayout()
2258{
2259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2260 "Channel::StopRecordingPlayout()");
2261
2262 if (!_outputFileRecording)
2263 {
2264 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2265 "StopRecordingPlayout() isnot recording");
2266 return -1;
2267 }
2268
2269
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002270 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002271
2272 if (_outputFileRecorderPtr->StopRecording() != 0)
2273 {
2274 _engineStatisticsPtr->SetLastError(
2275 VE_STOP_RECORDING_FAILED, kTraceError,
2276 "StopRecording() could not stop recording");
2277 return(-1);
2278 }
2279 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2280 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2281 _outputFileRecorderPtr = NULL;
2282 _outputFileRecording = false;
2283
2284 return 0;
2285}
2286
2287void
2288Channel::SetMixWithMicStatus(bool mix)
2289{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002290 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002291 _mixFileWithMicrophone=mix;
2292}
2293
2294int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002295Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002296{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002297 int8_t currentLevel = _outputAudioLevel.Level();
2298 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002299 return 0;
2300}
2301
2302int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002303Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002304{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002305 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2306 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002307 return 0;
2308}
2309
2310int
2311Channel::SetMute(bool enable)
2312{
wu@webrtc.org63420662013-10-17 18:28:55 +00002313 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002314 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2315 "Channel::SetMute(enable=%d)", enable);
2316 _mute = enable;
2317 return 0;
2318}
2319
2320bool
2321Channel::Mute() const
2322{
wu@webrtc.org63420662013-10-17 18:28:55 +00002323 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002324 return _mute;
2325}
2326
2327int
2328Channel::SetOutputVolumePan(float left, float right)
2329{
wu@webrtc.org63420662013-10-17 18:28:55 +00002330 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2332 "Channel::SetOutputVolumePan()");
2333 _panLeft = left;
2334 _panRight = right;
2335 return 0;
2336}
2337
2338int
2339Channel::GetOutputVolumePan(float& left, float& right) const
2340{
wu@webrtc.org63420662013-10-17 18:28:55 +00002341 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 left = _panLeft;
2343 right = _panRight;
niklase@google.com470e71d2011-07-07 08:21:25 +00002344 return 0;
2345}
2346
2347int
2348Channel::SetChannelOutputVolumeScaling(float scaling)
2349{
wu@webrtc.org63420662013-10-17 18:28:55 +00002350 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2352 "Channel::SetChannelOutputVolumeScaling()");
2353 _outputGain = scaling;
2354 return 0;
2355}
2356
2357int
2358Channel::GetChannelOutputVolumeScaling(float& scaling) const
2359{
wu@webrtc.org63420662013-10-17 18:28:55 +00002360 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002361 scaling = _outputGain;
niklase@google.com470e71d2011-07-07 08:21:25 +00002362 return 0;
2363}
2364
niklase@google.com470e71d2011-07-07 08:21:25 +00002365int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002366 int lengthMs, int attenuationDb,
2367 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002368{
2369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2370 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2371 playDtmfEvent);
2372
2373 _playOutbandDtmfEvent = playDtmfEvent;
2374
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002375 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002376 attenuationDb) != 0)
2377 {
2378 _engineStatisticsPtr->SetLastError(
2379 VE_SEND_DTMF_FAILED,
2380 kTraceWarning,
2381 "SendTelephoneEventOutband() failed to send event");
2382 return -1;
2383 }
2384 return 0;
2385}
2386
2387int Channel::SendTelephoneEventInband(unsigned char eventCode,
2388 int lengthMs,
2389 int attenuationDb,
2390 bool playDtmfEvent)
2391{
2392 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2393 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2394 playDtmfEvent);
2395
2396 _playInbandDtmfEvent = playDtmfEvent;
2397 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2398
2399 return 0;
2400}
2401
2402int
niklase@google.com470e71d2011-07-07 08:21:25 +00002403Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2404{
2405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2406 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002407 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002408 {
2409 _engineStatisticsPtr->SetLastError(
2410 VE_INVALID_ARGUMENT, kTraceError,
2411 "SetSendTelephoneEventPayloadType() invalid type");
2412 return -1;
2413 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002414 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002415 codec.plfreq = 8000;
2416 codec.pltype = type;
2417 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002418 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002419 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002420 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2421 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2422 _engineStatisticsPtr->SetLastError(
2423 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2424 "SetSendTelephoneEventPayloadType() failed to register send"
2425 "payload type");
2426 return -1;
2427 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002428 }
2429 _sendTelephoneEventPayloadType = type;
2430 return 0;
2431}
2432
2433int
2434Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2435{
niklase@google.com470e71d2011-07-07 08:21:25 +00002436 type = _sendTelephoneEventPayloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002437 return 0;
2438}
2439
niklase@google.com470e71d2011-07-07 08:21:25 +00002440int
2441Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2442{
2443 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2444 "Channel::UpdateRxVadDetection()");
2445
2446 int vadDecision = 1;
2447
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002448 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002449
2450 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2451 {
2452 OnRxVadDetected(vadDecision);
2453 _oldVadDecision = vadDecision;
2454 }
2455
2456 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2457 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2458 vadDecision);
2459 return 0;
2460}
2461
2462int
2463Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2464{
2465 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2466 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002467 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002468
2469 if (_rxVadObserverPtr)
2470 {
2471 _engineStatisticsPtr->SetLastError(
2472 VE_INVALID_OPERATION, kTraceError,
2473 "RegisterRxVadObserver() observer already enabled");
2474 return -1;
2475 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 _rxVadObserverPtr = &observer;
2477 _RxVadDetection = true;
2478 return 0;
2479}
2480
2481int
2482Channel::DeRegisterRxVadObserver()
2483{
2484 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2485 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002486 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002487
2488 if (!_rxVadObserverPtr)
2489 {
2490 _engineStatisticsPtr->SetLastError(
2491 VE_INVALID_OPERATION, kTraceWarning,
2492 "DeRegisterRxVadObserver() observer already disabled");
2493 return 0;
2494 }
2495 _rxVadObserverPtr = NULL;
2496 _RxVadDetection = false;
2497 return 0;
2498}
2499
2500int
2501Channel::VoiceActivityIndicator(int &activity)
2502{
2503 activity = _sendFrameType;
niklase@google.com470e71d2011-07-07 08:21:25 +00002504 return 0;
2505}
2506
2507#ifdef WEBRTC_VOICE_ENGINE_AGC
2508
2509int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002510Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002511{
2512 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2513 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2514 (int)enable, (int)mode);
2515
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002516 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002517 switch (mode)
2518 {
2519 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002520 break;
2521 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002522 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002523 break;
2524 case kAgcFixedDigital:
2525 agcMode = GainControl::kFixedDigital;
2526 break;
2527 case kAgcAdaptiveDigital:
2528 agcMode =GainControl::kAdaptiveDigital;
2529 break;
2530 default:
2531 _engineStatisticsPtr->SetLastError(
2532 VE_INVALID_ARGUMENT, kTraceError,
2533 "SetRxAgcStatus() invalid Agc mode");
2534 return -1;
2535 }
2536
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002537 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002538 {
2539 _engineStatisticsPtr->SetLastError(
2540 VE_APM_ERROR, kTraceError,
2541 "SetRxAgcStatus() failed to set Agc mode");
2542 return -1;
2543 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002544 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002545 {
2546 _engineStatisticsPtr->SetLastError(
2547 VE_APM_ERROR, kTraceError,
2548 "SetRxAgcStatus() failed to set Agc state");
2549 return -1;
2550 }
2551
2552 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002553 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002554
2555 return 0;
2556}
2557
2558int
2559Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2560{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002561 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002562 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002563 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002564
2565 enabled = enable;
2566
2567 switch (agcMode)
2568 {
2569 case GainControl::kFixedDigital:
2570 mode = kAgcFixedDigital;
2571 break;
2572 case GainControl::kAdaptiveDigital:
2573 mode = kAgcAdaptiveDigital;
2574 break;
2575 default:
2576 _engineStatisticsPtr->SetLastError(
2577 VE_APM_ERROR, kTraceError,
2578 "GetRxAgcStatus() invalid Agc mode");
2579 return -1;
2580 }
2581
2582 return 0;
2583}
2584
2585int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002586Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002587{
2588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2589 "Channel::SetRxAgcConfig()");
2590
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002591 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002592 config.targetLeveldBOv) != 0)
2593 {
2594 _engineStatisticsPtr->SetLastError(
2595 VE_APM_ERROR, kTraceError,
2596 "SetRxAgcConfig() failed to set target peak |level|"
2597 "(or envelope) of the Agc");
2598 return -1;
2599 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002600 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002601 config.digitalCompressionGaindB) != 0)
2602 {
2603 _engineStatisticsPtr->SetLastError(
2604 VE_APM_ERROR, kTraceError,
2605 "SetRxAgcConfig() failed to set the range in |gain| the"
2606 " digital compression stage may apply");
2607 return -1;
2608 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002609 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002610 config.limiterEnable) != 0)
2611 {
2612 _engineStatisticsPtr->SetLastError(
2613 VE_APM_ERROR, kTraceError,
2614 "SetRxAgcConfig() failed to set hard limiter to the signal");
2615 return -1;
2616 }
2617
2618 return 0;
2619}
2620
2621int
2622Channel::GetRxAgcConfig(AgcConfig& config)
2623{
niklase@google.com470e71d2011-07-07 08:21:25 +00002624 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002625 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002626 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002627 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002628 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002629 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002630
niklase@google.com470e71d2011-07-07 08:21:25 +00002631 return 0;
2632}
2633
2634#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2635
2636#ifdef WEBRTC_VOICE_ENGINE_NR
2637
2638int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002639Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002640{
2641 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2642 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2643 (int)enable, (int)mode);
2644
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002645 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002646 switch (mode)
2647 {
2648
2649 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002650 break;
2651 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002652 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002653 break;
2654 case kNsConference:
2655 nsLevel = NoiseSuppression::kHigh;
2656 break;
2657 case kNsLowSuppression:
2658 nsLevel = NoiseSuppression::kLow;
2659 break;
2660 case kNsModerateSuppression:
2661 nsLevel = NoiseSuppression::kModerate;
2662 break;
2663 case kNsHighSuppression:
2664 nsLevel = NoiseSuppression::kHigh;
2665 break;
2666 case kNsVeryHighSuppression:
2667 nsLevel = NoiseSuppression::kVeryHigh;
2668 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002669 }
2670
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002671 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002672 != 0)
2673 {
2674 _engineStatisticsPtr->SetLastError(
2675 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002676 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002677 return -1;
2678 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002679 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 {
2681 _engineStatisticsPtr->SetLastError(
2682 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002683 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002684 return -1;
2685 }
2686
2687 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002688 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002689
2690 return 0;
2691}
2692
2693int
2694Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2695{
niklase@google.com470e71d2011-07-07 08:21:25 +00002696 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002697 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002698 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002699 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002700
2701 enabled = enable;
2702
2703 switch (ncLevel)
2704 {
2705 case NoiseSuppression::kLow:
2706 mode = kNsLowSuppression;
2707 break;
2708 case NoiseSuppression::kModerate:
2709 mode = kNsModerateSuppression;
2710 break;
2711 case NoiseSuppression::kHigh:
2712 mode = kNsHighSuppression;
2713 break;
2714 case NoiseSuppression::kVeryHigh:
2715 mode = kNsVeryHighSuppression;
2716 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002717 }
2718
niklase@google.com470e71d2011-07-07 08:21:25 +00002719 return 0;
2720}
2721
2722#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2723
2724int
niklase@google.com470e71d2011-07-07 08:21:25 +00002725Channel::SetLocalSSRC(unsigned int ssrc)
2726{
2727 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2728 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002729 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002730 {
2731 _engineStatisticsPtr->SetLastError(
2732 VE_ALREADY_SENDING, kTraceError,
2733 "SetLocalSSRC() already sending");
2734 return -1;
2735 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002736 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002737 return 0;
2738}
2739
2740int
2741Channel::GetLocalSSRC(unsigned int& ssrc)
2742{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002743 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002744 return 0;
2745}
2746
2747int
2748Channel::GetRemoteSSRC(unsigned int& ssrc)
2749{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002750 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002751 return 0;
2752}
2753
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002754int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002755 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002756 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002757}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002758
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002759int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2760 unsigned char id) {
2761 rtp_header_parser_->DeregisterRtpHeaderExtension(
2762 kRtpExtensionAudioLevel);
2763 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2764 kRtpExtensionAudioLevel, id)) {
2765 return -1;
2766 }
2767 return 0;
2768}
2769
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002770int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2771 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2772}
2773
2774int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2775 rtp_header_parser_->DeregisterRtpHeaderExtension(
2776 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002777 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2778 kRtpExtensionAbsoluteSendTime, id)) {
2779 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002780 }
2781 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002782}
2783
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002784void Channel::SetRTCPStatus(bool enable) {
2785 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2786 "Channel::SetRTCPStatus()");
2787 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002788}
2789
2790int
2791Channel::GetRTCPStatus(bool& enabled)
2792{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002793 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002794 enabled = (method != kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002795 return 0;
2796}
2797
2798int
2799Channel::SetRTCP_CNAME(const char cName[256])
2800{
2801 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2802 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002803 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002804 {
2805 _engineStatisticsPtr->SetLastError(
2806 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2807 "SetRTCP_CNAME() failed to set RTCP CNAME");
2808 return -1;
2809 }
2810 return 0;
2811}
2812
2813int
niklase@google.com470e71d2011-07-07 08:21:25 +00002814Channel::GetRemoteRTCP_CNAME(char cName[256])
2815{
2816 if (cName == NULL)
2817 {
2818 _engineStatisticsPtr->SetLastError(
2819 VE_INVALID_ARGUMENT, kTraceError,
2820 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2821 return -1;
2822 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002823 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002824 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002825 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002826 {
2827 _engineStatisticsPtr->SetLastError(
2828 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2829 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2830 return -1;
2831 }
2832 strcpy(cName, cname);
niklase@google.com470e71d2011-07-07 08:21:25 +00002833 return 0;
2834}
2835
2836int
2837Channel::GetRemoteRTCPData(
2838 unsigned int& NTPHigh,
2839 unsigned int& NTPLow,
2840 unsigned int& timestamp,
2841 unsigned int& playoutTimestamp,
2842 unsigned int* jitter,
2843 unsigned short* fractionLost)
2844{
2845 // --- Information from sender info in received Sender Reports
2846
2847 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002848 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002849 {
2850 _engineStatisticsPtr->SetLastError(
2851 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002852 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002853 "side");
2854 return -1;
2855 }
2856
2857 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2858 // and octet count)
2859 NTPHigh = senderInfo.NTPseconds;
2860 NTPLow = senderInfo.NTPfraction;
2861 timestamp = senderInfo.RTPtimeStamp;
2862
niklase@google.com470e71d2011-07-07 08:21:25 +00002863 // --- Locally derived information
2864
2865 // This value is updated on each incoming RTCP packet (0 when no packet
2866 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002867 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002868
niklase@google.com470e71d2011-07-07 08:21:25 +00002869 if (NULL != jitter || NULL != fractionLost)
2870 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002871 // Get all RTCP receiver report blocks that have been received on this
2872 // channel. If we receive RTP packets from a remote source we know the
2873 // remote SSRC and use the report block from him.
2874 // Otherwise use the first report block.
2875 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002876 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002877 remote_stats.empty()) {
2878 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2879 VoEId(_instanceId, _channelId),
2880 "GetRemoteRTCPData() failed to measure statistics due"
2881 " to lack of received RTP and/or RTCP packets");
2882 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002883 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002884
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002885 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002886 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2887 for (; it != remote_stats.end(); ++it) {
2888 if (it->remoteSSRC == remoteSSRC)
2889 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002890 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002891
2892 if (it == remote_stats.end()) {
2893 // If we have not received any RTCP packets from this SSRC it probably
2894 // means that we have not received any RTP packets.
2895 // Use the first received report block instead.
2896 it = remote_stats.begin();
2897 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00002898 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002899
xians@webrtc.org79af7342012-01-31 12:22:14 +00002900 if (jitter) {
2901 *jitter = it->jitter;
xians@webrtc.org79af7342012-01-31 12:22:14 +00002902 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002903
xians@webrtc.org79af7342012-01-31 12:22:14 +00002904 if (fractionLost) {
2905 *fractionLost = it->fractionLost;
xians@webrtc.org79af7342012-01-31 12:22:14 +00002906 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002907 }
2908 return 0;
2909}
2910
2911int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002912Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00002913 unsigned int name,
2914 const char* data,
2915 unsigned short dataLengthInBytes)
2916{
2917 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2918 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002919 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002920 {
2921 _engineStatisticsPtr->SetLastError(
2922 VE_NOT_SENDING, kTraceError,
2923 "SendApplicationDefinedRTCPPacket() not sending");
2924 return -1;
2925 }
2926 if (NULL == data)
2927 {
2928 _engineStatisticsPtr->SetLastError(
2929 VE_INVALID_ARGUMENT, kTraceError,
2930 "SendApplicationDefinedRTCPPacket() invalid data value");
2931 return -1;
2932 }
2933 if (dataLengthInBytes % 4 != 0)
2934 {
2935 _engineStatisticsPtr->SetLastError(
2936 VE_INVALID_ARGUMENT, kTraceError,
2937 "SendApplicationDefinedRTCPPacket() invalid length value");
2938 return -1;
2939 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002940 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 if (status == kRtcpOff)
2942 {
2943 _engineStatisticsPtr->SetLastError(
2944 VE_RTCP_ERROR, kTraceError,
2945 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
2946 return -1;
2947 }
2948
2949 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002950 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00002951 subType,
2952 name,
2953 (const unsigned char*) data,
2954 dataLengthInBytes) != 0)
2955 {
2956 _engineStatisticsPtr->SetLastError(
2957 VE_SEND_ERROR, kTraceError,
2958 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
2959 return -1;
2960 }
2961 return 0;
2962}
2963
2964int
2965Channel::GetRTPStatistics(
2966 unsigned int& averageJitterMs,
2967 unsigned int& maxJitterMs,
2968 unsigned int& discardedPackets)
2969{
niklase@google.com470e71d2011-07-07 08:21:25 +00002970 // The jitter statistics is updated for each received RTP packet and is
2971 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00002972 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
2973 // If RTCP is off, there is no timed thread in the RTCP module regularly
2974 // generating new stats, trigger the update manually here instead.
2975 StreamStatistician* statistician =
2976 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
2977 if (statistician) {
2978 // Don't use returned statistics, use data from proxy instead so that
2979 // max jitter can be fetched atomically.
2980 RtcpStatistics s;
2981 statistician->GetStatistics(&s, true);
2982 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002983 }
2984
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00002985 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002986 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00002987 if (playoutFrequency > 0) {
2988 // Scale RTP statistics given the current playout frequency
2989 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
2990 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00002991 }
2992
2993 discardedPackets = _numberOfDiscardedPackets;
2994
niklase@google.com470e71d2011-07-07 08:21:25 +00002995 return 0;
2996}
2997
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00002998int Channel::GetRemoteRTCPReportBlocks(
2999 std::vector<ReportBlock>* report_blocks) {
3000 if (report_blocks == NULL) {
3001 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3002 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3003 return -1;
3004 }
3005
3006 // Get the report blocks from the latest received RTCP Sender or Receiver
3007 // Report. Each element in the vector contains the sender's SSRC and a
3008 // report block according to RFC 3550.
3009 std::vector<RTCPReportBlock> rtcp_report_blocks;
3010 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003011 return -1;
3012 }
3013
3014 if (rtcp_report_blocks.empty())
3015 return 0;
3016
3017 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3018 for (; it != rtcp_report_blocks.end(); ++it) {
3019 ReportBlock report_block;
3020 report_block.sender_SSRC = it->remoteSSRC;
3021 report_block.source_SSRC = it->sourceSSRC;
3022 report_block.fraction_lost = it->fractionLost;
3023 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3024 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3025 report_block.interarrival_jitter = it->jitter;
3026 report_block.last_SR_timestamp = it->lastSR;
3027 report_block.delay_since_last_SR = it->delaySinceLastSR;
3028 report_blocks->push_back(report_block);
3029 }
3030 return 0;
3031}
3032
niklase@google.com470e71d2011-07-07 08:21:25 +00003033int
3034Channel::GetRTPStatistics(CallStatistics& stats)
3035{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003036 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003037
3038 // The jitter statistics is updated for each received RTP packet and is
3039 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003040 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003041 StreamStatistician* statistician =
3042 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3043 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003044 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3045 _engineStatisticsPtr->SetLastError(
3046 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3047 "GetRTPStatistics() failed to read RTP statistics from the "
3048 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003049 }
3050
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003051 stats.fractionLost = statistics.fraction_lost;
3052 stats.cumulativeLost = statistics.cumulative_lost;
3053 stats.extendedMax = statistics.extended_max_sequence_number;
3054 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003055
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003056 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003057 stats.rttMs = GetRTT(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003058
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003059 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003060
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003061 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003062 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003063 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003064 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003065
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003066 if (statistician) {
3067 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3068 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003069
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003070 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003071 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003072 {
3073 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3074 VoEId(_instanceId, _channelId),
3075 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003076 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003077 }
3078
3079 stats.bytesSent = bytesSent;
3080 stats.packetsSent = packetsSent;
3081 stats.bytesReceived = bytesReceived;
3082 stats.packetsReceived = packetsReceived;
3083
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003084 // --- Timestamps
3085 {
3086 CriticalSectionScoped lock(ts_stats_lock_.get());
3087 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3088 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003089 return 0;
3090}
3091
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003092int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003093 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003094 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003095
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003096 if (enable) {
3097 if (redPayloadtype < 0 || redPayloadtype > 127) {
3098 _engineStatisticsPtr->SetLastError(
3099 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003100 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003101 return -1;
3102 }
3103
3104 if (SetRedPayloadType(redPayloadtype) < 0) {
3105 _engineStatisticsPtr->SetLastError(
3106 VE_CODEC_ERROR, kTraceError,
3107 "SetSecondarySendCodec() Failed to register RED ACM");
3108 return -1;
3109 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003110 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003111
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003112 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003113 _engineStatisticsPtr->SetLastError(
3114 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003115 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003116 return -1;
3117 }
3118 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003119}
3120
3121int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003122Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003123{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003124 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 if (enabled)
3126 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003127 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003128 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003129 {
3130 _engineStatisticsPtr->SetLastError(
3131 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003132 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003133 "module");
3134 return -1;
3135 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003136 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003137 return 0;
3138 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003139 return 0;
3140}
3141
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003142int Channel::SetCodecFECStatus(bool enable) {
3143 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3144 "Channel::SetCodecFECStatus()");
3145
3146 if (audio_coding_->SetCodecFEC(enable) != 0) {
3147 _engineStatisticsPtr->SetLastError(
3148 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3149 "SetCodecFECStatus() failed to set FEC state");
3150 return -1;
3151 }
3152 return 0;
3153}
3154
3155bool Channel::GetCodecFECStatus() {
3156 bool enabled = audio_coding_->CodecFEC();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003157 return enabled;
3158}
3159
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003160void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3161 // None of these functions can fail.
3162 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003163 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3164 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003165 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003166 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003167 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003168 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003169}
3170
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003171// Called when we are missing one or more packets.
3172int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003173 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3174}
3175
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003176uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003177Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003178{
3179 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003180 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003181 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003182 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003183 return 0;
3184}
3185
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003186void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003187 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003188 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003189 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003190 CodecInst codec;
3191 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003192
Alejandro Luebscdfe20b2015-09-23 12:49:12 -07003193 // Never upsample or upmix the capture signal here. This should be done at the
3194 // end of the send chain.
3195 _audioFrame.sample_rate_hz_ = std::min(codec.plfreq, sample_rate);
3196 _audioFrame.num_channels_ = std::min(number_of_channels, codec.channels);
3197 RemixAndResample(audio_data, number_of_frames, number_of_channels,
3198 sample_rate, &input_resampler_, &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003199}
3200
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003201uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003202Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003203{
3204 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3205 "Channel::PrepareEncodeAndSend()");
3206
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003207 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003208 {
3209 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3210 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003211 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003212 }
3213
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003214 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003215 {
3216 MixOrReplaceAudioWithFile(mixingFrequency);
3217 }
3218
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003219 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3220 if (is_muted) {
3221 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003222 }
3223
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003224 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003225 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003226 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003227 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003228 if (_inputExternalMediaCallbackPtr)
3229 {
3230 _inputExternalMediaCallbackPtr->Process(
3231 _channelId,
3232 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003233 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003234 _audioFrame.samples_per_channel_,
3235 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003236 isStereo);
3237 }
3238 }
3239
3240 InsertInbandDtmfTone();
3241
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003242 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003243 size_t length =
3244 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003245 if (is_muted) {
3246 rms_level_.ProcessMuted(length);
3247 } else {
3248 rms_level_.Process(_audioFrame.data_, length);
3249 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003250 }
3251
niklase@google.com470e71d2011-07-07 08:21:25 +00003252 return 0;
3253}
3254
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003255uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003256Channel::EncodeAndSend()
3257{
3258 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3259 "Channel::EncodeAndSend()");
3260
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003261 assert(_audioFrame.num_channels_ <= 2);
3262 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003263 {
3264 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3265 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003266 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003267 }
3268
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003269 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003270
3271 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3272
3273 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003274 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003275 // This call will trigger AudioPacketizationCallback::SendData if encoding
3276 // is done and payload is ready for packetization and transmission.
3277 // Otherwise, it will return without invoking the callback.
3278 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003279 {
3280 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3281 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003282 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003283 }
3284
Peter Kastingb7e50542015-06-11 12:55:50 -07003285 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003286 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003287}
3288
Minyue2013aec2015-05-13 14:14:42 +02003289void Channel::DisassociateSendChannel(int channel_id) {
3290 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3291 Channel* channel = associate_send_channel_.channel();
3292 if (channel && channel->ChannelId() == channel_id) {
3293 // If this channel is associated with a send channel of the specified
3294 // Channel ID, disassociate with it.
3295 ChannelOwner ref(NULL);
3296 associate_send_channel_ = ref;
3297 }
3298}
3299
niklase@google.com470e71d2011-07-07 08:21:25 +00003300int Channel::RegisterExternalMediaProcessing(
3301 ProcessingTypes type,
3302 VoEMediaProcess& processObject)
3303{
3304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3305 "Channel::RegisterExternalMediaProcessing()");
3306
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003307 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003308
3309 if (kPlaybackPerChannel == type)
3310 {
3311 if (_outputExternalMediaCallbackPtr)
3312 {
3313 _engineStatisticsPtr->SetLastError(
3314 VE_INVALID_OPERATION, kTraceError,
3315 "Channel::RegisterExternalMediaProcessing() "
3316 "output external media already enabled");
3317 return -1;
3318 }
3319 _outputExternalMediaCallbackPtr = &processObject;
3320 _outputExternalMedia = true;
3321 }
3322 else if (kRecordingPerChannel == type)
3323 {
3324 if (_inputExternalMediaCallbackPtr)
3325 {
3326 _engineStatisticsPtr->SetLastError(
3327 VE_INVALID_OPERATION, kTraceError,
3328 "Channel::RegisterExternalMediaProcessing() "
3329 "output external media already enabled");
3330 return -1;
3331 }
3332 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003333 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003334 }
3335 return 0;
3336}
3337
3338int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3339{
3340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3341 "Channel::DeRegisterExternalMediaProcessing()");
3342
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003343 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003344
3345 if (kPlaybackPerChannel == type)
3346 {
3347 if (!_outputExternalMediaCallbackPtr)
3348 {
3349 _engineStatisticsPtr->SetLastError(
3350 VE_INVALID_OPERATION, kTraceWarning,
3351 "Channel::DeRegisterExternalMediaProcessing() "
3352 "output external media already disabled");
3353 return 0;
3354 }
3355 _outputExternalMedia = false;
3356 _outputExternalMediaCallbackPtr = NULL;
3357 }
3358 else if (kRecordingPerChannel == type)
3359 {
3360 if (!_inputExternalMediaCallbackPtr)
3361 {
3362 _engineStatisticsPtr->SetLastError(
3363 VE_INVALID_OPERATION, kTraceWarning,
3364 "Channel::DeRegisterExternalMediaProcessing() "
3365 "input external media already disabled");
3366 return 0;
3367 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003368 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003369 _inputExternalMediaCallbackPtr = NULL;
3370 }
3371
3372 return 0;
3373}
3374
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003375int Channel::SetExternalMixing(bool enabled) {
3376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3377 "Channel::SetExternalMixing(enabled=%d)", enabled);
3378
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003379 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003380 {
3381 _engineStatisticsPtr->SetLastError(
3382 VE_INVALID_OPERATION, kTraceError,
3383 "Channel::SetExternalMixing() "
3384 "external mixing cannot be changed while playing.");
3385 return -1;
3386 }
3387
3388 _externalMixing = enabled;
3389
3390 return 0;
3391}
3392
niklase@google.com470e71d2011-07-07 08:21:25 +00003393int
niklase@google.com470e71d2011-07-07 08:21:25 +00003394Channel::GetNetworkStatistics(NetworkStatistics& stats)
3395{
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003396 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003397}
3398
wu@webrtc.org24301a62013-12-13 19:17:43 +00003399void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3400 audio_coding_->GetDecodingCallStatistics(stats);
3401}
3402
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003403bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3404 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003405 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003406 if (_average_jitter_buffer_delay_us == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003407 return false;
3408 }
3409 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3410 _recPacketDelayMs;
3411 *playout_buffer_delay_ms = playout_delay_ms_;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003412 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003413}
3414
deadbeef74375882015-08-13 12:09:10 -07003415int Channel::LeastRequiredDelayMs() const {
3416 return audio_coding_->LeastRequiredDelayMs();
3417}
3418
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003419int Channel::SetInitialPlayoutDelay(int delay_ms)
3420{
3421 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3422 "Channel::SetInitialPlayoutDelay()");
3423 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3424 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3425 {
3426 _engineStatisticsPtr->SetLastError(
3427 VE_INVALID_ARGUMENT, kTraceError,
3428 "SetInitialPlayoutDelay() invalid min delay");
3429 return -1;
3430 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003431 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003432 {
3433 _engineStatisticsPtr->SetLastError(
3434 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3435 "SetInitialPlayoutDelay() failed to set min playout delay");
3436 return -1;
3437 }
3438 return 0;
3439}
3440
3441
niklase@google.com470e71d2011-07-07 08:21:25 +00003442int
3443Channel::SetMinimumPlayoutDelay(int delayMs)
3444{
3445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3446 "Channel::SetMinimumPlayoutDelay()");
3447 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3448 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3449 {
3450 _engineStatisticsPtr->SetLastError(
3451 VE_INVALID_ARGUMENT, kTraceError,
3452 "SetMinimumPlayoutDelay() invalid min delay");
3453 return -1;
3454 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003455 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003456 {
3457 _engineStatisticsPtr->SetLastError(
3458 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3459 "SetMinimumPlayoutDelay() failed to set min playout delay");
3460 return -1;
3461 }
3462 return 0;
3463}
3464
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003465int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
deadbeef74375882015-08-13 12:09:10 -07003466 uint32_t playout_timestamp_rtp = 0;
3467 {
3468 CriticalSectionScoped cs(video_sync_lock_.get());
3469 playout_timestamp_rtp = playout_timestamp_rtp_;
3470 }
3471 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003472 _engineStatisticsPtr->SetLastError(
3473 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3474 "GetPlayoutTimestamp() failed to retrieve timestamp");
3475 return -1;
3476 }
deadbeef74375882015-08-13 12:09:10 -07003477 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003478 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003479}
3480
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003481int Channel::SetInitTimestamp(unsigned int timestamp) {
3482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003483 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003484 if (channel_state_.Get().sending) {
3485 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3486 "SetInitTimestamp() already sending");
3487 return -1;
3488 }
3489 _rtpRtcpModule->SetStartTimestamp(timestamp);
3490 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003491}
3492
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003493int Channel::SetInitSequenceNumber(short sequenceNumber) {
3494 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3495 "Channel::SetInitSequenceNumber()");
3496 if (channel_state_.Get().sending) {
3497 _engineStatisticsPtr->SetLastError(
3498 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3499 return -1;
3500 }
3501 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3502 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003503}
3504
3505int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003506Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003507{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003508 *rtpRtcpModule = _rtpRtcpModule.get();
3509 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003510 return 0;
3511}
3512
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003513// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3514// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003515int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003516Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003517{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003518 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003519 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003520
3521 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003522 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003523
3524 if (_inputFilePlayerPtr == NULL)
3525 {
3526 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3527 VoEId(_instanceId, _channelId),
3528 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3529 " doesnt exist");
3530 return -1;
3531 }
3532
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003533 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003534 fileSamples,
3535 mixingFrequency) == -1)
3536 {
3537 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3538 VoEId(_instanceId, _channelId),
3539 "Channel::MixOrReplaceAudioWithFile() file mixing "
3540 "failed");
3541 return -1;
3542 }
3543 if (fileSamples == 0)
3544 {
3545 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3546 VoEId(_instanceId, _channelId),
3547 "Channel::MixOrReplaceAudioWithFile() file is ended");
3548 return 0;
3549 }
3550 }
3551
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003552 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003553
3554 if (_mixFileWithMicrophone)
3555 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003556 // Currently file stream is always mono.
3557 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003558 MixWithSat(_audioFrame.data_,
3559 _audioFrame.num_channels_,
3560 fileBuffer.get(),
3561 1,
3562 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003563 }
3564 else
3565 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003566 // Replace ACM audio with file.
3567 // Currently file stream is always mono.
3568 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003569 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003570 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003571 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003572 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003573 mixingFrequency,
3574 AudioFrame::kNormalSpeech,
3575 AudioFrame::kVadUnknown,
3576 1);
3577
3578 }
3579 return 0;
3580}
3581
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003582int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003583Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003584 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003585{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003586 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003587
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003588 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003589 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003590
3591 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003592 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003593
3594 if (_outputFilePlayerPtr == NULL)
3595 {
3596 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3597 VoEId(_instanceId, _channelId),
3598 "Channel::MixAudioWithFile() file mixing failed");
3599 return -1;
3600 }
3601
3602 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003603 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003604 fileSamples,
3605 mixingFrequency) == -1)
3606 {
3607 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3608 VoEId(_instanceId, _channelId),
3609 "Channel::MixAudioWithFile() file mixing failed");
3610 return -1;
3611 }
3612 }
3613
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003614 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003615 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003616 // Currently file stream is always mono.
3617 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003618 MixWithSat(audioFrame.data_,
3619 audioFrame.num_channels_,
3620 fileBuffer.get(),
3621 1,
3622 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003623 }
3624 else
3625 {
3626 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003627 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3628 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003629 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003630 return -1;
3631 }
3632
3633 return 0;
3634}
3635
3636int
3637Channel::InsertInbandDtmfTone()
3638{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003639 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003640 if (_inbandDtmfQueue.PendingDtmf() &&
3641 !_inbandDtmfGenerator.IsAddingTone() &&
3642 _inbandDtmfGenerator.DelaySinceLastTone() >
3643 kMinTelephoneEventSeparationMs)
3644 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003645 int8_t eventCode(0);
3646 uint16_t lengthMs(0);
3647 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003648
3649 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3650 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3651 if (_playInbandDtmfEvent)
3652 {
3653 // Add tone to output mixer using a reduced length to minimize
3654 // risk of echo.
3655 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3656 attenuationDb);
3657 }
3658 }
3659
3660 if (_inbandDtmfGenerator.IsAddingTone())
3661 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003662 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003663 _inbandDtmfGenerator.GetSampleRate(frequency);
3664
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003665 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003666 {
3667 // Update sample rate of Dtmf tone since the mixing frequency
3668 // has changed.
3669 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003670 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003671 // Reset the tone to be added taking the new sample rate into
3672 // account.
3673 _inbandDtmfGenerator.ResetTone();
3674 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003675
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003676 int16_t toneBuffer[320];
3677 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003678 // Get 10ms tone segment and set time since last tone to zero
3679 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3680 {
3681 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3682 VoEId(_instanceId, _channelId),
3683 "Channel::EncodeAndSend() inserting Dtmf failed");
3684 return -1;
3685 }
3686
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003687 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003688 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003689 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003690 sample++)
3691 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003692 for (int channel = 0;
3693 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003694 channel++)
3695 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003696 const size_t index =
3697 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003698 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003699 }
3700 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003701
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003702 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003703 } else
3704 {
3705 // Add 10ms to "delay-since-last-tone" counter
3706 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3707 }
3708 return 0;
3709}
3710
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003711int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003712Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003713{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003714 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003715 if (_transportPtr == NULL)
3716 {
3717 return -1;
3718 }
3719 if (!RTCP)
3720 {
Peter Boströmac547a62015-09-17 23:03:57 +02003721 return _transportPtr->SendPacket(data, len);
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 }
3723 else
3724 {
Peter Boströmac547a62015-09-17 23:03:57 +02003725 return _transportPtr->SendRTCPPacket(data, len);
niklase@google.com470e71d2011-07-07 08:21:25 +00003726 }
3727}
3728
deadbeef74375882015-08-13 12:09:10 -07003729void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3730 uint32_t playout_timestamp = 0;
3731
3732 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3733 // This can happen if this channel has not been received any RTP packet. In
3734 // this case, NetEq is not capable of computing playout timestamp.
3735 return;
3736 }
3737
3738 uint16_t delay_ms = 0;
3739 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3740 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3741 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3742 " delay from the ADM");
3743 _engineStatisticsPtr->SetLastError(
3744 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3745 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3746 return;
3747 }
3748
3749 jitter_buffer_playout_timestamp_ = playout_timestamp;
3750
3751 // Remove the playout delay.
3752 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3753
3754 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3755 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3756 playout_timestamp);
3757
3758 {
3759 CriticalSectionScoped cs(video_sync_lock_.get());
3760 if (rtcp) {
3761 playout_timestamp_rtcp_ = playout_timestamp;
3762 } else {
3763 playout_timestamp_rtp_ = playout_timestamp;
3764 }
3765 playout_delay_ms_ = delay_ms;
3766 }
3767}
3768
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003769// Called for incoming RTP packets after successful RTP header parsing.
3770void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3771 uint16_t sequence_number) {
3772 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3773 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3774 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003775
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003776 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003777 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003778
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003779 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3780 // every incoming packet.
3781 uint32_t timestamp_diff_ms = (rtp_timestamp -
3782 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003783 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3784 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3785 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3786 // timestamp, the resulting difference is negative, but is set to zero.
3787 // This can happen when a network glitch causes a packet to arrive late,
3788 // and during long comfort noise periods with clock drift.
3789 timestamp_diff_ms = 0;
3790 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003791
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003792 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3793 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003794
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003795 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003796
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003797 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003798
deadbeef74375882015-08-13 12:09:10 -07003799 {
3800 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003801
deadbeef74375882015-08-13 12:09:10 -07003802 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3803 _recPacketDelayMs = packet_delay_ms;
3804 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003805
deadbeef74375882015-08-13 12:09:10 -07003806 if (_average_jitter_buffer_delay_us == 0) {
3807 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3808 return;
3809 }
3810
3811 // Filter average delay value using exponential filter (alpha is
3812 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3813 // risk of rounding error) and compensate for it in GetDelayEstimate()
3814 // later.
3815 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3816 1000 * timestamp_diff_ms + 500) / 8;
3817 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003818}
3819
3820void
3821Channel::RegisterReceiveCodecsToRTPModule()
3822{
3823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3824 "Channel::RegisterReceiveCodecsToRTPModule()");
3825
niklase@google.com470e71d2011-07-07 08:21:25 +00003826 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003827 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003828
3829 for (int idx = 0; idx < nSupportedCodecs; idx++)
3830 {
3831 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003832 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003833 (rtp_receiver_->RegisterReceivePayload(
3834 codec.plname,
3835 codec.pltype,
3836 codec.plfreq,
3837 codec.channels,
3838 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003839 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003840 WEBRTC_TRACE(kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00003841 kTraceVoice,
3842 VoEId(_instanceId, _channelId),
3843 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3844 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
3845 codec.plname, codec.pltype, codec.plfreq,
3846 codec.channels, codec.rate);
3847 }
3848 else
3849 {
Peter Boströmd5c75b12015-09-23 13:24:32 +02003850 WEBRTC_TRACE(kTraceInfo,
niklase@google.com470e71d2011-07-07 08:21:25 +00003851 kTraceVoice,
3852 VoEId(_instanceId, _channelId),
3853 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003854 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003855 "receiver",
3856 codec.plname, codec.pltype, codec.plfreq,
3857 codec.channels, codec.rate);
3858 }
3859 }
3860}
3861
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003862// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003863int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003864 CodecInst codec;
3865 bool found_red = false;
3866
3867 // Get default RED settings from the ACM database
3868 const int num_codecs = AudioCodingModule::NumberOfCodecs();
3869 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003870 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003871 if (!STR_CASE_CMP(codec.plname, "RED")) {
3872 found_red = true;
3873 break;
3874 }
3875 }
3876
3877 if (!found_red) {
3878 _engineStatisticsPtr->SetLastError(
3879 VE_CODEC_ERROR, kTraceError,
3880 "SetRedPayloadType() RED is not supported");
3881 return -1;
3882 }
3883
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00003884 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003885 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003886 _engineStatisticsPtr->SetLastError(
3887 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3888 "SetRedPayloadType() RED registration in ACM module failed");
3889 return -1;
3890 }
3891
3892 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
3893 _engineStatisticsPtr->SetLastError(
3894 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3895 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
3896 return -1;
3897 }
3898 return 0;
3899}
3900
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003901int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
3902 unsigned char id) {
3903 int error = 0;
3904 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
3905 if (enable) {
3906 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
3907 }
3908 return error;
3909}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003910
wu@webrtc.org94454b72014-06-05 20:34:08 +00003911int32_t Channel::GetPlayoutFrequency() {
3912 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
3913 CodecInst current_recive_codec;
3914 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
3915 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3916 // Even though the actual sampling rate for G.722 audio is
3917 // 16,000 Hz, the RTP clock rate for the G722 payload format is
3918 // 8,000 Hz because that value was erroneously assigned in
3919 // RFC 1890 and must remain unchanged for backward compatibility.
3920 playout_frequency = 8000;
3921 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3922 // We are resampling Opus internally to 32,000 Hz until all our
3923 // DSP routines can operate at 48,000 Hz, but the RTP clock
3924 // rate for the Opus payload format is standardized to 48,000 Hz,
3925 // because that is the maximum supported decoding sampling rate.
3926 playout_frequency = 48000;
3927 }
3928 }
3929 return playout_frequency;
3930}
3931
Minyue2013aec2015-05-13 14:14:42 +02003932int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003933 RTCPMethod method = _rtpRtcpModule->RTCP();
3934 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003935 return 0;
3936 }
3937 std::vector<RTCPReportBlock> report_blocks;
3938 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02003939
3940 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003941 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02003942 if (allow_associate_channel) {
3943 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3944 Channel* channel = associate_send_channel_.channel();
3945 // Tries to get RTT from an associated channel. This is important for
3946 // receive-only channels.
3947 if (channel) {
3948 // To prevent infinite recursion and deadlock, calling GetRTT of
3949 // associate channel should always use "false" for argument:
3950 // |allow_associate_channel|.
3951 rtt = channel->GetRTT(false);
3952 }
3953 }
3954 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003955 }
3956
3957 uint32_t remoteSSRC = rtp_receiver_->SSRC();
3958 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
3959 for (; it != report_blocks.end(); ++it) {
3960 if (it->remoteSSRC == remoteSSRC)
3961 break;
3962 }
3963 if (it == report_blocks.end()) {
3964 // We have not received packets with SSRC matching the report blocks.
3965 // To calculate RTT we try with the SSRC of the first report block.
3966 // This is very important for send-only channels where we don't know
3967 // the SSRC of the other end.
3968 remoteSSRC = report_blocks[0].remoteSSRC;
3969 }
Minyue2013aec2015-05-13 14:14:42 +02003970
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003971 int64_t avg_rtt = 0;
3972 int64_t max_rtt= 0;
3973 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003974 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
3975 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003976 return 0;
3977 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003978 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003979}
3980
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00003981} // namespace voe
3982} // namespace webrtc