blob: 9038d6bf56bab02cd951adaa2e96dbd0b2c80d70 [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
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000015#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000016#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000017#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020018#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000019#include "webrtc/modules/audio_device/include/audio_device.h"
20#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000021#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000022#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
23#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
24#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
25#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000026#include "webrtc/modules/utility/interface/audio_frame_operations.h"
27#include "webrtc/modules/utility/interface/process_thread.h"
28#include "webrtc/modules/utility/interface/rtp_dump.h"
29#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 void ResetStatistics() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 stats_ = ChannelStatistics();
81 }
82
83 ChannelStatistics GetStats() {
84 CriticalSectionScoped cs(stats_lock_.get());
85 return stats_;
86 }
87
88 private:
89 // StatisticsUpdated calls are triggered from threads in the RTP module,
90 // while GetStats calls can be triggered from the public voice engine API,
91 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000092 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000093 const uint32_t ssrc_;
94 ChannelStatistics stats_;
95};
96
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000097class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000098 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000099 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
100 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000101
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000102 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
103 // Not used for Voice Engine.
104 }
105
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000106 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
107 int64_t rtt,
108 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000109 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
110 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
111 // report for VoiceEngine?
112 if (report_blocks.empty())
113 return;
114
115 int fraction_lost_aggregate = 0;
116 int total_number_of_packets = 0;
117
118 // If receiving multiple report blocks, calculate the weighted average based
119 // on the number of packets a report refers to.
120 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
121 block_it != report_blocks.end(); ++block_it) {
122 // Find the previous extended high sequence number for this remote SSRC,
123 // to calculate the number of RTP packets this report refers to. Ignore if
124 // we haven't seen this SSRC before.
125 std::map<uint32_t, uint32_t>::iterator seq_num_it =
126 extended_max_sequence_number_.find(block_it->sourceSSRC);
127 int number_of_packets = 0;
128 if (seq_num_it != extended_max_sequence_number_.end()) {
129 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
130 }
131 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
132 total_number_of_packets += number_of_packets;
133
134 extended_max_sequence_number_[block_it->sourceSSRC] =
135 block_it->extendedHighSeqNum;
136 }
137 int weighted_fraction_lost = 0;
138 if (total_number_of_packets > 0) {
139 weighted_fraction_lost = (fraction_lost_aggregate +
140 total_number_of_packets / 2) / total_number_of_packets;
141 }
142 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000143 }
144
145 private:
146 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000147 // Maps remote side ssrc to extended highest sequence number received.
148 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000149};
150
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000152Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000153 uint8_t payloadType,
154 uint32_t timeStamp,
155 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000156 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 const RTPFragmentationHeader* fragmentation)
158{
159 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
160 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000161 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
162 frameType, payloadType, timeStamp,
163 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
165 if (_includeAudioLevelIndication)
166 {
167 // Store current audio level in the RTP/RTCP module.
168 // The level will be used in combination with voice-activity state
169 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000170 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 }
172
173 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
174 // packetization.
175 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000176 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 payloadType,
178 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000179 // Leaving the time when this frame was
180 // received from the capture device as
181 // undefined for voice for now.
182 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 payloadData,
184 payloadSize,
185 fragmentation) == -1)
186 {
187 _engineStatisticsPtr->SetLastError(
188 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
189 "Channel::SendData() failed to send data to RTP/RTCP module");
190 return -1;
191 }
192
193 _lastLocalTimeStamp = timeStamp;
194 _lastPayloadType = payloadType;
195
196 return 0;
197}
198
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000199int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000200Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000201{
202 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000203 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000204
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000205 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000206 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000207 return 0;
208}
209
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000210int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000211Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000212{
213 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
214 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
215
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000216 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 if (_rxVadObserverPtr)
218 {
219 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
220 }
221
222 return 0;
223}
224
225int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000226Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000227{
228 channel = VoEChannelId(channel);
229 assert(channel == _channelId);
230
231 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000232 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
233 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000234
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000235 CriticalSectionScoped cs(&_callbackCritSect);
236
niklase@google.com470e71d2011-07-07 08:21:25 +0000237 if (_transportPtr == NULL)
238 {
239 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
240 "Channel::SendPacket() failed to send RTP packet due to"
241 " invalid transport object");
242 return -1;
243 }
244
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000245 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000246 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000247
248 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000249 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 {
251 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
252 VoEId(_instanceId,_channelId),
253 "Channel::SendPacket() RTP dump to output file failed");
254 }
255
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000256 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
257 bufferLength);
258 if (n < 0) {
259 std::string transport_name =
260 _externalTransport ? "external transport" : "WebRtc sockets";
261 WEBRTC_TRACE(kTraceError, kTraceVoice,
262 VoEId(_instanceId,_channelId),
263 "Channel::SendPacket() RTP transmission using %s failed",
264 transport_name.c_str());
265 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000267 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000268}
269
270int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000271Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000272{
273 channel = VoEChannelId(channel);
274 assert(channel == _channelId);
275
276 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000277 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
278 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000279
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000280 CriticalSectionScoped cs(&_callbackCritSect);
281 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000282 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000283 WEBRTC_TRACE(kTraceError, kTraceVoice,
284 VoEId(_instanceId,_channelId),
285 "Channel::SendRTCPPacket() failed to send RTCP packet"
286 " due to invalid transport object");
287 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000288 }
289
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000290 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000291 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000292
293 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000294 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 {
296 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
297 VoEId(_instanceId,_channelId),
298 "Channel::SendPacket() RTCP dump to output file failed");
299 }
300
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000301 int n = _transportPtr->SendRTCPPacket(channel,
302 bufferToSendPtr,
303 bufferLength);
304 if (n < 0) {
305 std::string transport_name =
306 _externalTransport ? "external transport" : "WebRtc sockets";
307 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
308 VoEId(_instanceId,_channelId),
309 "Channel::SendRTCPPacket() transmission using %s failed",
310 transport_name.c_str());
311 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000313 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000314}
315
316void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000317Channel::OnPlayTelephoneEvent(int32_t id,
318 uint8_t event,
319 uint16_t lengthMs,
320 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000321{
322 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
323 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000324 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000325
326 if (!_playOutbandDtmfEvent || (event > 15))
327 {
328 // Ignore callback since feedback is disabled or event is not a
329 // Dtmf tone event.
330 return;
331 }
332
333 assert(_outputMixerPtr != NULL);
334
335 // Start playing out the Dtmf tone (if playout is enabled).
336 // Reduce length of tone with 80ms to the reduce risk of echo.
337 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
338}
339
340void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000341Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000342{
343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
344 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000345 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000346
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000347 // Update ssrc so that NTP for AV sync can be updated.
348 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000349}
350
pbos@webrtc.org92135212013-05-14 08:31:39 +0000351void Channel::OnIncomingCSRCChanged(int32_t id,
352 uint32_t CSRC,
353 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000354{
355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
356 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
357 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000358}
359
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000360void Channel::ResetStatistics(uint32_t ssrc) {
361 StreamStatistician* statistician =
362 rtp_receive_statistics_->GetStatistician(ssrc);
363 if (statistician) {
364 statistician->ResetStatistics();
365 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000366 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000367}
368
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000369int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000370Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000371 int32_t id,
372 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000373 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000374 int frequency,
375 uint8_t channels,
376 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000377{
378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
379 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
380 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
381 id, payloadType, payloadName, frequency, channels, rate);
382
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000383 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000384
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000385 CodecInst receiveCodec = {0};
386 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000387
388 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 receiveCodec.plfreq = frequency;
390 receiveCodec.channels = channels;
391 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000392 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000393
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000394 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000395 receiveCodec.pacsize = dummyCodec.pacsize;
396
397 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000398 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000399 {
400 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000401 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 "Channel::OnInitializeDecoder() invalid codec ("
403 "pt=%d, name=%s) received - 1", payloadType, payloadName);
404 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
405 return -1;
406 }
407
408 return 0;
409}
410
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000411int32_t
412Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000413 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 const WebRtcRTPHeader* rtpHeader)
415{
416 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000417 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 " payloadType=%u, audioChannel=%u)",
419 payloadSize,
420 rtpHeader->header.payloadType,
421 rtpHeader->type.Audio.channel);
422
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000423 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 {
425 // Avoid inserting into NetEQ when we are not playing. Count the
426 // packet as discarded.
427 WEBRTC_TRACE(kTraceStream, kTraceVoice,
428 VoEId(_instanceId, _channelId),
429 "received packet is discarded since playing is not"
430 " activated");
431 _numberOfDiscardedPackets++;
432 return 0;
433 }
434
435 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000436 if (audio_coding_->IncomingPacket(payloadData,
437 payloadSize,
438 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 {
440 _engineStatisticsPtr->SetLastError(
441 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
442 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
443 return -1;
444 }
445
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000446 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 UpdatePacketDelay(rtpHeader->header.timestamp,
448 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000449
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000450 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000451 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
452 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000453
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000454 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000455 round_trip_time);
456 if (!nack_list.empty()) {
457 // Can't use nack_list.data() since it's not supported by all
458 // compilers.
459 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000460 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000461 return 0;
462}
463
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000464bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000465 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000466 RTPHeader header;
467 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
468 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
469 "IncomingPacket invalid RTP header");
470 return false;
471 }
472 header.payload_type_frequency =
473 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
474 if (header.payload_type_frequency < 0)
475 return false;
476 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
477}
478
pbos@webrtc.org92135212013-05-14 08:31:39 +0000479int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000480{
481 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
482 "Channel::GetAudioFrame(id=%d)", id);
483
484 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000485 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
486 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 {
488 WEBRTC_TRACE(kTraceError, kTraceVoice,
489 VoEId(_instanceId,_channelId),
490 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000491 // In all likelihood, the audio in this frame is garbage. We return an
492 // error so that the audio mixer module doesn't add it to the mix. As
493 // a result, it won't be played out and the actions skipped here are
494 // irrelevant.
495 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 }
497
498 if (_RxVadDetection)
499 {
500 UpdateRxVadDetection(audioFrame);
501 }
502
503 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000504 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000506 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000507
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000508 ChannelState::State state = channel_state_.Get();
509
510 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000511 int err = rx_audioproc_->ProcessStream(&audioFrame);
512 if (err) {
513 LOG(LS_ERROR) << "ProcessStream() error: " << err;
514 assert(false);
515 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 }
517
wu@webrtc.org63420662013-10-17 18:28:55 +0000518 float output_gain = 1.0f;
519 float left_pan = 1.0f;
520 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000522 CriticalSectionScoped cs(&volume_settings_critsect_);
523 output_gain = _outputGain;
524 left_pan = _panLeft;
525 right_pan= _panRight;
526 }
527
528 // Output volume scaling
529 if (output_gain < 0.99f || output_gain > 1.01f)
530 {
531 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000532 }
533
534 // Scale left and/or right channel(s) if stereo and master balance is
535 // active
536
wu@webrtc.org63420662013-10-17 18:28:55 +0000537 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000539 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 {
541 // Emulate stereo mode since panning is active.
542 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000543 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 }
545 // For true stereo mode (when we are receiving a stereo signal), no
546 // action is needed.
547
548 // Do the panning operation (the audio frame contains stereo at this
549 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000550 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000551 }
552
553 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000554 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000556 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000557 }
558
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 // External media
560 if (_outputExternalMedia)
561 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000562 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000563 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000564 if (_outputExternalMediaCallbackPtr)
565 {
566 _outputExternalMediaCallbackPtr->Process(
567 _channelId,
568 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000569 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000570 audioFrame.samples_per_channel_,
571 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000572 isStereo);
573 }
574 }
575
576 // Record playout if enabled
577 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000578 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000579
580 if (_outputFileRecording && _outputFileRecorderPtr)
581 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000582 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }
584 }
585
586 // Measure audio level (0-9)
587 _outputAudioLevel.ComputeLevel(audioFrame);
588
wu@webrtc.org94454b72014-06-05 20:34:08 +0000589 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
590 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000591 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000592 }
593
594 if (capture_start_rtp_time_stamp_ >= 0) {
595 // audioFrame.timestamp_ should be valid from now on.
596
597 // Compute elapsed time.
598 int64_t unwrap_timestamp =
599 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
600 audioFrame.elapsed_time_ms_ =
601 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
602 (GetPlayoutFrequency() / 1000);
603
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000604 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000605 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000606 // Compute ntp time.
607 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
608 audioFrame.timestamp_);
609 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
610 if (audioFrame.ntp_time_ms_ > 0) {
611 // Compute |capture_start_ntp_time_ms_| so that
612 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
613 capture_start_ntp_time_ms_ =
614 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
615 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000616 }
617 }
618
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 return 0;
620}
621
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000622int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000623Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000624{
625 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
626 "Channel::NeededFrequency(id=%d)", id);
627
628 int highestNeeded = 0;
629
630 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000631 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000632
633 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000634 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000636 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 }
638 else
639 {
640 highestNeeded = receiveFrequency;
641 }
642
643 // Special case, if we're playing a file on the playout side
644 // we take that frequency into consideration as well
645 // This is not needed on sending side, since the codec will
646 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000647 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000649 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000650 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 {
652 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
653 {
654 highestNeeded=_outputFilePlayerPtr->Frequency();
655 }
656 }
657 }
658
659 return(highestNeeded);
660}
661
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000662int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000663Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000664 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000665 uint32_t instanceId,
666 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000667{
668 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
669 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
670 channelId, instanceId);
671
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000672 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 if (channel == NULL)
674 {
675 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
676 VoEId(instanceId,channelId),
677 "Channel::CreateChannel() unable to allocate memory for"
678 " channel");
679 return -1;
680 }
681 return 0;
682}
683
684void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000685Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000686{
687 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
688 "Channel::PlayNotification(id=%d, durationMs=%d)",
689 id, durationMs);
690
691 // Not implement yet
692}
693
694void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000695Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000696{
697 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
698 "Channel::RecordNotification(id=%d, durationMs=%d)",
699 id, durationMs);
700
701 // Not implement yet
702}
703
704void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000705Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000706{
707 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
708 "Channel::PlayFileEnded(id=%d)", id);
709
710 if (id == _inputFilePlayerId)
711 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000712 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000713 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
714 VoEId(_instanceId,_channelId),
715 "Channel::PlayFileEnded() => input file player module is"
716 " shutdown");
717 }
718 else if (id == _outputFilePlayerId)
719 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000720 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000721 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
722 VoEId(_instanceId,_channelId),
723 "Channel::PlayFileEnded() => output file player module is"
724 " shutdown");
725 }
726}
727
728void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000729Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000730{
731 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
732 "Channel::RecordFileEnded(id=%d)", id);
733
734 assert(id == _outputFileRecorderId);
735
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000736 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000737
738 _outputFileRecording = false;
739 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
740 VoEId(_instanceId,_channelId),
741 "Channel::RecordFileEnded() => output file recorder module is"
742 " shutdown");
743}
744
pbos@webrtc.org92135212013-05-14 08:31:39 +0000745Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000746 uint32_t instanceId,
747 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
749 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000750 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000751 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000752 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000753 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000754 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000755 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000756 rtp_receive_statistics_(ReceiveStatistics::Create(
757 Clock::GetRealTimeClock())),
758 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
759 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
760 this, this, rtp_payload_registry_.get())),
761 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000762 _rtpDumpIn(*RtpDump::CreateRtpDump()),
763 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000764 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 _inputFilePlayerPtr(NULL),
767 _outputFilePlayerPtr(NULL),
768 _outputFileRecorderPtr(NULL),
769 // Avoid conflict with other channels by adding 1024 - 1026,
770 // won't use as much as 1024 channels.
771 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
772 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
773 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000774 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000775 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
776 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 _inputExternalMediaCallbackPtr(NULL),
779 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000780 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
781 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000782 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000783 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000784 playout_timestamp_rtp_(0),
785 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000786 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000787 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000788 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000789 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000790 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
791 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000792 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000793 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000794 _outputMixerPtr(NULL),
795 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000796 _moduleProcessThreadPtr(NULL),
797 _audioDeviceModulePtr(NULL),
798 _voiceEngineObserverPtr(NULL),
799 _callbackCritSectPtr(NULL),
800 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000801 _rxVadObserverPtr(NULL),
802 _oldVadDecision(-1),
803 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000804 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000805 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 _mute(false),
807 _panLeft(1.0f),
808 _panRight(1.0f),
809 _outputGain(1.0f),
810 _playOutbandDtmfEvent(false),
811 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 _lastLocalTimeStamp(0),
813 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000814 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000816 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000817 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000818 _previousTimestamp(0),
819 _recPacketDelayMs(20),
820 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000821 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000822 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000823 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000824 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200825 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
826 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
827 associate_send_channel_(ChannelOwner(nullptr))
niklase@google.com470e71d2011-07-07 08:21:25 +0000828{
829 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
830 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200831 AudioCodingModule::Config acm_config;
832 acm_config.id = VoEModuleId(instanceId, channelId);
833 if (config.Get<NetEqCapacityConfig>().enabled) {
834 // Clamping the buffer capacity at 20 packets. While going lower will
835 // probably work, it makes little sense.
836 acm_config.neteq_config.max_packets_in_buffer =
837 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
838 }
839 audio_coding_.reset(AudioCodingModule::Create(acm_config));
840
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 _inbandDtmfQueue.ResetDtmf();
842 _inbandDtmfGenerator.Init();
843 _outputAudioLevel.Clear();
844
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000845 RtpRtcp::Configuration configuration;
846 configuration.id = VoEModuleId(instanceId, channelId);
847 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000848 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000849 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000850 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000851 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000852
853 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000854
855 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
856 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
857 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000858
859 Config audioproc_config;
860 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
861 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000862}
863
864Channel::~Channel()
865{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000866 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
868 "Channel::~Channel() - dtor");
869
870 if (_outputExternalMedia)
871 {
872 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
873 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000874 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 {
876 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
877 }
878 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 StopPlayout();
880
881 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000882 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 if (_inputFilePlayerPtr)
884 {
885 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
886 _inputFilePlayerPtr->StopPlayingFile();
887 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
888 _inputFilePlayerPtr = NULL;
889 }
890 if (_outputFilePlayerPtr)
891 {
892 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
893 _outputFilePlayerPtr->StopPlayingFile();
894 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
895 _outputFilePlayerPtr = NULL;
896 }
897 if (_outputFileRecorderPtr)
898 {
899 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
900 _outputFileRecorderPtr->StopRecording();
901 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
902 _outputFileRecorderPtr = NULL;
903 }
904 }
905
906 // The order to safely shutdown modules in a channel is:
907 // 1. De-register callbacks in modules
908 // 2. De-register modules in process thread
909 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000910 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 {
912 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
913 VoEId(_instanceId,_channelId),
914 "~Channel() failed to de-register transport callback"
915 " (Audio coding module)");
916 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000917 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 {
919 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
920 VoEId(_instanceId,_channelId),
921 "~Channel() failed to de-register VAD callback"
922 " (Audio coding module)");
923 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000925 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
926
niklase@google.com470e71d2011-07-07 08:21:25 +0000927 // End of modules shutdown
928
929 // Delete other objects
930 RtpDump::DestroyRtpDump(&_rtpDumpIn);
931 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000934 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000935}
936
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000937int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000938Channel::Init()
939{
940 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
941 "Channel::Init()");
942
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000943 channel_state_.Reset();
944
niklase@google.com470e71d2011-07-07 08:21:25 +0000945 // --- Initial sanity
946
947 if ((_engineStatisticsPtr == NULL) ||
948 (_moduleProcessThreadPtr == NULL))
949 {
950 WEBRTC_TRACE(kTraceError, kTraceVoice,
951 VoEId(_instanceId,_channelId),
952 "Channel::Init() must call SetEngineInformation() first");
953 return -1;
954 }
955
956 // --- Add modules to process thread (for periodic schedulation)
957
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000958 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
959
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000960 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000961
Henrik Lundin45c64492015-03-30 19:00:44 +0200962 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000963#ifdef WEBRTC_CODEC_AVT
964 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200965 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000966#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200967 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 {
969 _engineStatisticsPtr->SetLastError(
970 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
971 "Channel::Init() unable to initialize the ACM - 1");
972 return -1;
973 }
974
975 // --- RTP/RTCP module initialization
976
977 // Ensure that RTCP is enabled by default for the created channel.
978 // Note that, the module will keep generating RTCP until it is explicitly
979 // disabled by the user.
980 // After StopListen (when no sockets exists), RTCP packets will no longer
981 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000982 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
983 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000984 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
985 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000986 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000987 (audio_coding_->RegisterTransportCallback(this) == -1) ||
988 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000989
990 if (fail)
991 {
992 _engineStatisticsPtr->SetLastError(
993 VE_CANNOT_INIT_CHANNEL, kTraceError,
994 "Channel::Init() callbacks not registered");
995 return -1;
996 }
997
998 // --- Register all supported codecs to the receiving side of the
999 // RTP/RTCP module
1000
1001 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001002 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001003
1004 for (int idx = 0; idx < nSupportedCodecs; idx++)
1005 {
1006 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001007 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001008 (rtp_receiver_->RegisterReceivePayload(
1009 codec.plname,
1010 codec.pltype,
1011 codec.plfreq,
1012 codec.channels,
1013 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001014 {
1015 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1016 VoEId(_instanceId,_channelId),
1017 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1018 "to RTP/RTCP receiver",
1019 codec.plname, codec.pltype, codec.plfreq,
1020 codec.channels, codec.rate);
1021 }
1022 else
1023 {
1024 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1025 VoEId(_instanceId,_channelId),
1026 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1027 "the RTP/RTCP receiver",
1028 codec.plname, codec.pltype, codec.plfreq,
1029 codec.channels, codec.rate);
1030 }
1031
1032 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001033 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 {
1035 SetSendCodec(codec);
1036 }
1037
1038 // Register default PT for outband 'telephone-event'
1039 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1040 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001041 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001042 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
1044 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1045 VoEId(_instanceId,_channelId),
1046 "Channel::Init() failed to register outband "
1047 "'telephone-event' (%d/%d) correctly",
1048 codec.pltype, codec.plfreq);
1049 }
1050 }
1051
1052 if (!STR_CASE_CMP(codec.plname, "CN"))
1053 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001054 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1055 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001056 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 {
1058 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1059 VoEId(_instanceId,_channelId),
1060 "Channel::Init() failed to register CN (%d/%d) "
1061 "correctly - 1",
1062 codec.pltype, codec.plfreq);
1063 }
1064 }
1065#ifdef WEBRTC_CODEC_RED
1066 // Register RED to the receiving side of the ACM.
1067 // We will not receive an OnInitializeDecoder() callback for RED.
1068 if (!STR_CASE_CMP(codec.plname, "RED"))
1069 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001070 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001071 {
1072 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1073 VoEId(_instanceId,_channelId),
1074 "Channel::Init() failed to register RED (%d/%d) "
1075 "correctly",
1076 codec.pltype, codec.plfreq);
1077 }
1078 }
1079#endif
1080 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001081
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001082 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1083 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1084 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001086 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1087 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1088 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001089 }
1090
1091 return 0;
1092}
1093
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001094int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001095Channel::SetEngineInformation(Statistics& engineStatistics,
1096 OutputMixer& outputMixer,
1097 voe::TransmitMixer& transmitMixer,
1098 ProcessThread& moduleProcessThread,
1099 AudioDeviceModule& audioDeviceModule,
1100 VoiceEngineObserver* voiceEngineObserver,
1101 CriticalSectionWrapper* callbackCritSect)
1102{
1103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1104 "Channel::SetEngineInformation()");
1105 _engineStatisticsPtr = &engineStatistics;
1106 _outputMixerPtr = &outputMixer;
1107 _transmitMixerPtr = &transmitMixer,
1108 _moduleProcessThreadPtr = &moduleProcessThread;
1109 _audioDeviceModulePtr = &audioDeviceModule;
1110 _voiceEngineObserverPtr = voiceEngineObserver;
1111 _callbackCritSectPtr = callbackCritSect;
1112 return 0;
1113}
1114
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001115int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001116Channel::UpdateLocalTimeStamp()
1117{
1118
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001119 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 return 0;
1121}
1122
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001123int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001124Channel::StartPlayout()
1125{
1126 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1127 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001128 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 {
1130 return 0;
1131 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001132
1133 if (!_externalMixing) {
1134 // Add participant as candidates for mixing.
1135 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1136 {
1137 _engineStatisticsPtr->SetLastError(
1138 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1139 "StartPlayout() failed to add participant to mixer");
1140 return -1;
1141 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 }
1143
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001144 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001145 if (RegisterFilePlayingToMixer() != 0)
1146 return -1;
1147
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 return 0;
1149}
1150
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001151int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001152Channel::StopPlayout()
1153{
1154 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1155 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001156 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 {
1158 return 0;
1159 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001160
1161 if (!_externalMixing) {
1162 // Remove participant as candidates for mixing
1163 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1164 {
1165 _engineStatisticsPtr->SetLastError(
1166 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1167 "StopPlayout() failed to remove participant from mixer");
1168 return -1;
1169 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 }
1171
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001172 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001173 _outputAudioLevel.Clear();
1174
1175 return 0;
1176}
1177
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001178int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001179Channel::StartSend()
1180{
1181 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1182 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001183 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001184 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001185 if (send_sequence_number_)
1186 SetInitSequenceNumber(send_sequence_number_);
1187
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001190 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001192 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001193
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001194 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 {
1196 _engineStatisticsPtr->SetLastError(
1197 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1198 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001199 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001200 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 return -1;
1202 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001203
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::StopSend()
1209{
1210 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1211 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001212 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001214 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001216 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001217
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001218 // Store the sequence number to be able to pick up the same sequence for
1219 // the next StartSend(). This is needed for restarting device, otherwise
1220 // it might cause libSRTP to complain about packets being replayed.
1221 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1222 // CL is landed. See issue
1223 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1224 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1225
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 // Reset sending SSRC and sequence number and triggers direct transmission
1227 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001228 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1229 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 {
1231 _engineStatisticsPtr->SetLastError(
1232 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1233 "StartSend() RTP/RTCP failed to stop sending");
1234 }
1235
niklase@google.com470e71d2011-07-07 08:21:25 +00001236 return 0;
1237}
1238
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001239int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001240Channel::StartReceiving()
1241{
1242 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1243 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001244 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001245 {
1246 return 0;
1247 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001248 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001249 _numberOfDiscardedPackets = 0;
1250 return 0;
1251}
1252
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001253int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001254Channel::StopReceiving()
1255{
1256 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1257 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001258 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001259 {
1260 return 0;
1261 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001262
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001263 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001264 return 0;
1265}
1266
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001267int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001268Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1269{
1270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1271 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001272 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001273
1274 if (_voiceEngineObserverPtr)
1275 {
1276 _engineStatisticsPtr->SetLastError(
1277 VE_INVALID_OPERATION, kTraceError,
1278 "RegisterVoiceEngineObserver() observer already enabled");
1279 return -1;
1280 }
1281 _voiceEngineObserverPtr = &observer;
1282 return 0;
1283}
1284
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001285int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001286Channel::DeRegisterVoiceEngineObserver()
1287{
1288 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1289 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001290 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001291
1292 if (!_voiceEngineObserverPtr)
1293 {
1294 _engineStatisticsPtr->SetLastError(
1295 VE_INVALID_OPERATION, kTraceWarning,
1296 "DeRegisterVoiceEngineObserver() observer already disabled");
1297 return 0;
1298 }
1299 _voiceEngineObserverPtr = NULL;
1300 return 0;
1301}
1302
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001303int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001304Channel::GetSendCodec(CodecInst& codec)
1305{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001306 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001307}
1308
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001309int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001310Channel::GetRecCodec(CodecInst& codec)
1311{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001312 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001313}
1314
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001315int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001316Channel::SetSendCodec(const CodecInst& codec)
1317{
1318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1319 "Channel::SetSendCodec()");
1320
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001321 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001322 {
1323 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1324 "SetSendCodec() failed to register codec to ACM");
1325 return -1;
1326 }
1327
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001328 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001329 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001330 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1331 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001332 {
1333 WEBRTC_TRACE(
1334 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1335 "SetSendCodec() failed to register codec to"
1336 " RTP/RTCP module");
1337 return -1;
1338 }
1339 }
1340
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001341 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001342 {
1343 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1344 "SetSendCodec() failed to set audio packet size");
1345 return -1;
1346 }
1347
1348 return 0;
1349}
1350
Ivo Creusenadf89b72015-04-29 16:03:33 +02001351void Channel::SetBitRate(int bitrate_bps) {
1352 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1353 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1354 audio_coding_->SetBitRate(bitrate_bps);
1355}
1356
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001357void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001358 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001359 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1360
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001361 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001362 if (audio_coding_->SetPacketLossRate(
1363 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001364 assert(false); // This should not happen.
1365 }
1366}
1367
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001368int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001369Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1370{
1371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1372 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001373 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001374 // To disable VAD, DTX must be disabled too
1375 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001376 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001377 {
1378 _engineStatisticsPtr->SetLastError(
1379 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1380 "SetVADStatus() failed to set VAD");
1381 return -1;
1382 }
1383 return 0;
1384}
1385
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001386int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001387Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1388{
1389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1390 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001391 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001392 {
1393 _engineStatisticsPtr->SetLastError(
1394 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1395 "GetVADStatus() failed to get VAD status");
1396 return -1;
1397 }
1398 disabledDTX = !disabledDTX;
1399 return 0;
1400}
1401
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001402int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001403Channel::SetRecPayloadType(const CodecInst& codec)
1404{
1405 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1406 "Channel::SetRecPayloadType()");
1407
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001408 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 {
1410 _engineStatisticsPtr->SetLastError(
1411 VE_ALREADY_PLAYING, kTraceError,
1412 "SetRecPayloadType() unable to set PT while playing");
1413 return -1;
1414 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001415 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 {
1417 _engineStatisticsPtr->SetLastError(
1418 VE_ALREADY_LISTENING, kTraceError,
1419 "SetRecPayloadType() unable to set PT while listening");
1420 return -1;
1421 }
1422
1423 if (codec.pltype == -1)
1424 {
1425 // De-register the selected codec (RTP/RTCP module and ACM)
1426
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001427 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001428 CodecInst rxCodec = codec;
1429
1430 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001431 rtp_payload_registry_->ReceivePayloadType(
1432 rxCodec.plname,
1433 rxCodec.plfreq,
1434 rxCodec.channels,
1435 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1436 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001437 rxCodec.pltype = pltype;
1438
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001439 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 {
1441 _engineStatisticsPtr->SetLastError(
1442 VE_RTP_RTCP_MODULE_ERROR,
1443 kTraceError,
1444 "SetRecPayloadType() RTP/RTCP-module deregistration "
1445 "failed");
1446 return -1;
1447 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001448 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
1450 _engineStatisticsPtr->SetLastError(
1451 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1452 "SetRecPayloadType() ACM deregistration failed - 1");
1453 return -1;
1454 }
1455 return 0;
1456 }
1457
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001458 if (rtp_receiver_->RegisterReceivePayload(
1459 codec.plname,
1460 codec.pltype,
1461 codec.plfreq,
1462 codec.channels,
1463 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 {
1465 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001466 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1467 if (rtp_receiver_->RegisterReceivePayload(
1468 codec.plname,
1469 codec.pltype,
1470 codec.plfreq,
1471 codec.channels,
1472 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 {
1474 _engineStatisticsPtr->SetLastError(
1475 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1476 "SetRecPayloadType() RTP/RTCP-module registration failed");
1477 return -1;
1478 }
1479 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001480 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001482 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1483 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001484 {
1485 _engineStatisticsPtr->SetLastError(
1486 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1487 "SetRecPayloadType() ACM registration failed - 1");
1488 return -1;
1489 }
1490 }
1491 return 0;
1492}
1493
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001494int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001495Channel::GetRecPayloadType(CodecInst& codec)
1496{
1497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1498 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001499 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001500 if (rtp_payload_registry_->ReceivePayloadType(
1501 codec.plname,
1502 codec.plfreq,
1503 codec.channels,
1504 (codec.rate < 0) ? 0 : codec.rate,
1505 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 {
1507 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001508 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001509 "GetRecPayloadType() failed to retrieve RX payload type");
1510 return -1;
1511 }
1512 codec.pltype = payloadType;
1513 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001514 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001515 return 0;
1516}
1517
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001518int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001519Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1520{
1521 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1522 "Channel::SetSendCNPayloadType()");
1523
1524 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001525 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001526 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 if (frequency == kFreq32000Hz)
1528 samplingFreqHz = 32000;
1529 else if (frequency == kFreq16000Hz)
1530 samplingFreqHz = 16000;
1531
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001532 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001533 {
1534 _engineStatisticsPtr->SetLastError(
1535 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1536 "SetSendCNPayloadType() failed to retrieve default CN codec "
1537 "settings");
1538 return -1;
1539 }
1540
1541 // Modify the payload type (must be set to dynamic range)
1542 codec.pltype = type;
1543
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001544 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001545 {
1546 _engineStatisticsPtr->SetLastError(
1547 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1548 "SetSendCNPayloadType() failed to register CN to ACM");
1549 return -1;
1550 }
1551
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001552 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001553 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001554 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1555 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001556 {
1557 _engineStatisticsPtr->SetLastError(
1558 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1559 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1560 "module");
1561 return -1;
1562 }
1563 }
1564 return 0;
1565}
1566
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001567int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001569 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001570
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001571 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001572 _engineStatisticsPtr->SetLastError(
1573 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001574 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001575 return -1;
1576 }
1577 return 0;
1578}
1579
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001580int Channel::SetOpusDtx(bool enable_dtx) {
1581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1582 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001583 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001584 : audio_coding_->DisableOpusDtx();
1585 if (ret != 0) {
1586 _engineStatisticsPtr->SetLastError(
1587 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1588 return -1;
1589 }
1590 return 0;
1591}
1592
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001593int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001594{
1595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1596 "Channel::RegisterExternalTransport()");
1597
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001598 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001599
niklase@google.com470e71d2011-07-07 08:21:25 +00001600 if (_externalTransport)
1601 {
1602 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1603 kTraceError,
1604 "RegisterExternalTransport() external transport already enabled");
1605 return -1;
1606 }
1607 _externalTransport = true;
1608 _transportPtr = &transport;
1609 return 0;
1610}
1611
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001612int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001613Channel::DeRegisterExternalTransport()
1614{
1615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1616 "Channel::DeRegisterExternalTransport()");
1617
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001618 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001619
niklase@google.com470e71d2011-07-07 08:21:25 +00001620 if (!_transportPtr)
1621 {
1622 _engineStatisticsPtr->SetLastError(
1623 VE_INVALID_OPERATION, kTraceWarning,
1624 "DeRegisterExternalTransport() external transport already "
1625 "disabled");
1626 return 0;
1627 }
1628 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001629 _transportPtr = NULL;
1630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1631 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001632 return 0;
1633}
1634
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001635int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001636 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001637 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1638 "Channel::ReceivedRTPPacket()");
1639
1640 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001641 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001642
1643 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001644 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1645 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001646 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1647 VoEId(_instanceId,_channelId),
1648 "Channel::SendPacket() RTP dump to input file failed");
1649 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001650 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001651 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001652 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1653 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1654 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001655 return -1;
1656 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001657 header.payload_type_frequency =
1658 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001659 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001660 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001661 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001662 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001663 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001664 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001665
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001666 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001667}
1668
1669bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001670 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001671 const RTPHeader& header,
1672 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001673 if (rtp_payload_registry_->IsRtx(header)) {
1674 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001675 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001676 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001677 assert(packet_length >= header.headerLength);
1678 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001679 PayloadUnion payload_specific;
1680 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001681 &payload_specific)) {
1682 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001683 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001684 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1685 payload_specific, in_order);
1686}
1687
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001688bool Channel::HandleRtxPacket(const uint8_t* packet,
1689 size_t packet_length,
1690 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001691 if (!rtp_payload_registry_->IsRtx(header))
1692 return false;
1693
1694 // Remove the RTX header and parse the original RTP header.
1695 if (packet_length < header.headerLength)
1696 return false;
1697 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1698 return false;
1699 if (restored_packet_in_use_) {
1700 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1701 "Multiple RTX headers detected, dropping packet");
1702 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001703 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001704 uint8_t* restored_packet_ptr = restored_packet_;
1705 if (!rtp_payload_registry_->RestoreOriginalPacket(
1706 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1707 header)) {
1708 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1709 "Incoming RTX packet: invalid RTP header");
1710 return false;
1711 }
1712 restored_packet_in_use_ = true;
1713 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1714 restored_packet_in_use_ = false;
1715 return ret;
1716}
1717
1718bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1719 StreamStatistician* statistician =
1720 rtp_receive_statistics_->GetStatistician(header.ssrc);
1721 if (!statistician)
1722 return false;
1723 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001724}
1725
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001726bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1727 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001728 // Retransmissions are handled separately if RTX is enabled.
1729 if (rtp_payload_registry_->RtxEnabled())
1730 return false;
1731 StreamStatistician* statistician =
1732 rtp_receive_statistics_->GetStatistician(header.ssrc);
1733 if (!statistician)
1734 return false;
1735 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001736 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001737 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001738 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001739 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001740}
1741
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001742int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001743 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1744 "Channel::ReceivedRTCPPacket()");
1745 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001746 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001747
1748 // Dump the RTCP packet to a file (if RTP dump is enabled).
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001749 if (_rtpDumpIn.DumpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001750 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1751 VoEId(_instanceId,_channelId),
1752 "Channel::SendPacket() RTCP dump to input file failed");
1753 }
1754
1755 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001756 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001757 _engineStatisticsPtr->SetLastError(
1758 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1759 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1760 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001761
Minyue2013aec2015-05-13 14:14:42 +02001762 int64_t rtt = GetRTT(true);
1763 if (rtt == 0) {
1764 // Waiting for valid RTT.
1765 return 0;
1766 }
1767 uint32_t ntp_secs = 0;
1768 uint32_t ntp_frac = 0;
1769 uint32_t rtp_timestamp = 0;
1770 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1771 &rtp_timestamp)) {
1772 // Waiting for RTCP.
1773 return 0;
1774 }
1775
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001776 {
1777 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001778 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001779 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001780 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001781}
1782
niklase@google.com470e71d2011-07-07 08:21:25 +00001783int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001784 bool loop,
1785 FileFormats format,
1786 int startPosition,
1787 float volumeScaling,
1788 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001789 const CodecInst* codecInst)
1790{
1791 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1792 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1793 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1794 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1795 startPosition, stopPosition);
1796
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001797 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001798 {
1799 _engineStatisticsPtr->SetLastError(
1800 VE_ALREADY_PLAYING, kTraceError,
1801 "StartPlayingFileLocally() is already playing");
1802 return -1;
1803 }
1804
niklase@google.com470e71d2011-07-07 08:21:25 +00001805 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001806 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001807
1808 if (_outputFilePlayerPtr)
1809 {
1810 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1811 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1812 _outputFilePlayerPtr = NULL;
1813 }
1814
1815 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1816 _outputFilePlayerId, (const FileFormats)format);
1817
1818 if (_outputFilePlayerPtr == NULL)
1819 {
1820 _engineStatisticsPtr->SetLastError(
1821 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001822 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001823 return -1;
1824 }
1825
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001826 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001827
1828 if (_outputFilePlayerPtr->StartPlayingFile(
1829 fileName,
1830 loop,
1831 startPosition,
1832 volumeScaling,
1833 notificationTime,
1834 stopPosition,
1835 (const CodecInst*)codecInst) != 0)
1836 {
1837 _engineStatisticsPtr->SetLastError(
1838 VE_BAD_FILE, kTraceError,
1839 "StartPlayingFile() failed to start file playout");
1840 _outputFilePlayerPtr->StopPlayingFile();
1841 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1842 _outputFilePlayerPtr = NULL;
1843 return -1;
1844 }
1845 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001846 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001847 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001848
1849 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001850 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001851
1852 return 0;
1853}
1854
1855int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001856 FileFormats format,
1857 int startPosition,
1858 float volumeScaling,
1859 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001860 const CodecInst* codecInst)
1861{
1862 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1863 "Channel::StartPlayingFileLocally(format=%d,"
1864 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1865 format, volumeScaling, startPosition, stopPosition);
1866
1867 if(stream == NULL)
1868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_BAD_FILE, kTraceError,
1871 "StartPlayingFileLocally() NULL as input stream");
1872 return -1;
1873 }
1874
1875
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001876 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001877 {
1878 _engineStatisticsPtr->SetLastError(
1879 VE_ALREADY_PLAYING, kTraceError,
1880 "StartPlayingFileLocally() is already playing");
1881 return -1;
1882 }
1883
niklase@google.com470e71d2011-07-07 08:21:25 +00001884 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001885 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001886
1887 // Destroy the old instance
1888 if (_outputFilePlayerPtr)
1889 {
1890 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1891 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1892 _outputFilePlayerPtr = NULL;
1893 }
1894
1895 // Create the instance
1896 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1897 _outputFilePlayerId,
1898 (const FileFormats)format);
1899
1900 if (_outputFilePlayerPtr == NULL)
1901 {
1902 _engineStatisticsPtr->SetLastError(
1903 VE_INVALID_ARGUMENT, kTraceError,
1904 "StartPlayingFileLocally() filePlayer format isnot correct");
1905 return -1;
1906 }
1907
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001908 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001909
1910 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1911 volumeScaling,
1912 notificationTime,
1913 stopPosition, codecInst) != 0)
1914 {
1915 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1916 "StartPlayingFile() failed to "
1917 "start file playout");
1918 _outputFilePlayerPtr->StopPlayingFile();
1919 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1920 _outputFilePlayerPtr = NULL;
1921 return -1;
1922 }
1923 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001924 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001925 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001926
1927 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001928 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001929
niklase@google.com470e71d2011-07-07 08:21:25 +00001930 return 0;
1931}
1932
1933int Channel::StopPlayingFileLocally()
1934{
1935 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1936 "Channel::StopPlayingFileLocally()");
1937
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001938 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001939 {
1940 _engineStatisticsPtr->SetLastError(
1941 VE_INVALID_OPERATION, kTraceWarning,
1942 "StopPlayingFileLocally() isnot playing");
1943 return 0;
1944 }
1945
niklase@google.com470e71d2011-07-07 08:21:25 +00001946 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001947 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001948
1949 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1950 {
1951 _engineStatisticsPtr->SetLastError(
1952 VE_STOP_RECORDING_FAILED, kTraceError,
1953 "StopPlayingFile() could not stop playing");
1954 return -1;
1955 }
1956 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1957 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1958 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001959 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001960 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001961 // _fileCritSect cannot be taken while calling
1962 // SetAnonymousMixibilityStatus. Refer to comments in
1963 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001964 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1965 {
1966 _engineStatisticsPtr->SetLastError(
1967 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001968 "StopPlayingFile() failed to stop participant from playing as"
1969 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001970 return -1;
1971 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001972
1973 return 0;
1974}
1975
1976int Channel::IsPlayingFileLocally() const
1977{
1978 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1979 "Channel::IsPlayingFileLocally()");
1980
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001981 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001982}
1983
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001984int Channel::RegisterFilePlayingToMixer()
1985{
1986 // Return success for not registering for file playing to mixer if:
1987 // 1. playing file before playout is started on that channel.
1988 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001989 if (!channel_state_.Get().playing ||
1990 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001991 {
1992 return 0;
1993 }
1994
1995 // |_fileCritSect| cannot be taken while calling
1996 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1997 // frames can be pulled by the mixer. Since the frames are generated from
1998 // the file, _fileCritSect will be taken. This would result in a deadlock.
1999 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2000 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002001 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002002 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002003 _engineStatisticsPtr->SetLastError(
2004 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2005 "StartPlayingFile() failed to add participant as file to mixer");
2006 _outputFilePlayerPtr->StopPlayingFile();
2007 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2008 _outputFilePlayerPtr = NULL;
2009 return -1;
2010 }
2011
2012 return 0;
2013}
2014
niklase@google.com470e71d2011-07-07 08:21:25 +00002015int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002016 bool loop,
2017 FileFormats format,
2018 int startPosition,
2019 float volumeScaling,
2020 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 const CodecInst* codecInst)
2022{
2023 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2024 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2025 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2026 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2027 startPosition, stopPosition);
2028
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002029 CriticalSectionScoped cs(&_fileCritSect);
2030
2031 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 {
2033 _engineStatisticsPtr->SetLastError(
2034 VE_ALREADY_PLAYING, kTraceWarning,
2035 "StartPlayingFileAsMicrophone() filePlayer is playing");
2036 return 0;
2037 }
2038
niklase@google.com470e71d2011-07-07 08:21:25 +00002039 // Destroy the old instance
2040 if (_inputFilePlayerPtr)
2041 {
2042 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2043 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2044 _inputFilePlayerPtr = NULL;
2045 }
2046
2047 // Create the instance
2048 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2049 _inputFilePlayerId, (const FileFormats)format);
2050
2051 if (_inputFilePlayerPtr == NULL)
2052 {
2053 _engineStatisticsPtr->SetLastError(
2054 VE_INVALID_ARGUMENT, kTraceError,
2055 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2056 return -1;
2057 }
2058
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002059 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002060
2061 if (_inputFilePlayerPtr->StartPlayingFile(
2062 fileName,
2063 loop,
2064 startPosition,
2065 volumeScaling,
2066 notificationTime,
2067 stopPosition,
2068 (const CodecInst*)codecInst) != 0)
2069 {
2070 _engineStatisticsPtr->SetLastError(
2071 VE_BAD_FILE, kTraceError,
2072 "StartPlayingFile() failed to start file playout");
2073 _inputFilePlayerPtr->StopPlayingFile();
2074 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2075 _inputFilePlayerPtr = NULL;
2076 return -1;
2077 }
2078 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002079 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002080
2081 return 0;
2082}
2083
2084int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002085 FileFormats format,
2086 int startPosition,
2087 float volumeScaling,
2088 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002089 const CodecInst* codecInst)
2090{
2091 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2092 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2093 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2094 format, volumeScaling, startPosition, stopPosition);
2095
2096 if(stream == NULL)
2097 {
2098 _engineStatisticsPtr->SetLastError(
2099 VE_BAD_FILE, kTraceError,
2100 "StartPlayingFileAsMicrophone NULL as input stream");
2101 return -1;
2102 }
2103
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002104 CriticalSectionScoped cs(&_fileCritSect);
2105
2106 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002107 {
2108 _engineStatisticsPtr->SetLastError(
2109 VE_ALREADY_PLAYING, kTraceWarning,
2110 "StartPlayingFileAsMicrophone() is playing");
2111 return 0;
2112 }
2113
niklase@google.com470e71d2011-07-07 08:21:25 +00002114 // Destroy the old instance
2115 if (_inputFilePlayerPtr)
2116 {
2117 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2118 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2119 _inputFilePlayerPtr = NULL;
2120 }
2121
2122 // Create the instance
2123 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2124 _inputFilePlayerId, (const FileFormats)format);
2125
2126 if (_inputFilePlayerPtr == NULL)
2127 {
2128 _engineStatisticsPtr->SetLastError(
2129 VE_INVALID_ARGUMENT, kTraceError,
2130 "StartPlayingInputFile() filePlayer format isnot correct");
2131 return -1;
2132 }
2133
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002134 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002135
2136 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2137 volumeScaling, notificationTime,
2138 stopPosition, codecInst) != 0)
2139 {
2140 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2141 "StartPlayingFile() failed to start "
2142 "file playout");
2143 _inputFilePlayerPtr->StopPlayingFile();
2144 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2145 _inputFilePlayerPtr = NULL;
2146 return -1;
2147 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002148
niklase@google.com470e71d2011-07-07 08:21:25 +00002149 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002150 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002151
2152 return 0;
2153}
2154
2155int Channel::StopPlayingFileAsMicrophone()
2156{
2157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2158 "Channel::StopPlayingFileAsMicrophone()");
2159
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002160 CriticalSectionScoped cs(&_fileCritSect);
2161
2162 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002163 {
2164 _engineStatisticsPtr->SetLastError(
2165 VE_INVALID_OPERATION, kTraceWarning,
2166 "StopPlayingFileAsMicrophone() isnot playing");
2167 return 0;
2168 }
2169
niklase@google.com470e71d2011-07-07 08:21:25 +00002170 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2171 {
2172 _engineStatisticsPtr->SetLastError(
2173 VE_STOP_RECORDING_FAILED, kTraceError,
2174 "StopPlayingFile() could not stop playing");
2175 return -1;
2176 }
2177 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2178 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2179 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002180 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002181
2182 return 0;
2183}
2184
2185int Channel::IsPlayingFileAsMicrophone() const
2186{
2187 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2188 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002189 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002190}
2191
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002192int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002193 const CodecInst* codecInst)
2194{
2195 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2196 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2197
2198 if (_outputFileRecording)
2199 {
2200 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2201 "StartRecordingPlayout() is already recording");
2202 return 0;
2203 }
2204
2205 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002206 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002207 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2208
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002209 if ((codecInst != NULL) &&
2210 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002211 {
2212 _engineStatisticsPtr->SetLastError(
2213 VE_BAD_ARGUMENT, kTraceError,
2214 "StartRecordingPlayout() invalid compression");
2215 return(-1);
2216 }
2217 if(codecInst == NULL)
2218 {
2219 format = kFileFormatPcm16kHzFile;
2220 codecInst=&dummyCodec;
2221 }
2222 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2223 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2224 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2225 {
2226 format = kFileFormatWavFile;
2227 }
2228 else
2229 {
2230 format = kFileFormatCompressedFile;
2231 }
2232
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002233 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002234
2235 // Destroy the old instance
2236 if (_outputFileRecorderPtr)
2237 {
2238 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2239 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2240 _outputFileRecorderPtr = NULL;
2241 }
2242
2243 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2244 _outputFileRecorderId, (const FileFormats)format);
2245 if (_outputFileRecorderPtr == NULL)
2246 {
2247 _engineStatisticsPtr->SetLastError(
2248 VE_INVALID_ARGUMENT, kTraceError,
2249 "StartRecordingPlayout() fileRecorder format isnot correct");
2250 return -1;
2251 }
2252
2253 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2254 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2255 {
2256 _engineStatisticsPtr->SetLastError(
2257 VE_BAD_FILE, kTraceError,
2258 "StartRecordingAudioFile() failed to start file recording");
2259 _outputFileRecorderPtr->StopRecording();
2260 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2261 _outputFileRecorderPtr = NULL;
2262 return -1;
2263 }
2264 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2265 _outputFileRecording = true;
2266
2267 return 0;
2268}
2269
2270int Channel::StartRecordingPlayout(OutStream* stream,
2271 const CodecInst* codecInst)
2272{
2273 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2274 "Channel::StartRecordingPlayout()");
2275
2276 if (_outputFileRecording)
2277 {
2278 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2279 "StartRecordingPlayout() is already recording");
2280 return 0;
2281 }
2282
2283 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002284 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002285 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2286
2287 if (codecInst != NULL && codecInst->channels != 1)
2288 {
2289 _engineStatisticsPtr->SetLastError(
2290 VE_BAD_ARGUMENT, kTraceError,
2291 "StartRecordingPlayout() invalid compression");
2292 return(-1);
2293 }
2294 if(codecInst == NULL)
2295 {
2296 format = kFileFormatPcm16kHzFile;
2297 codecInst=&dummyCodec;
2298 }
2299 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2300 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2301 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2302 {
2303 format = kFileFormatWavFile;
2304 }
2305 else
2306 {
2307 format = kFileFormatCompressedFile;
2308 }
2309
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002310 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002311
2312 // Destroy the old instance
2313 if (_outputFileRecorderPtr)
2314 {
2315 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2316 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2317 _outputFileRecorderPtr = NULL;
2318 }
2319
2320 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2321 _outputFileRecorderId, (const FileFormats)format);
2322 if (_outputFileRecorderPtr == NULL)
2323 {
2324 _engineStatisticsPtr->SetLastError(
2325 VE_INVALID_ARGUMENT, kTraceError,
2326 "StartRecordingPlayout() fileRecorder format isnot correct");
2327 return -1;
2328 }
2329
2330 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2331 notificationTime) != 0)
2332 {
2333 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2334 "StartRecordingPlayout() failed to "
2335 "start file recording");
2336 _outputFileRecorderPtr->StopRecording();
2337 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2338 _outputFileRecorderPtr = NULL;
2339 return -1;
2340 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002341
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2343 _outputFileRecording = true;
2344
2345 return 0;
2346}
2347
2348int Channel::StopRecordingPlayout()
2349{
2350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2351 "Channel::StopRecordingPlayout()");
2352
2353 if (!_outputFileRecording)
2354 {
2355 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2356 "StopRecordingPlayout() isnot recording");
2357 return -1;
2358 }
2359
2360
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002361 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002362
2363 if (_outputFileRecorderPtr->StopRecording() != 0)
2364 {
2365 _engineStatisticsPtr->SetLastError(
2366 VE_STOP_RECORDING_FAILED, kTraceError,
2367 "StopRecording() could not stop recording");
2368 return(-1);
2369 }
2370 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2371 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2372 _outputFileRecorderPtr = NULL;
2373 _outputFileRecording = false;
2374
2375 return 0;
2376}
2377
2378void
2379Channel::SetMixWithMicStatus(bool mix)
2380{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002381 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002382 _mixFileWithMicrophone=mix;
2383}
2384
2385int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002386Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002387{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002388 int8_t currentLevel = _outputAudioLevel.Level();
2389 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002390 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2391 VoEId(_instanceId,_channelId),
2392 "GetSpeechOutputLevel() => level=%u", level);
2393 return 0;
2394}
2395
2396int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002397Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002398{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002399 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2400 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002401 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2402 VoEId(_instanceId,_channelId),
2403 "GetSpeechOutputLevelFullRange() => level=%u", level);
2404 return 0;
2405}
2406
2407int
2408Channel::SetMute(bool enable)
2409{
wu@webrtc.org63420662013-10-17 18:28:55 +00002410 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002411 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2412 "Channel::SetMute(enable=%d)", enable);
2413 _mute = enable;
2414 return 0;
2415}
2416
2417bool
2418Channel::Mute() const
2419{
wu@webrtc.org63420662013-10-17 18:28:55 +00002420 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002421 return _mute;
2422}
2423
2424int
2425Channel::SetOutputVolumePan(float left, float right)
2426{
wu@webrtc.org63420662013-10-17 18:28:55 +00002427 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002428 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2429 "Channel::SetOutputVolumePan()");
2430 _panLeft = left;
2431 _panRight = right;
2432 return 0;
2433}
2434
2435int
2436Channel::GetOutputVolumePan(float& left, float& right) const
2437{
wu@webrtc.org63420662013-10-17 18:28:55 +00002438 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002439 left = _panLeft;
2440 right = _panRight;
2441 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2442 VoEId(_instanceId,_channelId),
2443 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2444 return 0;
2445}
2446
2447int
2448Channel::SetChannelOutputVolumeScaling(float scaling)
2449{
wu@webrtc.org63420662013-10-17 18:28:55 +00002450 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2452 "Channel::SetChannelOutputVolumeScaling()");
2453 _outputGain = scaling;
2454 return 0;
2455}
2456
2457int
2458Channel::GetChannelOutputVolumeScaling(float& scaling) const
2459{
wu@webrtc.org63420662013-10-17 18:28:55 +00002460 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002461 scaling = _outputGain;
2462 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2463 VoEId(_instanceId,_channelId),
2464 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2465 return 0;
2466}
2467
niklase@google.com470e71d2011-07-07 08:21:25 +00002468int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002469 int lengthMs, int attenuationDb,
2470 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002471{
2472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2473 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2474 playDtmfEvent);
2475
2476 _playOutbandDtmfEvent = playDtmfEvent;
2477
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002478 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002479 attenuationDb) != 0)
2480 {
2481 _engineStatisticsPtr->SetLastError(
2482 VE_SEND_DTMF_FAILED,
2483 kTraceWarning,
2484 "SendTelephoneEventOutband() failed to send event");
2485 return -1;
2486 }
2487 return 0;
2488}
2489
2490int Channel::SendTelephoneEventInband(unsigned char eventCode,
2491 int lengthMs,
2492 int attenuationDb,
2493 bool playDtmfEvent)
2494{
2495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2496 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2497 playDtmfEvent);
2498
2499 _playInbandDtmfEvent = playDtmfEvent;
2500 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2501
2502 return 0;
2503}
2504
2505int
niklase@google.com470e71d2011-07-07 08:21:25 +00002506Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2507{
2508 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2509 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002510 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002511 {
2512 _engineStatisticsPtr->SetLastError(
2513 VE_INVALID_ARGUMENT, kTraceError,
2514 "SetSendTelephoneEventPayloadType() invalid type");
2515 return -1;
2516 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002517 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002518 codec.plfreq = 8000;
2519 codec.pltype = type;
2520 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002521 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002522 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002523 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2524 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2525 _engineStatisticsPtr->SetLastError(
2526 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2527 "SetSendTelephoneEventPayloadType() failed to register send"
2528 "payload type");
2529 return -1;
2530 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002531 }
2532 _sendTelephoneEventPayloadType = type;
2533 return 0;
2534}
2535
2536int
2537Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2538{
2539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2540 "Channel::GetSendTelephoneEventPayloadType()");
2541 type = _sendTelephoneEventPayloadType;
2542 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2543 VoEId(_instanceId,_channelId),
2544 "GetSendTelephoneEventPayloadType() => type=%u", type);
2545 return 0;
2546}
2547
niklase@google.com470e71d2011-07-07 08:21:25 +00002548int
2549Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2550{
2551 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2552 "Channel::UpdateRxVadDetection()");
2553
2554 int vadDecision = 1;
2555
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002556 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002557
2558 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2559 {
2560 OnRxVadDetected(vadDecision);
2561 _oldVadDecision = vadDecision;
2562 }
2563
2564 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2565 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2566 vadDecision);
2567 return 0;
2568}
2569
2570int
2571Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2572{
2573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2574 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002575 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002576
2577 if (_rxVadObserverPtr)
2578 {
2579 _engineStatisticsPtr->SetLastError(
2580 VE_INVALID_OPERATION, kTraceError,
2581 "RegisterRxVadObserver() observer already enabled");
2582 return -1;
2583 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002584 _rxVadObserverPtr = &observer;
2585 _RxVadDetection = true;
2586 return 0;
2587}
2588
2589int
2590Channel::DeRegisterRxVadObserver()
2591{
2592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2593 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002594 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002595
2596 if (!_rxVadObserverPtr)
2597 {
2598 _engineStatisticsPtr->SetLastError(
2599 VE_INVALID_OPERATION, kTraceWarning,
2600 "DeRegisterRxVadObserver() observer already disabled");
2601 return 0;
2602 }
2603 _rxVadObserverPtr = NULL;
2604 _RxVadDetection = false;
2605 return 0;
2606}
2607
2608int
2609Channel::VoiceActivityIndicator(int &activity)
2610{
2611 activity = _sendFrameType;
2612
2613 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002614 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002615 return 0;
2616}
2617
2618#ifdef WEBRTC_VOICE_ENGINE_AGC
2619
2620int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002621Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002622{
2623 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2624 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2625 (int)enable, (int)mode);
2626
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002627 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002628 switch (mode)
2629 {
2630 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002631 break;
2632 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002633 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002634 break;
2635 case kAgcFixedDigital:
2636 agcMode = GainControl::kFixedDigital;
2637 break;
2638 case kAgcAdaptiveDigital:
2639 agcMode =GainControl::kAdaptiveDigital;
2640 break;
2641 default:
2642 _engineStatisticsPtr->SetLastError(
2643 VE_INVALID_ARGUMENT, kTraceError,
2644 "SetRxAgcStatus() invalid Agc mode");
2645 return -1;
2646 }
2647
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002648 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002649 {
2650 _engineStatisticsPtr->SetLastError(
2651 VE_APM_ERROR, kTraceError,
2652 "SetRxAgcStatus() failed to set Agc mode");
2653 return -1;
2654 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002655 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002656 {
2657 _engineStatisticsPtr->SetLastError(
2658 VE_APM_ERROR, kTraceError,
2659 "SetRxAgcStatus() failed to set Agc state");
2660 return -1;
2661 }
2662
2663 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002664 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002665
2666 return 0;
2667}
2668
2669int
2670Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2671{
2672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2673 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2674
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002675 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002676 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002677 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002678
2679 enabled = enable;
2680
2681 switch (agcMode)
2682 {
2683 case GainControl::kFixedDigital:
2684 mode = kAgcFixedDigital;
2685 break;
2686 case GainControl::kAdaptiveDigital:
2687 mode = kAgcAdaptiveDigital;
2688 break;
2689 default:
2690 _engineStatisticsPtr->SetLastError(
2691 VE_APM_ERROR, kTraceError,
2692 "GetRxAgcStatus() invalid Agc mode");
2693 return -1;
2694 }
2695
2696 return 0;
2697}
2698
2699int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002700Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002701{
2702 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2703 "Channel::SetRxAgcConfig()");
2704
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002705 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002706 config.targetLeveldBOv) != 0)
2707 {
2708 _engineStatisticsPtr->SetLastError(
2709 VE_APM_ERROR, kTraceError,
2710 "SetRxAgcConfig() failed to set target peak |level|"
2711 "(or envelope) of the Agc");
2712 return -1;
2713 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002714 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002715 config.digitalCompressionGaindB) != 0)
2716 {
2717 _engineStatisticsPtr->SetLastError(
2718 VE_APM_ERROR, kTraceError,
2719 "SetRxAgcConfig() failed to set the range in |gain| the"
2720 " digital compression stage may apply");
2721 return -1;
2722 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002723 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002724 config.limiterEnable) != 0)
2725 {
2726 _engineStatisticsPtr->SetLastError(
2727 VE_APM_ERROR, kTraceError,
2728 "SetRxAgcConfig() failed to set hard limiter to the signal");
2729 return -1;
2730 }
2731
2732 return 0;
2733}
2734
2735int
2736Channel::GetRxAgcConfig(AgcConfig& config)
2737{
2738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2739 "Channel::GetRxAgcConfig(config=%?)");
2740
2741 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002742 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002743 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002744 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002745 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002746 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002747
2748 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2749 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2750 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2751 " limiterEnable=%d",
2752 config.targetLeveldBOv,
2753 config.digitalCompressionGaindB,
2754 config.limiterEnable);
2755
2756 return 0;
2757}
2758
2759#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2760
2761#ifdef WEBRTC_VOICE_ENGINE_NR
2762
2763int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002764Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002765{
2766 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2767 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2768 (int)enable, (int)mode);
2769
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002770 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002771 switch (mode)
2772 {
2773
2774 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002775 break;
2776 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002777 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002778 break;
2779 case kNsConference:
2780 nsLevel = NoiseSuppression::kHigh;
2781 break;
2782 case kNsLowSuppression:
2783 nsLevel = NoiseSuppression::kLow;
2784 break;
2785 case kNsModerateSuppression:
2786 nsLevel = NoiseSuppression::kModerate;
2787 break;
2788 case kNsHighSuppression:
2789 nsLevel = NoiseSuppression::kHigh;
2790 break;
2791 case kNsVeryHighSuppression:
2792 nsLevel = NoiseSuppression::kVeryHigh;
2793 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002794 }
2795
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002796 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 != 0)
2798 {
2799 _engineStatisticsPtr->SetLastError(
2800 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002801 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 return -1;
2803 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002804 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002805 {
2806 _engineStatisticsPtr->SetLastError(
2807 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002808 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002809 return -1;
2810 }
2811
2812 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002813 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002814
2815 return 0;
2816}
2817
2818int
2819Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2820{
2821 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2822 "Channel::GetRxNsStatus(enable=?, mode=?)");
2823
2824 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002825 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002826 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002827 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002828
2829 enabled = enable;
2830
2831 switch (ncLevel)
2832 {
2833 case NoiseSuppression::kLow:
2834 mode = kNsLowSuppression;
2835 break;
2836 case NoiseSuppression::kModerate:
2837 mode = kNsModerateSuppression;
2838 break;
2839 case NoiseSuppression::kHigh:
2840 mode = kNsHighSuppression;
2841 break;
2842 case NoiseSuppression::kVeryHigh:
2843 mode = kNsVeryHighSuppression;
2844 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002845 }
2846
2847 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2848 VoEId(_instanceId,_channelId),
2849 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2850 return 0;
2851}
2852
2853#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2854
2855int
niklase@google.com470e71d2011-07-07 08:21:25 +00002856Channel::SetLocalSSRC(unsigned int ssrc)
2857{
2858 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2859 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002860 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002861 {
2862 _engineStatisticsPtr->SetLastError(
2863 VE_ALREADY_SENDING, kTraceError,
2864 "SetLocalSSRC() already sending");
2865 return -1;
2866 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002867 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002868 return 0;
2869}
2870
2871int
2872Channel::GetLocalSSRC(unsigned int& ssrc)
2873{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002874 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002875 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2876 VoEId(_instanceId,_channelId),
2877 "GetLocalSSRC() => ssrc=%lu", ssrc);
2878 return 0;
2879}
2880
2881int
2882Channel::GetRemoteSSRC(unsigned int& ssrc)
2883{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002884 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002885 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2886 VoEId(_instanceId,_channelId),
2887 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2888 return 0;
2889}
2890
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002891int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002892 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002893 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002894}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002895
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002896int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2897 unsigned char id) {
2898 rtp_header_parser_->DeregisterRtpHeaderExtension(
2899 kRtpExtensionAudioLevel);
2900 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2901 kRtpExtensionAudioLevel, id)) {
2902 return -1;
2903 }
2904 return 0;
2905}
2906
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002907int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2908 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2909}
2910
2911int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2912 rtp_header_parser_->DeregisterRtpHeaderExtension(
2913 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002914 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2915 kRtpExtensionAbsoluteSendTime, id)) {
2916 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002917 }
2918 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002919}
2920
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002921void Channel::SetRTCPStatus(bool enable) {
2922 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2923 "Channel::SetRTCPStatus()");
2924 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002925}
2926
2927int
2928Channel::GetRTCPStatus(bool& enabled)
2929{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002930 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002931 enabled = (method != kRtcpOff);
2932 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2933 VoEId(_instanceId,_channelId),
2934 "GetRTCPStatus() => enabled=%d", enabled);
2935 return 0;
2936}
2937
2938int
2939Channel::SetRTCP_CNAME(const char cName[256])
2940{
2941 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2942 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002943 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002944 {
2945 _engineStatisticsPtr->SetLastError(
2946 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2947 "SetRTCP_CNAME() failed to set RTCP CNAME");
2948 return -1;
2949 }
2950 return 0;
2951}
2952
2953int
niklase@google.com470e71d2011-07-07 08:21:25 +00002954Channel::GetRemoteRTCP_CNAME(char cName[256])
2955{
2956 if (cName == NULL)
2957 {
2958 _engineStatisticsPtr->SetLastError(
2959 VE_INVALID_ARGUMENT, kTraceError,
2960 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2961 return -1;
2962 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002963 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002964 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002965 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002966 {
2967 _engineStatisticsPtr->SetLastError(
2968 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2969 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2970 return -1;
2971 }
2972 strcpy(cName, cname);
2973 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2974 VoEId(_instanceId, _channelId),
2975 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2976 return 0;
2977}
2978
2979int
2980Channel::GetRemoteRTCPData(
2981 unsigned int& NTPHigh,
2982 unsigned int& NTPLow,
2983 unsigned int& timestamp,
2984 unsigned int& playoutTimestamp,
2985 unsigned int* jitter,
2986 unsigned short* fractionLost)
2987{
2988 // --- Information from sender info in received Sender Reports
2989
2990 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002991 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002992 {
2993 _engineStatisticsPtr->SetLastError(
2994 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002995 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002996 "side");
2997 return -1;
2998 }
2999
3000 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3001 // and octet count)
3002 NTPHigh = senderInfo.NTPseconds;
3003 NTPLow = senderInfo.NTPfraction;
3004 timestamp = senderInfo.RTPtimeStamp;
3005
3006 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3007 VoEId(_instanceId, _channelId),
3008 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3009 "timestamp=%lu",
3010 NTPHigh, NTPLow, timestamp);
3011
3012 // --- Locally derived information
3013
3014 // This value is updated on each incoming RTCP packet (0 when no packet
3015 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003016 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003017
3018 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3019 VoEId(_instanceId, _channelId),
3020 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003021 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003022
3023 if (NULL != jitter || NULL != fractionLost)
3024 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003025 // Get all RTCP receiver report blocks that have been received on this
3026 // channel. If we receive RTP packets from a remote source we know the
3027 // remote SSRC and use the report block from him.
3028 // Otherwise use the first report block.
3029 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003030 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003031 remote_stats.empty()) {
3032 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3033 VoEId(_instanceId, _channelId),
3034 "GetRemoteRTCPData() failed to measure statistics due"
3035 " to lack of received RTP and/or RTCP packets");
3036 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003037 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003038
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003039 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003040 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3041 for (; it != remote_stats.end(); ++it) {
3042 if (it->remoteSSRC == remoteSSRC)
3043 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003044 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003045
3046 if (it == remote_stats.end()) {
3047 // If we have not received any RTCP packets from this SSRC it probably
3048 // means that we have not received any RTP packets.
3049 // Use the first received report block instead.
3050 it = remote_stats.begin();
3051 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003052 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003053
xians@webrtc.org79af7342012-01-31 12:22:14 +00003054 if (jitter) {
3055 *jitter = it->jitter;
3056 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3057 VoEId(_instanceId, _channelId),
3058 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3059 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003060
xians@webrtc.org79af7342012-01-31 12:22:14 +00003061 if (fractionLost) {
3062 *fractionLost = it->fractionLost;
3063 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3064 VoEId(_instanceId, _channelId),
3065 "GetRemoteRTCPData() => fractionLost = %lu",
3066 *fractionLost);
3067 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003068 }
3069 return 0;
3070}
3071
3072int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003073Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003074 unsigned int name,
3075 const char* data,
3076 unsigned short dataLengthInBytes)
3077{
3078 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3079 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003080 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003081 {
3082 _engineStatisticsPtr->SetLastError(
3083 VE_NOT_SENDING, kTraceError,
3084 "SendApplicationDefinedRTCPPacket() not sending");
3085 return -1;
3086 }
3087 if (NULL == data)
3088 {
3089 _engineStatisticsPtr->SetLastError(
3090 VE_INVALID_ARGUMENT, kTraceError,
3091 "SendApplicationDefinedRTCPPacket() invalid data value");
3092 return -1;
3093 }
3094 if (dataLengthInBytes % 4 != 0)
3095 {
3096 _engineStatisticsPtr->SetLastError(
3097 VE_INVALID_ARGUMENT, kTraceError,
3098 "SendApplicationDefinedRTCPPacket() invalid length value");
3099 return -1;
3100 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003101 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003102 if (status == kRtcpOff)
3103 {
3104 _engineStatisticsPtr->SetLastError(
3105 VE_RTCP_ERROR, kTraceError,
3106 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3107 return -1;
3108 }
3109
3110 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003111 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003112 subType,
3113 name,
3114 (const unsigned char*) data,
3115 dataLengthInBytes) != 0)
3116 {
3117 _engineStatisticsPtr->SetLastError(
3118 VE_SEND_ERROR, kTraceError,
3119 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3120 return -1;
3121 }
3122 return 0;
3123}
3124
3125int
3126Channel::GetRTPStatistics(
3127 unsigned int& averageJitterMs,
3128 unsigned int& maxJitterMs,
3129 unsigned int& discardedPackets)
3130{
niklase@google.com470e71d2011-07-07 08:21:25 +00003131 // The jitter statistics is updated for each received RTP packet and is
3132 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003133 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3134 // If RTCP is off, there is no timed thread in the RTCP module regularly
3135 // generating new stats, trigger the update manually here instead.
3136 StreamStatistician* statistician =
3137 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3138 if (statistician) {
3139 // Don't use returned statistics, use data from proxy instead so that
3140 // max jitter can be fetched atomically.
3141 RtcpStatistics s;
3142 statistician->GetStatistics(&s, true);
3143 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003144 }
3145
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003146 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003147 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003148 if (playoutFrequency > 0) {
3149 // Scale RTP statistics given the current playout frequency
3150 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3151 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003152 }
3153
3154 discardedPackets = _numberOfDiscardedPackets;
3155
3156 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3157 VoEId(_instanceId, _channelId),
3158 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003159 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003160 averageJitterMs, maxJitterMs, discardedPackets);
3161 return 0;
3162}
3163
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003164int Channel::GetRemoteRTCPReportBlocks(
3165 std::vector<ReportBlock>* report_blocks) {
3166 if (report_blocks == NULL) {
3167 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3168 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3169 return -1;
3170 }
3171
3172 // Get the report blocks from the latest received RTCP Sender or Receiver
3173 // Report. Each element in the vector contains the sender's SSRC and a
3174 // report block according to RFC 3550.
3175 std::vector<RTCPReportBlock> rtcp_report_blocks;
3176 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3177 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3178 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3179 return -1;
3180 }
3181
3182 if (rtcp_report_blocks.empty())
3183 return 0;
3184
3185 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3186 for (; it != rtcp_report_blocks.end(); ++it) {
3187 ReportBlock report_block;
3188 report_block.sender_SSRC = it->remoteSSRC;
3189 report_block.source_SSRC = it->sourceSSRC;
3190 report_block.fraction_lost = it->fractionLost;
3191 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3192 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3193 report_block.interarrival_jitter = it->jitter;
3194 report_block.last_SR_timestamp = it->lastSR;
3195 report_block.delay_since_last_SR = it->delaySinceLastSR;
3196 report_blocks->push_back(report_block);
3197 }
3198 return 0;
3199}
3200
niklase@google.com470e71d2011-07-07 08:21:25 +00003201int
3202Channel::GetRTPStatistics(CallStatistics& stats)
3203{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003204 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003205
3206 // The jitter statistics is updated for each received RTP packet and is
3207 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003208 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003209 StreamStatistician* statistician =
3210 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3211 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003212 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3213 _engineStatisticsPtr->SetLastError(
3214 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3215 "GetRTPStatistics() failed to read RTP statistics from the "
3216 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003217 }
3218
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003219 stats.fractionLost = statistics.fraction_lost;
3220 stats.cumulativeLost = statistics.cumulative_lost;
3221 stats.extendedMax = statistics.extended_max_sequence_number;
3222 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003223
3224 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3225 VoEId(_instanceId, _channelId),
3226 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003227 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003228 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3229 stats.jitterSamples);
3230
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003231 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003232 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003233 if (stats.rttMs == 0) {
3234 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3235 "GetRTPStatistics() failed to get RTT");
3236 } else {
3237 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003238 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003239 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003240
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003241 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003242
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003243 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003244 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003245 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003246 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003247
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003248 if (statistician) {
3249 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3250 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003251
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003252 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003253 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003254 {
3255 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3256 VoEId(_instanceId, _channelId),
3257 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003258 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003259 }
3260
3261 stats.bytesSent = bytesSent;
3262 stats.packetsSent = packetsSent;
3263 stats.bytesReceived = bytesReceived;
3264 stats.packetsReceived = packetsReceived;
3265
3266 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3267 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003268 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3269 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3271 stats.packetsReceived);
3272
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003273 // --- Timestamps
3274 {
3275 CriticalSectionScoped lock(ts_stats_lock_.get());
3276 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3277 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003278 return 0;
3279}
3280
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003281int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003282 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003283 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003284
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003285 if (enable) {
3286 if (redPayloadtype < 0 || redPayloadtype > 127) {
3287 _engineStatisticsPtr->SetLastError(
3288 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003289 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003290 return -1;
3291 }
3292
3293 if (SetRedPayloadType(redPayloadtype) < 0) {
3294 _engineStatisticsPtr->SetLastError(
3295 VE_CODEC_ERROR, kTraceError,
3296 "SetSecondarySendCodec() Failed to register RED ACM");
3297 return -1;
3298 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003299 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003300
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003301 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003302 _engineStatisticsPtr->SetLastError(
3303 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003304 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003305 return -1;
3306 }
3307 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003308}
3309
3310int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003311Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003312{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003313 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003314 if (enabled)
3315 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003316 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003317 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003318 {
3319 _engineStatisticsPtr->SetLastError(
3320 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003321 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003322 "module");
3323 return -1;
3324 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003325 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003326 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3327 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003328 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003329 enabled, redPayloadtype);
3330 return 0;
3331 }
3332 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3333 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003334 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003335 return 0;
3336}
3337
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003338int Channel::SetCodecFECStatus(bool enable) {
3339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3340 "Channel::SetCodecFECStatus()");
3341
3342 if (audio_coding_->SetCodecFEC(enable) != 0) {
3343 _engineStatisticsPtr->SetLastError(
3344 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3345 "SetCodecFECStatus() failed to set FEC state");
3346 return -1;
3347 }
3348 return 0;
3349}
3350
3351bool Channel::GetCodecFECStatus() {
3352 bool enabled = audio_coding_->CodecFEC();
3353 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3354 VoEId(_instanceId, _channelId),
3355 "GetCodecFECStatus() => enabled=%d", enabled);
3356 return enabled;
3357}
3358
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003359void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3360 // None of these functions can fail.
3361 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003362 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3363 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003364 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003365 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003366 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003367 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003368}
3369
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003370// Called when we are missing one or more packets.
3371int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003372 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3373}
3374
niklase@google.com470e71d2011-07-07 08:21:25 +00003375int
niklase@google.com470e71d2011-07-07 08:21:25 +00003376Channel::StartRTPDump(const char fileNameUTF8[1024],
3377 RTPDirections direction)
3378{
3379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3380 "Channel::StartRTPDump()");
3381 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3382 {
3383 _engineStatisticsPtr->SetLastError(
3384 VE_INVALID_ARGUMENT, kTraceError,
3385 "StartRTPDump() invalid RTP direction");
3386 return -1;
3387 }
3388 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3389 &_rtpDumpIn : &_rtpDumpOut;
3390 if (rtpDumpPtr == NULL)
3391 {
3392 assert(false);
3393 return -1;
3394 }
3395 if (rtpDumpPtr->IsActive())
3396 {
3397 rtpDumpPtr->Stop();
3398 }
3399 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3400 {
3401 _engineStatisticsPtr->SetLastError(
3402 VE_BAD_FILE, kTraceError,
3403 "StartRTPDump() failed to create file");
3404 return -1;
3405 }
3406 return 0;
3407}
3408
3409int
3410Channel::StopRTPDump(RTPDirections direction)
3411{
3412 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3413 "Channel::StopRTPDump()");
3414 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3415 {
3416 _engineStatisticsPtr->SetLastError(
3417 VE_INVALID_ARGUMENT, kTraceError,
3418 "StopRTPDump() invalid RTP direction");
3419 return -1;
3420 }
3421 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3422 &_rtpDumpIn : &_rtpDumpOut;
3423 if (rtpDumpPtr == NULL)
3424 {
3425 assert(false);
3426 return -1;
3427 }
3428 if (!rtpDumpPtr->IsActive())
3429 {
3430 return 0;
3431 }
3432 return rtpDumpPtr->Stop();
3433}
3434
3435bool
3436Channel::RTPDumpIsActive(RTPDirections direction)
3437{
3438 if ((direction != kRtpIncoming) &&
3439 (direction != kRtpOutgoing))
3440 {
3441 _engineStatisticsPtr->SetLastError(
3442 VE_INVALID_ARGUMENT, kTraceError,
3443 "RTPDumpIsActive() invalid RTP direction");
3444 return false;
3445 }
3446 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3447 &_rtpDumpIn : &_rtpDumpOut;
3448 return rtpDumpPtr->IsActive();
3449}
3450
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003451uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003452Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003453{
3454 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003455 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003456 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003457 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003458 return 0;
3459}
3460
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003461void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003462 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003463 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003464 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003465 CodecInst codec;
3466 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003467
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003468 if (!mono_recording_audio_.get()) {
3469 // Temporary space for DownConvertToCodecFormat.
3470 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003471 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003472 DownConvertToCodecFormat(audio_data,
3473 number_of_frames,
3474 number_of_channels,
3475 sample_rate,
3476 codec.channels,
3477 codec.plfreq,
3478 mono_recording_audio_.get(),
3479 &input_resampler_,
3480 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003481}
3482
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003483uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003484Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003485{
3486 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3487 "Channel::PrepareEncodeAndSend()");
3488
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003489 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003490 {
3491 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3492 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003493 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003494 }
3495
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003496 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003497 {
3498 MixOrReplaceAudioWithFile(mixingFrequency);
3499 }
3500
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003501 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3502 if (is_muted) {
3503 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 }
3505
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003506 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003507 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003508 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003509 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003510 if (_inputExternalMediaCallbackPtr)
3511 {
3512 _inputExternalMediaCallbackPtr->Process(
3513 _channelId,
3514 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003515 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003516 _audioFrame.samples_per_channel_,
3517 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003518 isStereo);
3519 }
3520 }
3521
3522 InsertInbandDtmfTone();
3523
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003524 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003525 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003526 if (is_muted) {
3527 rms_level_.ProcessMuted(length);
3528 } else {
3529 rms_level_.Process(_audioFrame.data_, length);
3530 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003531 }
3532
niklase@google.com470e71d2011-07-07 08:21:25 +00003533 return 0;
3534}
3535
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003536uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003537Channel::EncodeAndSend()
3538{
3539 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3540 "Channel::EncodeAndSend()");
3541
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003542 assert(_audioFrame.num_channels_ <= 2);
3543 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003544 {
3545 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3546 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003547 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003548 }
3549
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003550 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003551
3552 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3553
3554 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003555 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003556 // This call will trigger AudioPacketizationCallback::SendData if encoding
3557 // is done and payload is ready for packetization and transmission.
3558 // Otherwise, it will return without invoking the callback.
3559 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003560 {
3561 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3562 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003563 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003564 }
3565
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003566 _timeStamp += _audioFrame.samples_per_channel_;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003567 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003568}
3569
Minyue2013aec2015-05-13 14:14:42 +02003570void Channel::DisassociateSendChannel(int channel_id) {
3571 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3572 Channel* channel = associate_send_channel_.channel();
3573 if (channel && channel->ChannelId() == channel_id) {
3574 // If this channel is associated with a send channel of the specified
3575 // Channel ID, disassociate with it.
3576 ChannelOwner ref(NULL);
3577 associate_send_channel_ = ref;
3578 }
3579}
3580
niklase@google.com470e71d2011-07-07 08:21:25 +00003581int Channel::RegisterExternalMediaProcessing(
3582 ProcessingTypes type,
3583 VoEMediaProcess& processObject)
3584{
3585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3586 "Channel::RegisterExternalMediaProcessing()");
3587
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003588 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003589
3590 if (kPlaybackPerChannel == type)
3591 {
3592 if (_outputExternalMediaCallbackPtr)
3593 {
3594 _engineStatisticsPtr->SetLastError(
3595 VE_INVALID_OPERATION, kTraceError,
3596 "Channel::RegisterExternalMediaProcessing() "
3597 "output external media already enabled");
3598 return -1;
3599 }
3600 _outputExternalMediaCallbackPtr = &processObject;
3601 _outputExternalMedia = true;
3602 }
3603 else if (kRecordingPerChannel == type)
3604 {
3605 if (_inputExternalMediaCallbackPtr)
3606 {
3607 _engineStatisticsPtr->SetLastError(
3608 VE_INVALID_OPERATION, kTraceError,
3609 "Channel::RegisterExternalMediaProcessing() "
3610 "output external media already enabled");
3611 return -1;
3612 }
3613 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003614 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003615 }
3616 return 0;
3617}
3618
3619int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3620{
3621 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3622 "Channel::DeRegisterExternalMediaProcessing()");
3623
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003624 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003625
3626 if (kPlaybackPerChannel == type)
3627 {
3628 if (!_outputExternalMediaCallbackPtr)
3629 {
3630 _engineStatisticsPtr->SetLastError(
3631 VE_INVALID_OPERATION, kTraceWarning,
3632 "Channel::DeRegisterExternalMediaProcessing() "
3633 "output external media already disabled");
3634 return 0;
3635 }
3636 _outputExternalMedia = false;
3637 _outputExternalMediaCallbackPtr = NULL;
3638 }
3639 else if (kRecordingPerChannel == type)
3640 {
3641 if (!_inputExternalMediaCallbackPtr)
3642 {
3643 _engineStatisticsPtr->SetLastError(
3644 VE_INVALID_OPERATION, kTraceWarning,
3645 "Channel::DeRegisterExternalMediaProcessing() "
3646 "input external media already disabled");
3647 return 0;
3648 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003649 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003650 _inputExternalMediaCallbackPtr = NULL;
3651 }
3652
3653 return 0;
3654}
3655
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003656int Channel::SetExternalMixing(bool enabled) {
3657 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3658 "Channel::SetExternalMixing(enabled=%d)", enabled);
3659
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003660 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003661 {
3662 _engineStatisticsPtr->SetLastError(
3663 VE_INVALID_OPERATION, kTraceError,
3664 "Channel::SetExternalMixing() "
3665 "external mixing cannot be changed while playing.");
3666 return -1;
3667 }
3668
3669 _externalMixing = enabled;
3670
3671 return 0;
3672}
3673
niklase@google.com470e71d2011-07-07 08:21:25 +00003674int
niklase@google.com470e71d2011-07-07 08:21:25 +00003675Channel::GetNetworkStatistics(NetworkStatistics& stats)
3676{
3677 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3678 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003679 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003680}
3681
wu@webrtc.org24301a62013-12-13 19:17:43 +00003682void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3683 audio_coding_->GetDecodingCallStatistics(stats);
3684}
3685
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003686bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3687 int* playout_buffer_delay_ms) const {
3688 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003689 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003690 "Channel::GetDelayEstimate() no valid estimate.");
3691 return false;
3692 }
3693 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3694 _recPacketDelayMs;
3695 *playout_buffer_delay_ms = playout_delay_ms_;
3696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3697 "Channel::GetDelayEstimate()");
3698 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003699}
3700
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003701int Channel::SetInitialPlayoutDelay(int delay_ms)
3702{
3703 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3704 "Channel::SetInitialPlayoutDelay()");
3705 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3706 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3707 {
3708 _engineStatisticsPtr->SetLastError(
3709 VE_INVALID_ARGUMENT, kTraceError,
3710 "SetInitialPlayoutDelay() invalid min delay");
3711 return -1;
3712 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003713 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003714 {
3715 _engineStatisticsPtr->SetLastError(
3716 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3717 "SetInitialPlayoutDelay() failed to set min playout delay");
3718 return -1;
3719 }
3720 return 0;
3721}
3722
3723
niklase@google.com470e71d2011-07-07 08:21:25 +00003724int
3725Channel::SetMinimumPlayoutDelay(int delayMs)
3726{
3727 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3728 "Channel::SetMinimumPlayoutDelay()");
3729 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3730 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3731 {
3732 _engineStatisticsPtr->SetLastError(
3733 VE_INVALID_ARGUMENT, kTraceError,
3734 "SetMinimumPlayoutDelay() invalid min delay");
3735 return -1;
3736 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003737 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003738 {
3739 _engineStatisticsPtr->SetLastError(
3740 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3741 "SetMinimumPlayoutDelay() failed to set min playout delay");
3742 return -1;
3743 }
3744 return 0;
3745}
3746
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003747void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3748 uint32_t playout_timestamp = 0;
3749
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003750 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003751 // This can happen if this channel has not been received any RTP packet. In
3752 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003753 return;
3754 }
3755
3756 uint16_t delay_ms = 0;
3757 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3758 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3759 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3760 " delay from the ADM");
3761 _engineStatisticsPtr->SetLastError(
3762 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3763 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3764 return;
3765 }
3766
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003767 jitter_buffer_playout_timestamp_ = playout_timestamp;
3768
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003769 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003770 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003771
3772 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3773 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3774 playout_timestamp);
3775
3776 if (rtcp) {
3777 playout_timestamp_rtcp_ = playout_timestamp;
3778 } else {
3779 playout_timestamp_rtp_ = playout_timestamp;
3780 }
3781 playout_delay_ms_ = delay_ms;
3782}
3783
3784int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3785 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3786 "Channel::GetPlayoutTimestamp()");
3787 if (playout_timestamp_rtp_ == 0) {
3788 _engineStatisticsPtr->SetLastError(
3789 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3790 "GetPlayoutTimestamp() failed to retrieve timestamp");
3791 return -1;
3792 }
3793 timestamp = playout_timestamp_rtp_;
3794 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3795 VoEId(_instanceId,_channelId),
3796 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3797 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003798}
3799
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003800int Channel::SetInitTimestamp(unsigned int timestamp) {
3801 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003802 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003803 if (channel_state_.Get().sending) {
3804 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3805 "SetInitTimestamp() already sending");
3806 return -1;
3807 }
3808 _rtpRtcpModule->SetStartTimestamp(timestamp);
3809 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003810}
3811
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003812int Channel::SetInitSequenceNumber(short sequenceNumber) {
3813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3814 "Channel::SetInitSequenceNumber()");
3815 if (channel_state_.Get().sending) {
3816 _engineStatisticsPtr->SetLastError(
3817 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3818 return -1;
3819 }
3820 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3821 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003822}
3823
3824int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003825Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003826{
3827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3828 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003829 *rtpRtcpModule = _rtpRtcpModule.get();
3830 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003831 return 0;
3832}
3833
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003834// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3835// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003836int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003837Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003838{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003839 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003840 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003841
3842 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003843 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003844
3845 if (_inputFilePlayerPtr == NULL)
3846 {
3847 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3848 VoEId(_instanceId, _channelId),
3849 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3850 " doesnt exist");
3851 return -1;
3852 }
3853
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003854 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003855 fileSamples,
3856 mixingFrequency) == -1)
3857 {
3858 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3859 VoEId(_instanceId, _channelId),
3860 "Channel::MixOrReplaceAudioWithFile() file mixing "
3861 "failed");
3862 return -1;
3863 }
3864 if (fileSamples == 0)
3865 {
3866 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3867 VoEId(_instanceId, _channelId),
3868 "Channel::MixOrReplaceAudioWithFile() file is ended");
3869 return 0;
3870 }
3871 }
3872
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003873 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003874
3875 if (_mixFileWithMicrophone)
3876 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003877 // Currently file stream is always mono.
3878 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003879 MixWithSat(_audioFrame.data_,
3880 _audioFrame.num_channels_,
3881 fileBuffer.get(),
3882 1,
3883 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003884 }
3885 else
3886 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003887 // Replace ACM audio with file.
3888 // Currently file stream is always mono.
3889 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003891 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003892 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003893 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003894 mixingFrequency,
3895 AudioFrame::kNormalSpeech,
3896 AudioFrame::kVadUnknown,
3897 1);
3898
3899 }
3900 return 0;
3901}
3902
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003903int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003904Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003905 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003906{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003907 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003908
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003909 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003910 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003911
3912 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003913 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003914
3915 if (_outputFilePlayerPtr == NULL)
3916 {
3917 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3918 VoEId(_instanceId, _channelId),
3919 "Channel::MixAudioWithFile() file mixing failed");
3920 return -1;
3921 }
3922
3923 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003924 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003925 fileSamples,
3926 mixingFrequency) == -1)
3927 {
3928 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3929 VoEId(_instanceId, _channelId),
3930 "Channel::MixAudioWithFile() file mixing failed");
3931 return -1;
3932 }
3933 }
3934
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003935 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003936 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003937 // Currently file stream is always mono.
3938 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003939 MixWithSat(audioFrame.data_,
3940 audioFrame.num_channels_,
3941 fileBuffer.get(),
3942 1,
3943 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003944 }
3945 else
3946 {
3947 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003948 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003949 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003950 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003951 return -1;
3952 }
3953
3954 return 0;
3955}
3956
3957int
3958Channel::InsertInbandDtmfTone()
3959{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003960 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003961 if (_inbandDtmfQueue.PendingDtmf() &&
3962 !_inbandDtmfGenerator.IsAddingTone() &&
3963 _inbandDtmfGenerator.DelaySinceLastTone() >
3964 kMinTelephoneEventSeparationMs)
3965 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003966 int8_t eventCode(0);
3967 uint16_t lengthMs(0);
3968 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003969
3970 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3971 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3972 if (_playInbandDtmfEvent)
3973 {
3974 // Add tone to output mixer using a reduced length to minimize
3975 // risk of echo.
3976 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3977 attenuationDb);
3978 }
3979 }
3980
3981 if (_inbandDtmfGenerator.IsAddingTone())
3982 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003983 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003984 _inbandDtmfGenerator.GetSampleRate(frequency);
3985
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003986 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003987 {
3988 // Update sample rate of Dtmf tone since the mixing frequency
3989 // has changed.
3990 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003991 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003992 // Reset the tone to be added taking the new sample rate into
3993 // account.
3994 _inbandDtmfGenerator.ResetTone();
3995 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003996
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003997 int16_t toneBuffer[320];
3998 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003999 // Get 10ms tone segment and set time since last tone to zero
4000 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4001 {
4002 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4003 VoEId(_instanceId, _channelId),
4004 "Channel::EncodeAndSend() inserting Dtmf failed");
4005 return -1;
4006 }
4007
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004008 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004009 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004010 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004011 sample++)
4012 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004013 for (int channel = 0;
4014 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004015 channel++)
4016 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004017 const int index = sample * _audioFrame.num_channels_ + channel;
4018 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004019 }
4020 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004021
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004022 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004023 } else
4024 {
4025 // Add 10ms to "delay-since-last-tone" counter
4026 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4027 }
4028 return 0;
4029}
4030
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004031int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00004032Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00004033{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004034 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004035 if (_transportPtr == NULL)
4036 {
4037 return -1;
4038 }
4039 if (!RTCP)
4040 {
4041 return _transportPtr->SendPacket(_channelId, data, len);
4042 }
4043 else
4044 {
4045 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4046 }
4047}
4048
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004049// Called for incoming RTP packets after successful RTP header parsing.
4050void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4051 uint16_t sequence_number) {
4052 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4053 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4054 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004055
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004056 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004057 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004058
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004059 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004060 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004061
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004062 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4063 // every incoming packet.
4064 uint32_t timestamp_diff_ms = (rtp_timestamp -
4065 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004066 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4067 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4068 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4069 // timestamp, the resulting difference is negative, but is set to zero.
4070 // This can happen when a network glitch causes a packet to arrive late,
4071 // and during long comfort noise periods with clock drift.
4072 timestamp_diff_ms = 0;
4073 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004074
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004075 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4076 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004077
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004078 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004079
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004080 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004081
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004082 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4083 _recPacketDelayMs = packet_delay_ms;
4084 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004085
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004086 if (_average_jitter_buffer_delay_us == 0) {
4087 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4088 return;
4089 }
4090
4091 // Filter average delay value using exponential filter (alpha is
4092 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4093 // risk of rounding error) and compensate for it in GetDelayEstimate()
4094 // later.
4095 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4096 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004097}
4098
4099void
4100Channel::RegisterReceiveCodecsToRTPModule()
4101{
4102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4103 "Channel::RegisterReceiveCodecsToRTPModule()");
4104
4105
4106 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004107 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004108
4109 for (int idx = 0; idx < nSupportedCodecs; idx++)
4110 {
4111 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004112 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004113 (rtp_receiver_->RegisterReceivePayload(
4114 codec.plname,
4115 codec.pltype,
4116 codec.plfreq,
4117 codec.channels,
4118 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004119 {
4120 WEBRTC_TRACE(
4121 kTraceWarning,
4122 kTraceVoice,
4123 VoEId(_instanceId, _channelId),
4124 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4125 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4126 codec.plname, codec.pltype, codec.plfreq,
4127 codec.channels, codec.rate);
4128 }
4129 else
4130 {
4131 WEBRTC_TRACE(
4132 kTraceInfo,
4133 kTraceVoice,
4134 VoEId(_instanceId, _channelId),
4135 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004136 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004137 "receiver",
4138 codec.plname, codec.pltype, codec.plfreq,
4139 codec.channels, codec.rate);
4140 }
4141 }
4142}
4143
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004144// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004145int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004146 CodecInst codec;
4147 bool found_red = false;
4148
4149 // Get default RED settings from the ACM database
4150 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4151 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004152 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004153 if (!STR_CASE_CMP(codec.plname, "RED")) {
4154 found_red = true;
4155 break;
4156 }
4157 }
4158
4159 if (!found_red) {
4160 _engineStatisticsPtr->SetLastError(
4161 VE_CODEC_ERROR, kTraceError,
4162 "SetRedPayloadType() RED is not supported");
4163 return -1;
4164 }
4165
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004166 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004167 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004168 _engineStatisticsPtr->SetLastError(
4169 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4170 "SetRedPayloadType() RED registration in ACM module failed");
4171 return -1;
4172 }
4173
4174 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4175 _engineStatisticsPtr->SetLastError(
4176 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4177 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4178 return -1;
4179 }
4180 return 0;
4181}
4182
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004183int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4184 unsigned char id) {
4185 int error = 0;
4186 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4187 if (enable) {
4188 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4189 }
4190 return error;
4191}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004192
wu@webrtc.org94454b72014-06-05 20:34:08 +00004193int32_t Channel::GetPlayoutFrequency() {
4194 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4195 CodecInst current_recive_codec;
4196 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4197 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4198 // Even though the actual sampling rate for G.722 audio is
4199 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4200 // 8,000 Hz because that value was erroneously assigned in
4201 // RFC 1890 and must remain unchanged for backward compatibility.
4202 playout_frequency = 8000;
4203 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4204 // We are resampling Opus internally to 32,000 Hz until all our
4205 // DSP routines can operate at 48,000 Hz, but the RTP clock
4206 // rate for the Opus payload format is standardized to 48,000 Hz,
4207 // because that is the maximum supported decoding sampling rate.
4208 playout_frequency = 48000;
4209 }
4210 }
4211 return playout_frequency;
4212}
4213
Minyue2013aec2015-05-13 14:14:42 +02004214int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004215 RTCPMethod method = _rtpRtcpModule->RTCP();
4216 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004217 return 0;
4218 }
4219 std::vector<RTCPReportBlock> report_blocks;
4220 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004221
4222 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004223 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004224 if (allow_associate_channel) {
4225 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4226 Channel* channel = associate_send_channel_.channel();
4227 // Tries to get RTT from an associated channel. This is important for
4228 // receive-only channels.
4229 if (channel) {
4230 // To prevent infinite recursion and deadlock, calling GetRTT of
4231 // associate channel should always use "false" for argument:
4232 // |allow_associate_channel|.
4233 rtt = channel->GetRTT(false);
4234 }
4235 }
4236 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004237 }
4238
4239 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4240 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4241 for (; it != report_blocks.end(); ++it) {
4242 if (it->remoteSSRC == remoteSSRC)
4243 break;
4244 }
4245 if (it == report_blocks.end()) {
4246 // We have not received packets with SSRC matching the report blocks.
4247 // To calculate RTT we try with the SSRC of the first report block.
4248 // This is very important for send-only channels where we don't know
4249 // the SSRC of the other end.
4250 remoteSSRC = report_blocks[0].remoteSSRC;
4251 }
Minyue2013aec2015-05-13 14:14:42 +02004252
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004253 int64_t avg_rtt = 0;
4254 int64_t max_rtt= 0;
4255 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004256 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4257 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004258 return 0;
4259 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004260 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004261}
4262
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004263} // namespace voe
4264} // namespace webrtc