blob: def39887e3d40f8c90756c9fef57ef92bab91365 [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)),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000825 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000826{
827 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
828 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200829 AudioCodingModule::Config acm_config;
830 acm_config.id = VoEModuleId(instanceId, channelId);
831 if (config.Get<NetEqCapacityConfig>().enabled) {
832 // Clamping the buffer capacity at 20 packets. While going lower will
833 // probably work, it makes little sense.
834 acm_config.neteq_config.max_packets_in_buffer =
835 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
836 }
837 audio_coding_.reset(AudioCodingModule::Create(acm_config));
838
niklase@google.com470e71d2011-07-07 08:21:25 +0000839 _inbandDtmfQueue.ResetDtmf();
840 _inbandDtmfGenerator.Init();
841 _outputAudioLevel.Clear();
842
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000843 RtpRtcp::Configuration configuration;
844 configuration.id = VoEModuleId(instanceId, channelId);
845 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000846 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000847 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000848 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000849 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000850
851 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000852
853 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
854 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
855 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000856
857 Config audioproc_config;
858 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
859 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000860}
861
862Channel::~Channel()
863{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000864 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000865 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
866 "Channel::~Channel() - dtor");
867
868 if (_outputExternalMedia)
869 {
870 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
871 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000872 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 {
874 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
875 }
876 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 StopPlayout();
878
879 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000880 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000881 if (_inputFilePlayerPtr)
882 {
883 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
884 _inputFilePlayerPtr->StopPlayingFile();
885 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
886 _inputFilePlayerPtr = NULL;
887 }
888 if (_outputFilePlayerPtr)
889 {
890 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
891 _outputFilePlayerPtr->StopPlayingFile();
892 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
893 _outputFilePlayerPtr = NULL;
894 }
895 if (_outputFileRecorderPtr)
896 {
897 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
898 _outputFileRecorderPtr->StopRecording();
899 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
900 _outputFileRecorderPtr = NULL;
901 }
902 }
903
904 // The order to safely shutdown modules in a channel is:
905 // 1. De-register callbacks in modules
906 // 2. De-register modules in process thread
907 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000908 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 {
910 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
911 VoEId(_instanceId,_channelId),
912 "~Channel() failed to de-register transport callback"
913 " (Audio coding module)");
914 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000915 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 {
917 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
918 VoEId(_instanceId,_channelId),
919 "~Channel() failed to de-register VAD callback"
920 " (Audio coding module)");
921 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000923 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
924
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 // End of modules shutdown
926
927 // Delete other objects
928 RtpDump::DestroyRtpDump(&_rtpDumpIn);
929 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000932 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000933}
934
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000935int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000936Channel::Init()
937{
938 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
939 "Channel::Init()");
940
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000941 channel_state_.Reset();
942
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 // --- Initial sanity
944
945 if ((_engineStatisticsPtr == NULL) ||
946 (_moduleProcessThreadPtr == NULL))
947 {
948 WEBRTC_TRACE(kTraceError, kTraceVoice,
949 VoEId(_instanceId,_channelId),
950 "Channel::Init() must call SetEngineInformation() first");
951 return -1;
952 }
953
954 // --- Add modules to process thread (for periodic schedulation)
955
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000956 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
957
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000958 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000959
Henrik Lundin45c64492015-03-30 19:00:44 +0200960 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000961#ifdef WEBRTC_CODEC_AVT
962 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200963 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000964#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200965 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 {
967 _engineStatisticsPtr->SetLastError(
968 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
969 "Channel::Init() unable to initialize the ACM - 1");
970 return -1;
971 }
972
973 // --- RTP/RTCP module initialization
974
975 // Ensure that RTCP is enabled by default for the created channel.
976 // Note that, the module will keep generating RTCP until it is explicitly
977 // disabled by the user.
978 // After StopListen (when no sockets exists), RTCP packets will no longer
979 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000980 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
981 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000982 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
983 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000985 (audio_coding_->RegisterTransportCallback(this) == -1) ||
986 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000987
988 if (fail)
989 {
990 _engineStatisticsPtr->SetLastError(
991 VE_CANNOT_INIT_CHANNEL, kTraceError,
992 "Channel::Init() callbacks not registered");
993 return -1;
994 }
995
996 // --- Register all supported codecs to the receiving side of the
997 // RTP/RTCP module
998
999 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001000 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001001
1002 for (int idx = 0; idx < nSupportedCodecs; idx++)
1003 {
1004 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001005 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001006 (rtp_receiver_->RegisterReceivePayload(
1007 codec.plname,
1008 codec.pltype,
1009 codec.plfreq,
1010 codec.channels,
1011 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 {
1013 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1014 VoEId(_instanceId,_channelId),
1015 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1016 "to RTP/RTCP receiver",
1017 codec.plname, codec.pltype, codec.plfreq,
1018 codec.channels, codec.rate);
1019 }
1020 else
1021 {
1022 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1023 VoEId(_instanceId,_channelId),
1024 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1025 "the RTP/RTCP receiver",
1026 codec.plname, codec.pltype, codec.plfreq,
1027 codec.channels, codec.rate);
1028 }
1029
1030 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001031 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 {
1033 SetSendCodec(codec);
1034 }
1035
1036 // Register default PT for outband 'telephone-event'
1037 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1038 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001039 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001040 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 {
1042 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1043 VoEId(_instanceId,_channelId),
1044 "Channel::Init() failed to register outband "
1045 "'telephone-event' (%d/%d) correctly",
1046 codec.pltype, codec.plfreq);
1047 }
1048 }
1049
1050 if (!STR_CASE_CMP(codec.plname, "CN"))
1051 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001052 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1053 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001054 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 {
1056 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1057 VoEId(_instanceId,_channelId),
1058 "Channel::Init() failed to register CN (%d/%d) "
1059 "correctly - 1",
1060 codec.pltype, codec.plfreq);
1061 }
1062 }
1063#ifdef WEBRTC_CODEC_RED
1064 // Register RED to the receiving side of the ACM.
1065 // We will not receive an OnInitializeDecoder() callback for RED.
1066 if (!STR_CASE_CMP(codec.plname, "RED"))
1067 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001068 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 {
1070 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1071 VoEId(_instanceId,_channelId),
1072 "Channel::Init() failed to register RED (%d/%d) "
1073 "correctly",
1074 codec.pltype, codec.plfreq);
1075 }
1076 }
1077#endif
1078 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001079
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001080 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1081 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1082 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001084 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1085 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1086 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001087 }
1088
1089 return 0;
1090}
1091
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001092int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001093Channel::SetEngineInformation(Statistics& engineStatistics,
1094 OutputMixer& outputMixer,
1095 voe::TransmitMixer& transmitMixer,
1096 ProcessThread& moduleProcessThread,
1097 AudioDeviceModule& audioDeviceModule,
1098 VoiceEngineObserver* voiceEngineObserver,
1099 CriticalSectionWrapper* callbackCritSect)
1100{
1101 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1102 "Channel::SetEngineInformation()");
1103 _engineStatisticsPtr = &engineStatistics;
1104 _outputMixerPtr = &outputMixer;
1105 _transmitMixerPtr = &transmitMixer,
1106 _moduleProcessThreadPtr = &moduleProcessThread;
1107 _audioDeviceModulePtr = &audioDeviceModule;
1108 _voiceEngineObserverPtr = voiceEngineObserver;
1109 _callbackCritSectPtr = callbackCritSect;
1110 return 0;
1111}
1112
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001113int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001114Channel::UpdateLocalTimeStamp()
1115{
1116
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001117 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001118 return 0;
1119}
1120
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001121int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001122Channel::StartPlayout()
1123{
1124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1125 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001126 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001127 {
1128 return 0;
1129 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001130
1131 if (!_externalMixing) {
1132 // Add participant as candidates for mixing.
1133 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1134 {
1135 _engineStatisticsPtr->SetLastError(
1136 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1137 "StartPlayout() failed to add participant to mixer");
1138 return -1;
1139 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 }
1141
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001142 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001143 if (RegisterFilePlayingToMixer() != 0)
1144 return -1;
1145
niklase@google.com470e71d2011-07-07 08:21:25 +00001146 return 0;
1147}
1148
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001149int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001150Channel::StopPlayout()
1151{
1152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1153 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001154 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001155 {
1156 return 0;
1157 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001158
1159 if (!_externalMixing) {
1160 // Remove participant as candidates for mixing
1161 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1162 {
1163 _engineStatisticsPtr->SetLastError(
1164 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1165 "StopPlayout() failed to remove participant from mixer");
1166 return -1;
1167 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001168 }
1169
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001170 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001171 _outputAudioLevel.Clear();
1172
1173 return 0;
1174}
1175
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001176int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001177Channel::StartSend()
1178{
1179 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1180 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001181 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001182 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001183 if (send_sequence_number_)
1184 SetInitSequenceNumber(send_sequence_number_);
1185
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001186 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001190 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001191
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001192 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 {
1194 _engineStatisticsPtr->SetLastError(
1195 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1196 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001197 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001198 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 return -1;
1200 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001201
niklase@google.com470e71d2011-07-07 08:21:25 +00001202 return 0;
1203}
1204
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001205int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001206Channel::StopSend()
1207{
1208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1209 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001210 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001212 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001214 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001215
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001216 // Store the sequence number to be able to pick up the same sequence for
1217 // the next StartSend(). This is needed for restarting device, otherwise
1218 // it might cause libSRTP to complain about packets being replayed.
1219 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1220 // CL is landed. See issue
1221 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1222 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1223
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 // Reset sending SSRC and sequence number and triggers direct transmission
1225 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001226 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1227 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001228 {
1229 _engineStatisticsPtr->SetLastError(
1230 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1231 "StartSend() RTP/RTCP failed to stop sending");
1232 }
1233
niklase@google.com470e71d2011-07-07 08:21:25 +00001234 return 0;
1235}
1236
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001237int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001238Channel::StartReceiving()
1239{
1240 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1241 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 {
1244 return 0;
1245 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001246 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 _numberOfDiscardedPackets = 0;
1248 return 0;
1249}
1250
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001251int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001252Channel::StopReceiving()
1253{
1254 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1255 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001256 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001257 {
1258 return 0;
1259 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001260
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001261 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 return 0;
1263}
1264
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001265int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001266Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1267{
1268 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1269 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001270 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001271
1272 if (_voiceEngineObserverPtr)
1273 {
1274 _engineStatisticsPtr->SetLastError(
1275 VE_INVALID_OPERATION, kTraceError,
1276 "RegisterVoiceEngineObserver() observer already enabled");
1277 return -1;
1278 }
1279 _voiceEngineObserverPtr = &observer;
1280 return 0;
1281}
1282
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001283int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001284Channel::DeRegisterVoiceEngineObserver()
1285{
1286 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1287 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001288 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001289
1290 if (!_voiceEngineObserverPtr)
1291 {
1292 _engineStatisticsPtr->SetLastError(
1293 VE_INVALID_OPERATION, kTraceWarning,
1294 "DeRegisterVoiceEngineObserver() observer already disabled");
1295 return 0;
1296 }
1297 _voiceEngineObserverPtr = NULL;
1298 return 0;
1299}
1300
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001301int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001302Channel::GetSendCodec(CodecInst& codec)
1303{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001304 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001305}
1306
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001307int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001308Channel::GetRecCodec(CodecInst& codec)
1309{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001310 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001311}
1312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001313int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001314Channel::SetSendCodec(const CodecInst& codec)
1315{
1316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1317 "Channel::SetSendCodec()");
1318
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001319 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001320 {
1321 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1322 "SetSendCodec() failed to register codec to ACM");
1323 return -1;
1324 }
1325
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001326 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001328 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1329 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 {
1331 WEBRTC_TRACE(
1332 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1333 "SetSendCodec() failed to register codec to"
1334 " RTP/RTCP module");
1335 return -1;
1336 }
1337 }
1338
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001339 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 {
1341 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1342 "SetSendCodec() failed to set audio packet size");
1343 return -1;
1344 }
1345
1346 return 0;
1347}
1348
Ivo Creusenadf89b72015-04-29 16:03:33 +02001349void Channel::SetBitRate(int bitrate_bps) {
1350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1351 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1352 audio_coding_->SetBitRate(bitrate_bps);
1353}
1354
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001355void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001356 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001357 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1358
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001359 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001360 if (audio_coding_->SetPacketLossRate(
1361 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001362 assert(false); // This should not happen.
1363 }
1364}
1365
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001366int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001367Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1368{
1369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1370 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001371 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 // To disable VAD, DTX must be disabled too
1373 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001374 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001375 {
1376 _engineStatisticsPtr->SetLastError(
1377 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1378 "SetVADStatus() failed to set VAD");
1379 return -1;
1380 }
1381 return 0;
1382}
1383
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001384int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001385Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1386{
1387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1388 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001389 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 {
1391 _engineStatisticsPtr->SetLastError(
1392 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1393 "GetVADStatus() failed to get VAD status");
1394 return -1;
1395 }
1396 disabledDTX = !disabledDTX;
1397 return 0;
1398}
1399
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001400int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001401Channel::SetRecPayloadType(const CodecInst& codec)
1402{
1403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1404 "Channel::SetRecPayloadType()");
1405
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001406 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 {
1408 _engineStatisticsPtr->SetLastError(
1409 VE_ALREADY_PLAYING, kTraceError,
1410 "SetRecPayloadType() unable to set PT while playing");
1411 return -1;
1412 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001413 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 {
1415 _engineStatisticsPtr->SetLastError(
1416 VE_ALREADY_LISTENING, kTraceError,
1417 "SetRecPayloadType() unable to set PT while listening");
1418 return -1;
1419 }
1420
1421 if (codec.pltype == -1)
1422 {
1423 // De-register the selected codec (RTP/RTCP module and ACM)
1424
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001425 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 CodecInst rxCodec = codec;
1427
1428 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001429 rtp_payload_registry_->ReceivePayloadType(
1430 rxCodec.plname,
1431 rxCodec.plfreq,
1432 rxCodec.channels,
1433 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1434 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 rxCodec.pltype = pltype;
1436
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001437 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001438 {
1439 _engineStatisticsPtr->SetLastError(
1440 VE_RTP_RTCP_MODULE_ERROR,
1441 kTraceError,
1442 "SetRecPayloadType() RTP/RTCP-module deregistration "
1443 "failed");
1444 return -1;
1445 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001446 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001447 {
1448 _engineStatisticsPtr->SetLastError(
1449 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1450 "SetRecPayloadType() ACM deregistration failed - 1");
1451 return -1;
1452 }
1453 return 0;
1454 }
1455
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001456 if (rtp_receiver_->RegisterReceivePayload(
1457 codec.plname,
1458 codec.pltype,
1459 codec.plfreq,
1460 codec.channels,
1461 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 {
1463 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001464 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1465 if (rtp_receiver_->RegisterReceivePayload(
1466 codec.plname,
1467 codec.pltype,
1468 codec.plfreq,
1469 codec.channels,
1470 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001471 {
1472 _engineStatisticsPtr->SetLastError(
1473 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1474 "SetRecPayloadType() RTP/RTCP-module registration failed");
1475 return -1;
1476 }
1477 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001478 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001479 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001480 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1481 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 {
1483 _engineStatisticsPtr->SetLastError(
1484 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1485 "SetRecPayloadType() ACM registration failed - 1");
1486 return -1;
1487 }
1488 }
1489 return 0;
1490}
1491
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001492int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001493Channel::GetRecPayloadType(CodecInst& codec)
1494{
1495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1496 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001497 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001498 if (rtp_payload_registry_->ReceivePayloadType(
1499 codec.plname,
1500 codec.plfreq,
1501 codec.channels,
1502 (codec.rate < 0) ? 0 : codec.rate,
1503 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 {
1505 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001506 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001507 "GetRecPayloadType() failed to retrieve RX payload type");
1508 return -1;
1509 }
1510 codec.pltype = payloadType;
1511 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001512 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001513 return 0;
1514}
1515
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001516int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001517Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1518{
1519 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1520 "Channel::SetSendCNPayloadType()");
1521
1522 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001523 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001524 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001525 if (frequency == kFreq32000Hz)
1526 samplingFreqHz = 32000;
1527 else if (frequency == kFreq16000Hz)
1528 samplingFreqHz = 16000;
1529
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001530 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 {
1532 _engineStatisticsPtr->SetLastError(
1533 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1534 "SetSendCNPayloadType() failed to retrieve default CN codec "
1535 "settings");
1536 return -1;
1537 }
1538
1539 // Modify the payload type (must be set to dynamic range)
1540 codec.pltype = type;
1541
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001542 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001543 {
1544 _engineStatisticsPtr->SetLastError(
1545 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1546 "SetSendCNPayloadType() failed to register CN to ACM");
1547 return -1;
1548 }
1549
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001550 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001551 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001552 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1553 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001554 {
1555 _engineStatisticsPtr->SetLastError(
1556 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1557 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1558 "module");
1559 return -1;
1560 }
1561 }
1562 return 0;
1563}
1564
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001565int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001567 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001568
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001569 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001570 _engineStatisticsPtr->SetLastError(
1571 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001572 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001573 return -1;
1574 }
1575 return 0;
1576}
1577
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001578int Channel::SetOpusDtx(bool enable_dtx) {
1579 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1580 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001581 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001582 : audio_coding_->DisableOpusDtx();
1583 if (ret != 0) {
1584 _engineStatisticsPtr->SetLastError(
1585 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1586 return -1;
1587 }
1588 return 0;
1589}
1590
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001591int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001592{
1593 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1594 "Channel::RegisterExternalTransport()");
1595
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001596 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001597
niklase@google.com470e71d2011-07-07 08:21:25 +00001598 if (_externalTransport)
1599 {
1600 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1601 kTraceError,
1602 "RegisterExternalTransport() external transport already enabled");
1603 return -1;
1604 }
1605 _externalTransport = true;
1606 _transportPtr = &transport;
1607 return 0;
1608}
1609
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001610int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001611Channel::DeRegisterExternalTransport()
1612{
1613 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1614 "Channel::DeRegisterExternalTransport()");
1615
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001616 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001617
niklase@google.com470e71d2011-07-07 08:21:25 +00001618 if (!_transportPtr)
1619 {
1620 _engineStatisticsPtr->SetLastError(
1621 VE_INVALID_OPERATION, kTraceWarning,
1622 "DeRegisterExternalTransport() external transport already "
1623 "disabled");
1624 return 0;
1625 }
1626 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001627 _transportPtr = NULL;
1628 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1629 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001630 return 0;
1631}
1632
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001633int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001634 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001635 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1636 "Channel::ReceivedRTPPacket()");
1637
1638 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001639 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001640
1641 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001642 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1643 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001644 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1645 VoEId(_instanceId,_channelId),
1646 "Channel::SendPacket() RTP dump to input file failed");
1647 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001648 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001649 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001650 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1651 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1652 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001653 return -1;
1654 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001655 header.payload_type_frequency =
1656 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001657 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001658 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001659 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001660 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001661 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001662 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001663
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001664 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001665}
1666
1667bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001668 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001669 const RTPHeader& header,
1670 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001671 if (rtp_payload_registry_->IsRtx(header)) {
1672 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001673 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001674 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001675 assert(packet_length >= header.headerLength);
1676 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001677 PayloadUnion payload_specific;
1678 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001679 &payload_specific)) {
1680 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001681 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001682 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1683 payload_specific, in_order);
1684}
1685
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001686bool Channel::HandleRtxPacket(const uint8_t* packet,
1687 size_t packet_length,
1688 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001689 if (!rtp_payload_registry_->IsRtx(header))
1690 return false;
1691
1692 // Remove the RTX header and parse the original RTP header.
1693 if (packet_length < header.headerLength)
1694 return false;
1695 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1696 return false;
1697 if (restored_packet_in_use_) {
1698 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1699 "Multiple RTX headers detected, dropping packet");
1700 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001701 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001702 uint8_t* restored_packet_ptr = restored_packet_;
1703 if (!rtp_payload_registry_->RestoreOriginalPacket(
1704 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1705 header)) {
1706 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1707 "Incoming RTX packet: invalid RTP header");
1708 return false;
1709 }
1710 restored_packet_in_use_ = true;
1711 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1712 restored_packet_in_use_ = false;
1713 return ret;
1714}
1715
1716bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1717 StreamStatistician* statistician =
1718 rtp_receive_statistics_->GetStatistician(header.ssrc);
1719 if (!statistician)
1720 return false;
1721 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001722}
1723
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001724bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1725 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001726 // Retransmissions are handled separately if RTX is enabled.
1727 if (rtp_payload_registry_->RtxEnabled())
1728 return false;
1729 StreamStatistician* statistician =
1730 rtp_receive_statistics_->GetStatistician(header.ssrc);
1731 if (!statistician)
1732 return false;
1733 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001734 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001735 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001736 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001737 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001738}
1739
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001740int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001741 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1742 "Channel::ReceivedRTCPPacket()");
1743 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001744 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001745
1746 // Dump the RTCP packet to a file (if RTP dump is enabled).
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001747 if (_rtpDumpIn.DumpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001748 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1749 VoEId(_instanceId,_channelId),
1750 "Channel::SendPacket() RTCP dump to input file failed");
1751 }
1752
1753 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001754 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001755 _engineStatisticsPtr->SetLastError(
1756 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1757 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1758 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001759
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001760 {
1761 CriticalSectionScoped lock(ts_stats_lock_.get());
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001762 int64_t rtt = GetRTT();
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001763 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 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001776 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001777 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001778}
1779
niklase@google.com470e71d2011-07-07 08:21:25 +00001780int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001781 bool loop,
1782 FileFormats format,
1783 int startPosition,
1784 float volumeScaling,
1785 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001786 const CodecInst* codecInst)
1787{
1788 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1789 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1790 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1791 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1792 startPosition, stopPosition);
1793
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001794 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001795 {
1796 _engineStatisticsPtr->SetLastError(
1797 VE_ALREADY_PLAYING, kTraceError,
1798 "StartPlayingFileLocally() is already playing");
1799 return -1;
1800 }
1801
niklase@google.com470e71d2011-07-07 08:21:25 +00001802 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001803 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001804
1805 if (_outputFilePlayerPtr)
1806 {
1807 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1808 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1809 _outputFilePlayerPtr = NULL;
1810 }
1811
1812 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1813 _outputFilePlayerId, (const FileFormats)format);
1814
1815 if (_outputFilePlayerPtr == NULL)
1816 {
1817 _engineStatisticsPtr->SetLastError(
1818 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001819 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001820 return -1;
1821 }
1822
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001823 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001824
1825 if (_outputFilePlayerPtr->StartPlayingFile(
1826 fileName,
1827 loop,
1828 startPosition,
1829 volumeScaling,
1830 notificationTime,
1831 stopPosition,
1832 (const CodecInst*)codecInst) != 0)
1833 {
1834 _engineStatisticsPtr->SetLastError(
1835 VE_BAD_FILE, kTraceError,
1836 "StartPlayingFile() failed to start file playout");
1837 _outputFilePlayerPtr->StopPlayingFile();
1838 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1839 _outputFilePlayerPtr = NULL;
1840 return -1;
1841 }
1842 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001843 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001844 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001845
1846 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001847 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001848
1849 return 0;
1850}
1851
1852int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001853 FileFormats format,
1854 int startPosition,
1855 float volumeScaling,
1856 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001857 const CodecInst* codecInst)
1858{
1859 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1860 "Channel::StartPlayingFileLocally(format=%d,"
1861 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1862 format, volumeScaling, startPosition, stopPosition);
1863
1864 if(stream == NULL)
1865 {
1866 _engineStatisticsPtr->SetLastError(
1867 VE_BAD_FILE, kTraceError,
1868 "StartPlayingFileLocally() NULL as input stream");
1869 return -1;
1870 }
1871
1872
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001873 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001874 {
1875 _engineStatisticsPtr->SetLastError(
1876 VE_ALREADY_PLAYING, kTraceError,
1877 "StartPlayingFileLocally() is already playing");
1878 return -1;
1879 }
1880
niklase@google.com470e71d2011-07-07 08:21:25 +00001881 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001882 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001883
1884 // Destroy the old instance
1885 if (_outputFilePlayerPtr)
1886 {
1887 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1888 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1889 _outputFilePlayerPtr = NULL;
1890 }
1891
1892 // Create the instance
1893 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1894 _outputFilePlayerId,
1895 (const FileFormats)format);
1896
1897 if (_outputFilePlayerPtr == NULL)
1898 {
1899 _engineStatisticsPtr->SetLastError(
1900 VE_INVALID_ARGUMENT, kTraceError,
1901 "StartPlayingFileLocally() filePlayer format isnot correct");
1902 return -1;
1903 }
1904
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001905 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001906
1907 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1908 volumeScaling,
1909 notificationTime,
1910 stopPosition, codecInst) != 0)
1911 {
1912 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1913 "StartPlayingFile() failed to "
1914 "start file playout");
1915 _outputFilePlayerPtr->StopPlayingFile();
1916 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1917 _outputFilePlayerPtr = NULL;
1918 return -1;
1919 }
1920 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001921 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001922 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001923
1924 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001925 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001926
niklase@google.com470e71d2011-07-07 08:21:25 +00001927 return 0;
1928}
1929
1930int Channel::StopPlayingFileLocally()
1931{
1932 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1933 "Channel::StopPlayingFileLocally()");
1934
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001935 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001936 {
1937 _engineStatisticsPtr->SetLastError(
1938 VE_INVALID_OPERATION, kTraceWarning,
1939 "StopPlayingFileLocally() isnot playing");
1940 return 0;
1941 }
1942
niklase@google.com470e71d2011-07-07 08:21:25 +00001943 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001944 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001945
1946 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1947 {
1948 _engineStatisticsPtr->SetLastError(
1949 VE_STOP_RECORDING_FAILED, kTraceError,
1950 "StopPlayingFile() could not stop playing");
1951 return -1;
1952 }
1953 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1954 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1955 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001956 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001957 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001958 // _fileCritSect cannot be taken while calling
1959 // SetAnonymousMixibilityStatus. Refer to comments in
1960 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001961 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1962 {
1963 _engineStatisticsPtr->SetLastError(
1964 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001965 "StopPlayingFile() failed to stop participant from playing as"
1966 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001967 return -1;
1968 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001969
1970 return 0;
1971}
1972
1973int Channel::IsPlayingFileLocally() const
1974{
1975 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1976 "Channel::IsPlayingFileLocally()");
1977
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001978 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001979}
1980
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001981int Channel::RegisterFilePlayingToMixer()
1982{
1983 // Return success for not registering for file playing to mixer if:
1984 // 1. playing file before playout is started on that channel.
1985 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001986 if (!channel_state_.Get().playing ||
1987 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001988 {
1989 return 0;
1990 }
1991
1992 // |_fileCritSect| cannot be taken while calling
1993 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1994 // frames can be pulled by the mixer. Since the frames are generated from
1995 // the file, _fileCritSect will be taken. This would result in a deadlock.
1996 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1997 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001998 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001999 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002000 _engineStatisticsPtr->SetLastError(
2001 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2002 "StartPlayingFile() failed to add participant as file to mixer");
2003 _outputFilePlayerPtr->StopPlayingFile();
2004 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2005 _outputFilePlayerPtr = NULL;
2006 return -1;
2007 }
2008
2009 return 0;
2010}
2011
niklase@google.com470e71d2011-07-07 08:21:25 +00002012int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002013 bool loop,
2014 FileFormats format,
2015 int startPosition,
2016 float volumeScaling,
2017 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002018 const CodecInst* codecInst)
2019{
2020 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2021 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2022 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2023 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2024 startPosition, stopPosition);
2025
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002026 CriticalSectionScoped cs(&_fileCritSect);
2027
2028 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002029 {
2030 _engineStatisticsPtr->SetLastError(
2031 VE_ALREADY_PLAYING, kTraceWarning,
2032 "StartPlayingFileAsMicrophone() filePlayer is playing");
2033 return 0;
2034 }
2035
niklase@google.com470e71d2011-07-07 08:21:25 +00002036 // Destroy the old instance
2037 if (_inputFilePlayerPtr)
2038 {
2039 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2040 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2041 _inputFilePlayerPtr = NULL;
2042 }
2043
2044 // Create the instance
2045 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2046 _inputFilePlayerId, (const FileFormats)format);
2047
2048 if (_inputFilePlayerPtr == NULL)
2049 {
2050 _engineStatisticsPtr->SetLastError(
2051 VE_INVALID_ARGUMENT, kTraceError,
2052 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2053 return -1;
2054 }
2055
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002056 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002057
2058 if (_inputFilePlayerPtr->StartPlayingFile(
2059 fileName,
2060 loop,
2061 startPosition,
2062 volumeScaling,
2063 notificationTime,
2064 stopPosition,
2065 (const CodecInst*)codecInst) != 0)
2066 {
2067 _engineStatisticsPtr->SetLastError(
2068 VE_BAD_FILE, kTraceError,
2069 "StartPlayingFile() failed to start file playout");
2070 _inputFilePlayerPtr->StopPlayingFile();
2071 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2072 _inputFilePlayerPtr = NULL;
2073 return -1;
2074 }
2075 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002076 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002077
2078 return 0;
2079}
2080
2081int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002082 FileFormats format,
2083 int startPosition,
2084 float volumeScaling,
2085 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002086 const CodecInst* codecInst)
2087{
2088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2089 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2090 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2091 format, volumeScaling, startPosition, stopPosition);
2092
2093 if(stream == NULL)
2094 {
2095 _engineStatisticsPtr->SetLastError(
2096 VE_BAD_FILE, kTraceError,
2097 "StartPlayingFileAsMicrophone NULL as input stream");
2098 return -1;
2099 }
2100
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002101 CriticalSectionScoped cs(&_fileCritSect);
2102
2103 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002104 {
2105 _engineStatisticsPtr->SetLastError(
2106 VE_ALREADY_PLAYING, kTraceWarning,
2107 "StartPlayingFileAsMicrophone() is playing");
2108 return 0;
2109 }
2110
niklase@google.com470e71d2011-07-07 08:21:25 +00002111 // Destroy the old instance
2112 if (_inputFilePlayerPtr)
2113 {
2114 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2115 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2116 _inputFilePlayerPtr = NULL;
2117 }
2118
2119 // Create the instance
2120 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2121 _inputFilePlayerId, (const FileFormats)format);
2122
2123 if (_inputFilePlayerPtr == NULL)
2124 {
2125 _engineStatisticsPtr->SetLastError(
2126 VE_INVALID_ARGUMENT, kTraceError,
2127 "StartPlayingInputFile() filePlayer format isnot correct");
2128 return -1;
2129 }
2130
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002131 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002132
2133 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2134 volumeScaling, notificationTime,
2135 stopPosition, codecInst) != 0)
2136 {
2137 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2138 "StartPlayingFile() failed to start "
2139 "file playout");
2140 _inputFilePlayerPtr->StopPlayingFile();
2141 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2142 _inputFilePlayerPtr = NULL;
2143 return -1;
2144 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002145
niklase@google.com470e71d2011-07-07 08:21:25 +00002146 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002147 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002148
2149 return 0;
2150}
2151
2152int Channel::StopPlayingFileAsMicrophone()
2153{
2154 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2155 "Channel::StopPlayingFileAsMicrophone()");
2156
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002157 CriticalSectionScoped cs(&_fileCritSect);
2158
2159 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002160 {
2161 _engineStatisticsPtr->SetLastError(
2162 VE_INVALID_OPERATION, kTraceWarning,
2163 "StopPlayingFileAsMicrophone() isnot playing");
2164 return 0;
2165 }
2166
niklase@google.com470e71d2011-07-07 08:21:25 +00002167 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2168 {
2169 _engineStatisticsPtr->SetLastError(
2170 VE_STOP_RECORDING_FAILED, kTraceError,
2171 "StopPlayingFile() could not stop playing");
2172 return -1;
2173 }
2174 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2175 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2176 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002177 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002178
2179 return 0;
2180}
2181
2182int Channel::IsPlayingFileAsMicrophone() const
2183{
2184 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2185 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002186 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002187}
2188
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002189int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002190 const CodecInst* codecInst)
2191{
2192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2193 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2194
2195 if (_outputFileRecording)
2196 {
2197 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2198 "StartRecordingPlayout() is already recording");
2199 return 0;
2200 }
2201
2202 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002203 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002204 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2205
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002206 if ((codecInst != NULL) &&
2207 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002208 {
2209 _engineStatisticsPtr->SetLastError(
2210 VE_BAD_ARGUMENT, kTraceError,
2211 "StartRecordingPlayout() invalid compression");
2212 return(-1);
2213 }
2214 if(codecInst == NULL)
2215 {
2216 format = kFileFormatPcm16kHzFile;
2217 codecInst=&dummyCodec;
2218 }
2219 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2220 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2221 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2222 {
2223 format = kFileFormatWavFile;
2224 }
2225 else
2226 {
2227 format = kFileFormatCompressedFile;
2228 }
2229
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002230 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002231
2232 // Destroy the old instance
2233 if (_outputFileRecorderPtr)
2234 {
2235 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2236 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2237 _outputFileRecorderPtr = NULL;
2238 }
2239
2240 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2241 _outputFileRecorderId, (const FileFormats)format);
2242 if (_outputFileRecorderPtr == NULL)
2243 {
2244 _engineStatisticsPtr->SetLastError(
2245 VE_INVALID_ARGUMENT, kTraceError,
2246 "StartRecordingPlayout() fileRecorder format isnot correct");
2247 return -1;
2248 }
2249
2250 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2251 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2252 {
2253 _engineStatisticsPtr->SetLastError(
2254 VE_BAD_FILE, kTraceError,
2255 "StartRecordingAudioFile() failed to start file recording");
2256 _outputFileRecorderPtr->StopRecording();
2257 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2258 _outputFileRecorderPtr = NULL;
2259 return -1;
2260 }
2261 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2262 _outputFileRecording = true;
2263
2264 return 0;
2265}
2266
2267int Channel::StartRecordingPlayout(OutStream* stream,
2268 const CodecInst* codecInst)
2269{
2270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2271 "Channel::StartRecordingPlayout()");
2272
2273 if (_outputFileRecording)
2274 {
2275 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2276 "StartRecordingPlayout() is already recording");
2277 return 0;
2278 }
2279
2280 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002281 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002282 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2283
2284 if (codecInst != NULL && codecInst->channels != 1)
2285 {
2286 _engineStatisticsPtr->SetLastError(
2287 VE_BAD_ARGUMENT, kTraceError,
2288 "StartRecordingPlayout() invalid compression");
2289 return(-1);
2290 }
2291 if(codecInst == NULL)
2292 {
2293 format = kFileFormatPcm16kHzFile;
2294 codecInst=&dummyCodec;
2295 }
2296 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2297 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2298 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2299 {
2300 format = kFileFormatWavFile;
2301 }
2302 else
2303 {
2304 format = kFileFormatCompressedFile;
2305 }
2306
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002307 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002308
2309 // Destroy the old instance
2310 if (_outputFileRecorderPtr)
2311 {
2312 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2313 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2314 _outputFileRecorderPtr = NULL;
2315 }
2316
2317 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2318 _outputFileRecorderId, (const FileFormats)format);
2319 if (_outputFileRecorderPtr == NULL)
2320 {
2321 _engineStatisticsPtr->SetLastError(
2322 VE_INVALID_ARGUMENT, kTraceError,
2323 "StartRecordingPlayout() fileRecorder format isnot correct");
2324 return -1;
2325 }
2326
2327 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2328 notificationTime) != 0)
2329 {
2330 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2331 "StartRecordingPlayout() failed to "
2332 "start file recording");
2333 _outputFileRecorderPtr->StopRecording();
2334 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2335 _outputFileRecorderPtr = NULL;
2336 return -1;
2337 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002338
niklase@google.com470e71d2011-07-07 08:21:25 +00002339 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2340 _outputFileRecording = true;
2341
2342 return 0;
2343}
2344
2345int Channel::StopRecordingPlayout()
2346{
2347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2348 "Channel::StopRecordingPlayout()");
2349
2350 if (!_outputFileRecording)
2351 {
2352 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2353 "StopRecordingPlayout() isnot recording");
2354 return -1;
2355 }
2356
2357
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002358 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002359
2360 if (_outputFileRecorderPtr->StopRecording() != 0)
2361 {
2362 _engineStatisticsPtr->SetLastError(
2363 VE_STOP_RECORDING_FAILED, kTraceError,
2364 "StopRecording() could not stop recording");
2365 return(-1);
2366 }
2367 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2368 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2369 _outputFileRecorderPtr = NULL;
2370 _outputFileRecording = false;
2371
2372 return 0;
2373}
2374
2375void
2376Channel::SetMixWithMicStatus(bool mix)
2377{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002378 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002379 _mixFileWithMicrophone=mix;
2380}
2381
2382int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002383Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002384{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002385 int8_t currentLevel = _outputAudioLevel.Level();
2386 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002387 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2388 VoEId(_instanceId,_channelId),
2389 "GetSpeechOutputLevel() => level=%u", level);
2390 return 0;
2391}
2392
2393int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002394Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002395{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002396 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2397 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002398 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2399 VoEId(_instanceId,_channelId),
2400 "GetSpeechOutputLevelFullRange() => level=%u", level);
2401 return 0;
2402}
2403
2404int
2405Channel::SetMute(bool enable)
2406{
wu@webrtc.org63420662013-10-17 18:28:55 +00002407 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2409 "Channel::SetMute(enable=%d)", enable);
2410 _mute = enable;
2411 return 0;
2412}
2413
2414bool
2415Channel::Mute() const
2416{
wu@webrtc.org63420662013-10-17 18:28:55 +00002417 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002418 return _mute;
2419}
2420
2421int
2422Channel::SetOutputVolumePan(float left, float right)
2423{
wu@webrtc.org63420662013-10-17 18:28:55 +00002424 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2426 "Channel::SetOutputVolumePan()");
2427 _panLeft = left;
2428 _panRight = right;
2429 return 0;
2430}
2431
2432int
2433Channel::GetOutputVolumePan(float& left, float& right) const
2434{
wu@webrtc.org63420662013-10-17 18:28:55 +00002435 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002436 left = _panLeft;
2437 right = _panRight;
2438 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2439 VoEId(_instanceId,_channelId),
2440 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2441 return 0;
2442}
2443
2444int
2445Channel::SetChannelOutputVolumeScaling(float scaling)
2446{
wu@webrtc.org63420662013-10-17 18:28:55 +00002447 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002448 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2449 "Channel::SetChannelOutputVolumeScaling()");
2450 _outputGain = scaling;
2451 return 0;
2452}
2453
2454int
2455Channel::GetChannelOutputVolumeScaling(float& scaling) const
2456{
wu@webrtc.org63420662013-10-17 18:28:55 +00002457 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002458 scaling = _outputGain;
2459 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2460 VoEId(_instanceId,_channelId),
2461 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2462 return 0;
2463}
2464
niklase@google.com470e71d2011-07-07 08:21:25 +00002465int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002466 int lengthMs, int attenuationDb,
2467 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002468{
2469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2470 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2471 playDtmfEvent);
2472
2473 _playOutbandDtmfEvent = playDtmfEvent;
2474
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002475 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 attenuationDb) != 0)
2477 {
2478 _engineStatisticsPtr->SetLastError(
2479 VE_SEND_DTMF_FAILED,
2480 kTraceWarning,
2481 "SendTelephoneEventOutband() failed to send event");
2482 return -1;
2483 }
2484 return 0;
2485}
2486
2487int Channel::SendTelephoneEventInband(unsigned char eventCode,
2488 int lengthMs,
2489 int attenuationDb,
2490 bool playDtmfEvent)
2491{
2492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2493 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2494 playDtmfEvent);
2495
2496 _playInbandDtmfEvent = playDtmfEvent;
2497 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2498
2499 return 0;
2500}
2501
2502int
niklase@google.com470e71d2011-07-07 08:21:25 +00002503Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2504{
2505 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2506 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002507 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002508 {
2509 _engineStatisticsPtr->SetLastError(
2510 VE_INVALID_ARGUMENT, kTraceError,
2511 "SetSendTelephoneEventPayloadType() invalid type");
2512 return -1;
2513 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002514 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002515 codec.plfreq = 8000;
2516 codec.pltype = type;
2517 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002518 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002519 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002520 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2521 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2522 _engineStatisticsPtr->SetLastError(
2523 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2524 "SetSendTelephoneEventPayloadType() failed to register send"
2525 "payload type");
2526 return -1;
2527 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002528 }
2529 _sendTelephoneEventPayloadType = type;
2530 return 0;
2531}
2532
2533int
2534Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2535{
2536 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2537 "Channel::GetSendTelephoneEventPayloadType()");
2538 type = _sendTelephoneEventPayloadType;
2539 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2540 VoEId(_instanceId,_channelId),
2541 "GetSendTelephoneEventPayloadType() => type=%u", type);
2542 return 0;
2543}
2544
niklase@google.com470e71d2011-07-07 08:21:25 +00002545int
2546Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2547{
2548 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2549 "Channel::UpdateRxVadDetection()");
2550
2551 int vadDecision = 1;
2552
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002553 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002554
2555 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2556 {
2557 OnRxVadDetected(vadDecision);
2558 _oldVadDecision = vadDecision;
2559 }
2560
2561 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2562 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2563 vadDecision);
2564 return 0;
2565}
2566
2567int
2568Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2569{
2570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2571 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002572 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002573
2574 if (_rxVadObserverPtr)
2575 {
2576 _engineStatisticsPtr->SetLastError(
2577 VE_INVALID_OPERATION, kTraceError,
2578 "RegisterRxVadObserver() observer already enabled");
2579 return -1;
2580 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002581 _rxVadObserverPtr = &observer;
2582 _RxVadDetection = true;
2583 return 0;
2584}
2585
2586int
2587Channel::DeRegisterRxVadObserver()
2588{
2589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2590 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002591 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002592
2593 if (!_rxVadObserverPtr)
2594 {
2595 _engineStatisticsPtr->SetLastError(
2596 VE_INVALID_OPERATION, kTraceWarning,
2597 "DeRegisterRxVadObserver() observer already disabled");
2598 return 0;
2599 }
2600 _rxVadObserverPtr = NULL;
2601 _RxVadDetection = false;
2602 return 0;
2603}
2604
2605int
2606Channel::VoiceActivityIndicator(int &activity)
2607{
2608 activity = _sendFrameType;
2609
2610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002611 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002612 return 0;
2613}
2614
2615#ifdef WEBRTC_VOICE_ENGINE_AGC
2616
2617int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002618Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002619{
2620 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2621 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2622 (int)enable, (int)mode);
2623
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002624 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002625 switch (mode)
2626 {
2627 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002628 break;
2629 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002630 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002631 break;
2632 case kAgcFixedDigital:
2633 agcMode = GainControl::kFixedDigital;
2634 break;
2635 case kAgcAdaptiveDigital:
2636 agcMode =GainControl::kAdaptiveDigital;
2637 break;
2638 default:
2639 _engineStatisticsPtr->SetLastError(
2640 VE_INVALID_ARGUMENT, kTraceError,
2641 "SetRxAgcStatus() invalid Agc mode");
2642 return -1;
2643 }
2644
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002645 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002646 {
2647 _engineStatisticsPtr->SetLastError(
2648 VE_APM_ERROR, kTraceError,
2649 "SetRxAgcStatus() failed to set Agc mode");
2650 return -1;
2651 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002652 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002653 {
2654 _engineStatisticsPtr->SetLastError(
2655 VE_APM_ERROR, kTraceError,
2656 "SetRxAgcStatus() failed to set Agc state");
2657 return -1;
2658 }
2659
2660 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002661 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002662
2663 return 0;
2664}
2665
2666int
2667Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2668{
2669 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2670 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2671
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002672 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002673 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002674 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002675
2676 enabled = enable;
2677
2678 switch (agcMode)
2679 {
2680 case GainControl::kFixedDigital:
2681 mode = kAgcFixedDigital;
2682 break;
2683 case GainControl::kAdaptiveDigital:
2684 mode = kAgcAdaptiveDigital;
2685 break;
2686 default:
2687 _engineStatisticsPtr->SetLastError(
2688 VE_APM_ERROR, kTraceError,
2689 "GetRxAgcStatus() invalid Agc mode");
2690 return -1;
2691 }
2692
2693 return 0;
2694}
2695
2696int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002697Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002698{
2699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2700 "Channel::SetRxAgcConfig()");
2701
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002702 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002703 config.targetLeveldBOv) != 0)
2704 {
2705 _engineStatisticsPtr->SetLastError(
2706 VE_APM_ERROR, kTraceError,
2707 "SetRxAgcConfig() failed to set target peak |level|"
2708 "(or envelope) of the Agc");
2709 return -1;
2710 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002711 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002712 config.digitalCompressionGaindB) != 0)
2713 {
2714 _engineStatisticsPtr->SetLastError(
2715 VE_APM_ERROR, kTraceError,
2716 "SetRxAgcConfig() failed to set the range in |gain| the"
2717 " digital compression stage may apply");
2718 return -1;
2719 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002720 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002721 config.limiterEnable) != 0)
2722 {
2723 _engineStatisticsPtr->SetLastError(
2724 VE_APM_ERROR, kTraceError,
2725 "SetRxAgcConfig() failed to set hard limiter to the signal");
2726 return -1;
2727 }
2728
2729 return 0;
2730}
2731
2732int
2733Channel::GetRxAgcConfig(AgcConfig& config)
2734{
2735 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2736 "Channel::GetRxAgcConfig(config=%?)");
2737
2738 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002739 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002740 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002741 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002742 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002743 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002744
2745 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2746 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2747 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2748 " limiterEnable=%d",
2749 config.targetLeveldBOv,
2750 config.digitalCompressionGaindB,
2751 config.limiterEnable);
2752
2753 return 0;
2754}
2755
2756#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2757
2758#ifdef WEBRTC_VOICE_ENGINE_NR
2759
2760int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002761Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002762{
2763 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2764 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2765 (int)enable, (int)mode);
2766
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002767 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002768 switch (mode)
2769 {
2770
2771 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002772 break;
2773 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002774 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002775 break;
2776 case kNsConference:
2777 nsLevel = NoiseSuppression::kHigh;
2778 break;
2779 case kNsLowSuppression:
2780 nsLevel = NoiseSuppression::kLow;
2781 break;
2782 case kNsModerateSuppression:
2783 nsLevel = NoiseSuppression::kModerate;
2784 break;
2785 case kNsHighSuppression:
2786 nsLevel = NoiseSuppression::kHigh;
2787 break;
2788 case kNsVeryHighSuppression:
2789 nsLevel = NoiseSuppression::kVeryHigh;
2790 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002791 }
2792
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002793 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002794 != 0)
2795 {
2796 _engineStatisticsPtr->SetLastError(
2797 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002798 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002799 return -1;
2800 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002801 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 {
2803 _engineStatisticsPtr->SetLastError(
2804 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002805 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002806 return -1;
2807 }
2808
2809 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002810 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002811
2812 return 0;
2813}
2814
2815int
2816Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2817{
2818 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2819 "Channel::GetRxNsStatus(enable=?, mode=?)");
2820
2821 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002822 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002823 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002824 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002825
2826 enabled = enable;
2827
2828 switch (ncLevel)
2829 {
2830 case NoiseSuppression::kLow:
2831 mode = kNsLowSuppression;
2832 break;
2833 case NoiseSuppression::kModerate:
2834 mode = kNsModerateSuppression;
2835 break;
2836 case NoiseSuppression::kHigh:
2837 mode = kNsHighSuppression;
2838 break;
2839 case NoiseSuppression::kVeryHigh:
2840 mode = kNsVeryHighSuppression;
2841 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002842 }
2843
2844 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2845 VoEId(_instanceId,_channelId),
2846 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2847 return 0;
2848}
2849
2850#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2851
2852int
niklase@google.com470e71d2011-07-07 08:21:25 +00002853Channel::SetLocalSSRC(unsigned int ssrc)
2854{
2855 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2856 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002857 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002858 {
2859 _engineStatisticsPtr->SetLastError(
2860 VE_ALREADY_SENDING, kTraceError,
2861 "SetLocalSSRC() already sending");
2862 return -1;
2863 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002864 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002865 return 0;
2866}
2867
2868int
2869Channel::GetLocalSSRC(unsigned int& ssrc)
2870{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002871 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002872 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2873 VoEId(_instanceId,_channelId),
2874 "GetLocalSSRC() => ssrc=%lu", ssrc);
2875 return 0;
2876}
2877
2878int
2879Channel::GetRemoteSSRC(unsigned int& ssrc)
2880{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002881 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002882 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2883 VoEId(_instanceId,_channelId),
2884 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2885 return 0;
2886}
2887
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002888int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002889 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002890 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002891}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002892
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002893int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2894 unsigned char id) {
2895 rtp_header_parser_->DeregisterRtpHeaderExtension(
2896 kRtpExtensionAudioLevel);
2897 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2898 kRtpExtensionAudioLevel, id)) {
2899 return -1;
2900 }
2901 return 0;
2902}
2903
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002904int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2905 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2906}
2907
2908int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2909 rtp_header_parser_->DeregisterRtpHeaderExtension(
2910 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002911 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2912 kRtpExtensionAbsoluteSendTime, id)) {
2913 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002914 }
2915 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002916}
2917
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002918void Channel::SetRTCPStatus(bool enable) {
2919 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2920 "Channel::SetRTCPStatus()");
2921 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002922}
2923
2924int
2925Channel::GetRTCPStatus(bool& enabled)
2926{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002927 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002928 enabled = (method != kRtcpOff);
2929 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2930 VoEId(_instanceId,_channelId),
2931 "GetRTCPStatus() => enabled=%d", enabled);
2932 return 0;
2933}
2934
2935int
2936Channel::SetRTCP_CNAME(const char cName[256])
2937{
2938 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2939 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002940 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 {
2942 _engineStatisticsPtr->SetLastError(
2943 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2944 "SetRTCP_CNAME() failed to set RTCP CNAME");
2945 return -1;
2946 }
2947 return 0;
2948}
2949
2950int
niklase@google.com470e71d2011-07-07 08:21:25 +00002951Channel::GetRemoteRTCP_CNAME(char cName[256])
2952{
2953 if (cName == NULL)
2954 {
2955 _engineStatisticsPtr->SetLastError(
2956 VE_INVALID_ARGUMENT, kTraceError,
2957 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2958 return -1;
2959 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002960 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002961 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002962 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002963 {
2964 _engineStatisticsPtr->SetLastError(
2965 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2966 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2967 return -1;
2968 }
2969 strcpy(cName, cname);
2970 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2971 VoEId(_instanceId, _channelId),
2972 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2973 return 0;
2974}
2975
2976int
2977Channel::GetRemoteRTCPData(
2978 unsigned int& NTPHigh,
2979 unsigned int& NTPLow,
2980 unsigned int& timestamp,
2981 unsigned int& playoutTimestamp,
2982 unsigned int* jitter,
2983 unsigned short* fractionLost)
2984{
2985 // --- Information from sender info in received Sender Reports
2986
2987 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002988 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002989 {
2990 _engineStatisticsPtr->SetLastError(
2991 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002992 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002993 "side");
2994 return -1;
2995 }
2996
2997 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2998 // and octet count)
2999 NTPHigh = senderInfo.NTPseconds;
3000 NTPLow = senderInfo.NTPfraction;
3001 timestamp = senderInfo.RTPtimeStamp;
3002
3003 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3004 VoEId(_instanceId, _channelId),
3005 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3006 "timestamp=%lu",
3007 NTPHigh, NTPLow, timestamp);
3008
3009 // --- Locally derived information
3010
3011 // This value is updated on each incoming RTCP packet (0 when no packet
3012 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003013 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003014
3015 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3016 VoEId(_instanceId, _channelId),
3017 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003018 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003019
3020 if (NULL != jitter || NULL != fractionLost)
3021 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003022 // Get all RTCP receiver report blocks that have been received on this
3023 // channel. If we receive RTP packets from a remote source we know the
3024 // remote SSRC and use the report block from him.
3025 // Otherwise use the first report block.
3026 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003027 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003028 remote_stats.empty()) {
3029 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3030 VoEId(_instanceId, _channelId),
3031 "GetRemoteRTCPData() failed to measure statistics due"
3032 " to lack of received RTP and/or RTCP packets");
3033 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003034 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003035
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003036 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003037 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3038 for (; it != remote_stats.end(); ++it) {
3039 if (it->remoteSSRC == remoteSSRC)
3040 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003041 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003042
3043 if (it == remote_stats.end()) {
3044 // If we have not received any RTCP packets from this SSRC it probably
3045 // means that we have not received any RTP packets.
3046 // Use the first received report block instead.
3047 it = remote_stats.begin();
3048 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003049 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003050
xians@webrtc.org79af7342012-01-31 12:22:14 +00003051 if (jitter) {
3052 *jitter = it->jitter;
3053 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3054 VoEId(_instanceId, _channelId),
3055 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3056 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003057
xians@webrtc.org79af7342012-01-31 12:22:14 +00003058 if (fractionLost) {
3059 *fractionLost = it->fractionLost;
3060 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3061 VoEId(_instanceId, _channelId),
3062 "GetRemoteRTCPData() => fractionLost = %lu",
3063 *fractionLost);
3064 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003065 }
3066 return 0;
3067}
3068
3069int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003070Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003071 unsigned int name,
3072 const char* data,
3073 unsigned short dataLengthInBytes)
3074{
3075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3076 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003077 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003078 {
3079 _engineStatisticsPtr->SetLastError(
3080 VE_NOT_SENDING, kTraceError,
3081 "SendApplicationDefinedRTCPPacket() not sending");
3082 return -1;
3083 }
3084 if (NULL == data)
3085 {
3086 _engineStatisticsPtr->SetLastError(
3087 VE_INVALID_ARGUMENT, kTraceError,
3088 "SendApplicationDefinedRTCPPacket() invalid data value");
3089 return -1;
3090 }
3091 if (dataLengthInBytes % 4 != 0)
3092 {
3093 _engineStatisticsPtr->SetLastError(
3094 VE_INVALID_ARGUMENT, kTraceError,
3095 "SendApplicationDefinedRTCPPacket() invalid length value");
3096 return -1;
3097 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003098 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003099 if (status == kRtcpOff)
3100 {
3101 _engineStatisticsPtr->SetLastError(
3102 VE_RTCP_ERROR, kTraceError,
3103 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3104 return -1;
3105 }
3106
3107 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003108 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003109 subType,
3110 name,
3111 (const unsigned char*) data,
3112 dataLengthInBytes) != 0)
3113 {
3114 _engineStatisticsPtr->SetLastError(
3115 VE_SEND_ERROR, kTraceError,
3116 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3117 return -1;
3118 }
3119 return 0;
3120}
3121
3122int
3123Channel::GetRTPStatistics(
3124 unsigned int& averageJitterMs,
3125 unsigned int& maxJitterMs,
3126 unsigned int& discardedPackets)
3127{
niklase@google.com470e71d2011-07-07 08:21:25 +00003128 // The jitter statistics is updated for each received RTP packet and is
3129 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003130 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3131 // If RTCP is off, there is no timed thread in the RTCP module regularly
3132 // generating new stats, trigger the update manually here instead.
3133 StreamStatistician* statistician =
3134 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3135 if (statistician) {
3136 // Don't use returned statistics, use data from proxy instead so that
3137 // max jitter can be fetched atomically.
3138 RtcpStatistics s;
3139 statistician->GetStatistics(&s, true);
3140 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003141 }
3142
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003143 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003144 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003145 if (playoutFrequency > 0) {
3146 // Scale RTP statistics given the current playout frequency
3147 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3148 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003149 }
3150
3151 discardedPackets = _numberOfDiscardedPackets;
3152
3153 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3154 VoEId(_instanceId, _channelId),
3155 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003156 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003157 averageJitterMs, maxJitterMs, discardedPackets);
3158 return 0;
3159}
3160
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003161int Channel::GetRemoteRTCPReportBlocks(
3162 std::vector<ReportBlock>* report_blocks) {
3163 if (report_blocks == NULL) {
3164 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3165 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3166 return -1;
3167 }
3168
3169 // Get the report blocks from the latest received RTCP Sender or Receiver
3170 // Report. Each element in the vector contains the sender's SSRC and a
3171 // report block according to RFC 3550.
3172 std::vector<RTCPReportBlock> rtcp_report_blocks;
3173 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3174 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3175 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3176 return -1;
3177 }
3178
3179 if (rtcp_report_blocks.empty())
3180 return 0;
3181
3182 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3183 for (; it != rtcp_report_blocks.end(); ++it) {
3184 ReportBlock report_block;
3185 report_block.sender_SSRC = it->remoteSSRC;
3186 report_block.source_SSRC = it->sourceSSRC;
3187 report_block.fraction_lost = it->fractionLost;
3188 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3189 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3190 report_block.interarrival_jitter = it->jitter;
3191 report_block.last_SR_timestamp = it->lastSR;
3192 report_block.delay_since_last_SR = it->delaySinceLastSR;
3193 report_blocks->push_back(report_block);
3194 }
3195 return 0;
3196}
3197
niklase@google.com470e71d2011-07-07 08:21:25 +00003198int
3199Channel::GetRTPStatistics(CallStatistics& stats)
3200{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003201 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003202
3203 // The jitter statistics is updated for each received RTP packet and is
3204 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003205 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003206 StreamStatistician* statistician =
3207 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3208 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003209 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3210 _engineStatisticsPtr->SetLastError(
3211 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3212 "GetRTPStatistics() failed to read RTP statistics from the "
3213 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003214 }
3215
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003216 stats.fractionLost = statistics.fraction_lost;
3217 stats.cumulativeLost = statistics.cumulative_lost;
3218 stats.extendedMax = statistics.extended_max_sequence_number;
3219 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003220
3221 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3222 VoEId(_instanceId, _channelId),
3223 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003224 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003225 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3226 stats.jitterSamples);
3227
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003228 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003229 stats.rttMs = GetRTT();
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003230 if (stats.rttMs == 0) {
3231 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3232 "GetRTPStatistics() failed to get RTT");
3233 } else {
3234 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003235 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003236 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003237
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003238 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003239
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003240 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003241 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003242 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003243 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003244
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003245 if (statistician) {
3246 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3247 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003248
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003249 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003250 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003251 {
3252 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3253 VoEId(_instanceId, _channelId),
3254 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003255 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003256 }
3257
3258 stats.bytesSent = bytesSent;
3259 stats.packetsSent = packetsSent;
3260 stats.bytesReceived = bytesReceived;
3261 stats.packetsReceived = packetsReceived;
3262
3263 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3264 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003265 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3266 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003267 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3268 stats.packetsReceived);
3269
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003270 // --- Timestamps
3271 {
3272 CriticalSectionScoped lock(ts_stats_lock_.get());
3273 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3274 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003275 return 0;
3276}
3277
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003278int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003279 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003280 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003281
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003282 if (enable) {
3283 if (redPayloadtype < 0 || redPayloadtype > 127) {
3284 _engineStatisticsPtr->SetLastError(
3285 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003286 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003287 return -1;
3288 }
3289
3290 if (SetRedPayloadType(redPayloadtype) < 0) {
3291 _engineStatisticsPtr->SetLastError(
3292 VE_CODEC_ERROR, kTraceError,
3293 "SetSecondarySendCodec() Failed to register RED ACM");
3294 return -1;
3295 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003296 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003297
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003298 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003299 _engineStatisticsPtr->SetLastError(
3300 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003301 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003302 return -1;
3303 }
3304 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003305}
3306
3307int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003308Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003309{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003310 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003311 if (enabled)
3312 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003313 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003314 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003315 {
3316 _engineStatisticsPtr->SetLastError(
3317 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003318 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003319 "module");
3320 return -1;
3321 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003322 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003323 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3324 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003325 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003326 enabled, redPayloadtype);
3327 return 0;
3328 }
3329 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3330 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003331 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003332 return 0;
3333}
3334
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003335int Channel::SetCodecFECStatus(bool enable) {
3336 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3337 "Channel::SetCodecFECStatus()");
3338
3339 if (audio_coding_->SetCodecFEC(enable) != 0) {
3340 _engineStatisticsPtr->SetLastError(
3341 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3342 "SetCodecFECStatus() failed to set FEC state");
3343 return -1;
3344 }
3345 return 0;
3346}
3347
3348bool Channel::GetCodecFECStatus() {
3349 bool enabled = audio_coding_->CodecFEC();
3350 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3351 VoEId(_instanceId, _channelId),
3352 "GetCodecFECStatus() => enabled=%d", enabled);
3353 return enabled;
3354}
3355
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003356void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3357 // None of these functions can fail.
3358 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003359 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3360 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003361 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003362 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003363 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003364 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003365}
3366
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003367// Called when we are missing one or more packets.
3368int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003369 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3370}
3371
niklase@google.com470e71d2011-07-07 08:21:25 +00003372int
niklase@google.com470e71d2011-07-07 08:21:25 +00003373Channel::StartRTPDump(const char fileNameUTF8[1024],
3374 RTPDirections direction)
3375{
3376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3377 "Channel::StartRTPDump()");
3378 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3379 {
3380 _engineStatisticsPtr->SetLastError(
3381 VE_INVALID_ARGUMENT, kTraceError,
3382 "StartRTPDump() invalid RTP direction");
3383 return -1;
3384 }
3385 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3386 &_rtpDumpIn : &_rtpDumpOut;
3387 if (rtpDumpPtr == NULL)
3388 {
3389 assert(false);
3390 return -1;
3391 }
3392 if (rtpDumpPtr->IsActive())
3393 {
3394 rtpDumpPtr->Stop();
3395 }
3396 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3397 {
3398 _engineStatisticsPtr->SetLastError(
3399 VE_BAD_FILE, kTraceError,
3400 "StartRTPDump() failed to create file");
3401 return -1;
3402 }
3403 return 0;
3404}
3405
3406int
3407Channel::StopRTPDump(RTPDirections direction)
3408{
3409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3410 "Channel::StopRTPDump()");
3411 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3412 {
3413 _engineStatisticsPtr->SetLastError(
3414 VE_INVALID_ARGUMENT, kTraceError,
3415 "StopRTPDump() invalid RTP direction");
3416 return -1;
3417 }
3418 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3419 &_rtpDumpIn : &_rtpDumpOut;
3420 if (rtpDumpPtr == NULL)
3421 {
3422 assert(false);
3423 return -1;
3424 }
3425 if (!rtpDumpPtr->IsActive())
3426 {
3427 return 0;
3428 }
3429 return rtpDumpPtr->Stop();
3430}
3431
3432bool
3433Channel::RTPDumpIsActive(RTPDirections direction)
3434{
3435 if ((direction != kRtpIncoming) &&
3436 (direction != kRtpOutgoing))
3437 {
3438 _engineStatisticsPtr->SetLastError(
3439 VE_INVALID_ARGUMENT, kTraceError,
3440 "RTPDumpIsActive() invalid RTP direction");
3441 return false;
3442 }
3443 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3444 &_rtpDumpIn : &_rtpDumpOut;
3445 return rtpDumpPtr->IsActive();
3446}
3447
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003448uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003449Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003450{
3451 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003452 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003453 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003454 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003455 return 0;
3456}
3457
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003458void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003459 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003460 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003461 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003462 CodecInst codec;
3463 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003464
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003465 if (!mono_recording_audio_.get()) {
3466 // Temporary space for DownConvertToCodecFormat.
3467 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003468 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003469 DownConvertToCodecFormat(audio_data,
3470 number_of_frames,
3471 number_of_channels,
3472 sample_rate,
3473 codec.channels,
3474 codec.plfreq,
3475 mono_recording_audio_.get(),
3476 &input_resampler_,
3477 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003478}
3479
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003480uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003481Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003482{
3483 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3484 "Channel::PrepareEncodeAndSend()");
3485
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003486 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003487 {
3488 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3489 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003490 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003491 }
3492
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003493 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003494 {
3495 MixOrReplaceAudioWithFile(mixingFrequency);
3496 }
3497
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003498 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3499 if (is_muted) {
3500 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003501 }
3502
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003503 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003505 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003506 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003507 if (_inputExternalMediaCallbackPtr)
3508 {
3509 _inputExternalMediaCallbackPtr->Process(
3510 _channelId,
3511 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003512 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003513 _audioFrame.samples_per_channel_,
3514 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003515 isStereo);
3516 }
3517 }
3518
3519 InsertInbandDtmfTone();
3520
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003521 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003522 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003523 if (is_muted) {
3524 rms_level_.ProcessMuted(length);
3525 } else {
3526 rms_level_.Process(_audioFrame.data_, length);
3527 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003528 }
3529
niklase@google.com470e71d2011-07-07 08:21:25 +00003530 return 0;
3531}
3532
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003533uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003534Channel::EncodeAndSend()
3535{
3536 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3537 "Channel::EncodeAndSend()");
3538
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003539 assert(_audioFrame.num_channels_ <= 2);
3540 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003541 {
3542 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3543 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003544 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003545 }
3546
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003547 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003548
3549 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3550
3551 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003552 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003553 // This call will trigger AudioPacketizationCallback::SendData if encoding
3554 // is done and payload is ready for packetization and transmission.
3555 // Otherwise, it will return without invoking the callback.
3556 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003557 {
3558 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3559 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003560 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003561 }
3562
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003563 _timeStamp += _audioFrame.samples_per_channel_;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003564 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003565}
3566
3567int Channel::RegisterExternalMediaProcessing(
3568 ProcessingTypes type,
3569 VoEMediaProcess& processObject)
3570{
3571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3572 "Channel::RegisterExternalMediaProcessing()");
3573
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003574 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003575
3576 if (kPlaybackPerChannel == type)
3577 {
3578 if (_outputExternalMediaCallbackPtr)
3579 {
3580 _engineStatisticsPtr->SetLastError(
3581 VE_INVALID_OPERATION, kTraceError,
3582 "Channel::RegisterExternalMediaProcessing() "
3583 "output external media already enabled");
3584 return -1;
3585 }
3586 _outputExternalMediaCallbackPtr = &processObject;
3587 _outputExternalMedia = true;
3588 }
3589 else if (kRecordingPerChannel == type)
3590 {
3591 if (_inputExternalMediaCallbackPtr)
3592 {
3593 _engineStatisticsPtr->SetLastError(
3594 VE_INVALID_OPERATION, kTraceError,
3595 "Channel::RegisterExternalMediaProcessing() "
3596 "output external media already enabled");
3597 return -1;
3598 }
3599 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003600 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003601 }
3602 return 0;
3603}
3604
3605int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3606{
3607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3608 "Channel::DeRegisterExternalMediaProcessing()");
3609
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003610 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003611
3612 if (kPlaybackPerChannel == type)
3613 {
3614 if (!_outputExternalMediaCallbackPtr)
3615 {
3616 _engineStatisticsPtr->SetLastError(
3617 VE_INVALID_OPERATION, kTraceWarning,
3618 "Channel::DeRegisterExternalMediaProcessing() "
3619 "output external media already disabled");
3620 return 0;
3621 }
3622 _outputExternalMedia = false;
3623 _outputExternalMediaCallbackPtr = NULL;
3624 }
3625 else if (kRecordingPerChannel == type)
3626 {
3627 if (!_inputExternalMediaCallbackPtr)
3628 {
3629 _engineStatisticsPtr->SetLastError(
3630 VE_INVALID_OPERATION, kTraceWarning,
3631 "Channel::DeRegisterExternalMediaProcessing() "
3632 "input external media already disabled");
3633 return 0;
3634 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003635 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003636 _inputExternalMediaCallbackPtr = NULL;
3637 }
3638
3639 return 0;
3640}
3641
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003642int Channel::SetExternalMixing(bool enabled) {
3643 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3644 "Channel::SetExternalMixing(enabled=%d)", enabled);
3645
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003646 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003647 {
3648 _engineStatisticsPtr->SetLastError(
3649 VE_INVALID_OPERATION, kTraceError,
3650 "Channel::SetExternalMixing() "
3651 "external mixing cannot be changed while playing.");
3652 return -1;
3653 }
3654
3655 _externalMixing = enabled;
3656
3657 return 0;
3658}
3659
niklase@google.com470e71d2011-07-07 08:21:25 +00003660int
niklase@google.com470e71d2011-07-07 08:21:25 +00003661Channel::GetNetworkStatistics(NetworkStatistics& stats)
3662{
3663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3664 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003665 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003666}
3667
wu@webrtc.org24301a62013-12-13 19:17:43 +00003668void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3669 audio_coding_->GetDecodingCallStatistics(stats);
3670}
3671
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003672bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3673 int* playout_buffer_delay_ms) const {
3674 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003675 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003676 "Channel::GetDelayEstimate() no valid estimate.");
3677 return false;
3678 }
3679 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3680 _recPacketDelayMs;
3681 *playout_buffer_delay_ms = playout_delay_ms_;
3682 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3683 "Channel::GetDelayEstimate()");
3684 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003685}
3686
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003687int Channel::SetInitialPlayoutDelay(int delay_ms)
3688{
3689 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3690 "Channel::SetInitialPlayoutDelay()");
3691 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3692 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3693 {
3694 _engineStatisticsPtr->SetLastError(
3695 VE_INVALID_ARGUMENT, kTraceError,
3696 "SetInitialPlayoutDelay() invalid min delay");
3697 return -1;
3698 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003699 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003700 {
3701 _engineStatisticsPtr->SetLastError(
3702 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3703 "SetInitialPlayoutDelay() failed to set min playout delay");
3704 return -1;
3705 }
3706 return 0;
3707}
3708
3709
niklase@google.com470e71d2011-07-07 08:21:25 +00003710int
3711Channel::SetMinimumPlayoutDelay(int delayMs)
3712{
3713 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3714 "Channel::SetMinimumPlayoutDelay()");
3715 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3716 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3717 {
3718 _engineStatisticsPtr->SetLastError(
3719 VE_INVALID_ARGUMENT, kTraceError,
3720 "SetMinimumPlayoutDelay() invalid min delay");
3721 return -1;
3722 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003723 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3727 "SetMinimumPlayoutDelay() failed to set min playout delay");
3728 return -1;
3729 }
3730 return 0;
3731}
3732
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003733void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3734 uint32_t playout_timestamp = 0;
3735
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003736 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003737 // This can happen if this channel has not been received any RTP packet. In
3738 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003739 return;
3740 }
3741
3742 uint16_t delay_ms = 0;
3743 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3744 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3745 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3746 " delay from the ADM");
3747 _engineStatisticsPtr->SetLastError(
3748 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3749 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3750 return;
3751 }
3752
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003753 jitter_buffer_playout_timestamp_ = playout_timestamp;
3754
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003755 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003756 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003757
3758 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3759 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3760 playout_timestamp);
3761
3762 if (rtcp) {
3763 playout_timestamp_rtcp_ = playout_timestamp;
3764 } else {
3765 playout_timestamp_rtp_ = playout_timestamp;
3766 }
3767 playout_delay_ms_ = delay_ms;
3768}
3769
3770int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3771 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3772 "Channel::GetPlayoutTimestamp()");
3773 if (playout_timestamp_rtp_ == 0) {
3774 _engineStatisticsPtr->SetLastError(
3775 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3776 "GetPlayoutTimestamp() failed to retrieve timestamp");
3777 return -1;
3778 }
3779 timestamp = playout_timestamp_rtp_;
3780 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3781 VoEId(_instanceId,_channelId),
3782 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3783 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003784}
3785
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003786int Channel::SetInitTimestamp(unsigned int timestamp) {
3787 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003788 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003789 if (channel_state_.Get().sending) {
3790 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3791 "SetInitTimestamp() already sending");
3792 return -1;
3793 }
3794 _rtpRtcpModule->SetStartTimestamp(timestamp);
3795 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003796}
3797
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003798int Channel::SetInitSequenceNumber(short sequenceNumber) {
3799 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3800 "Channel::SetInitSequenceNumber()");
3801 if (channel_state_.Get().sending) {
3802 _engineStatisticsPtr->SetLastError(
3803 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3804 return -1;
3805 }
3806 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3807 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003808}
3809
3810int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003811Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003812{
3813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3814 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003815 *rtpRtcpModule = _rtpRtcpModule.get();
3816 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003817 return 0;
3818}
3819
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003820// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3821// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003822int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003823Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003824{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003825 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003826 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003827
3828 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003829 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003830
3831 if (_inputFilePlayerPtr == NULL)
3832 {
3833 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3834 VoEId(_instanceId, _channelId),
3835 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3836 " doesnt exist");
3837 return -1;
3838 }
3839
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003840 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003841 fileSamples,
3842 mixingFrequency) == -1)
3843 {
3844 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3845 VoEId(_instanceId, _channelId),
3846 "Channel::MixOrReplaceAudioWithFile() file mixing "
3847 "failed");
3848 return -1;
3849 }
3850 if (fileSamples == 0)
3851 {
3852 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3853 VoEId(_instanceId, _channelId),
3854 "Channel::MixOrReplaceAudioWithFile() file is ended");
3855 return 0;
3856 }
3857 }
3858
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003859 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003860
3861 if (_mixFileWithMicrophone)
3862 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003863 // Currently file stream is always mono.
3864 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003865 MixWithSat(_audioFrame.data_,
3866 _audioFrame.num_channels_,
3867 fileBuffer.get(),
3868 1,
3869 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003870 }
3871 else
3872 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003873 // Replace ACM audio with file.
3874 // Currently file stream is always mono.
3875 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003876 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003877 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003878 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003879 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003880 mixingFrequency,
3881 AudioFrame::kNormalSpeech,
3882 AudioFrame::kVadUnknown,
3883 1);
3884
3885 }
3886 return 0;
3887}
3888
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003889int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003890Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003891 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003892{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003893 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003894
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003895 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003896 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003897
3898 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003899 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003900
3901 if (_outputFilePlayerPtr == NULL)
3902 {
3903 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3904 VoEId(_instanceId, _channelId),
3905 "Channel::MixAudioWithFile() file mixing failed");
3906 return -1;
3907 }
3908
3909 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003910 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003911 fileSamples,
3912 mixingFrequency) == -1)
3913 {
3914 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3915 VoEId(_instanceId, _channelId),
3916 "Channel::MixAudioWithFile() file mixing failed");
3917 return -1;
3918 }
3919 }
3920
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003921 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003922 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003923 // Currently file stream is always mono.
3924 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003925 MixWithSat(audioFrame.data_,
3926 audioFrame.num_channels_,
3927 fileBuffer.get(),
3928 1,
3929 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003930 }
3931 else
3932 {
3933 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003934 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003935 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003936 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003937 return -1;
3938 }
3939
3940 return 0;
3941}
3942
3943int
3944Channel::InsertInbandDtmfTone()
3945{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003946 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003947 if (_inbandDtmfQueue.PendingDtmf() &&
3948 !_inbandDtmfGenerator.IsAddingTone() &&
3949 _inbandDtmfGenerator.DelaySinceLastTone() >
3950 kMinTelephoneEventSeparationMs)
3951 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003952 int8_t eventCode(0);
3953 uint16_t lengthMs(0);
3954 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003955
3956 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3957 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3958 if (_playInbandDtmfEvent)
3959 {
3960 // Add tone to output mixer using a reduced length to minimize
3961 // risk of echo.
3962 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3963 attenuationDb);
3964 }
3965 }
3966
3967 if (_inbandDtmfGenerator.IsAddingTone())
3968 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003969 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003970 _inbandDtmfGenerator.GetSampleRate(frequency);
3971
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003972 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003973 {
3974 // Update sample rate of Dtmf tone since the mixing frequency
3975 // has changed.
3976 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003977 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003978 // Reset the tone to be added taking the new sample rate into
3979 // account.
3980 _inbandDtmfGenerator.ResetTone();
3981 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003982
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003983 int16_t toneBuffer[320];
3984 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003985 // Get 10ms tone segment and set time since last tone to zero
3986 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3987 {
3988 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3989 VoEId(_instanceId, _channelId),
3990 "Channel::EncodeAndSend() inserting Dtmf failed");
3991 return -1;
3992 }
3993
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003994 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003995 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003996 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003997 sample++)
3998 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003999 for (int channel = 0;
4000 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004001 channel++)
4002 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004003 const int index = sample * _audioFrame.num_channels_ + channel;
4004 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004005 }
4006 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004007
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004008 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004009 } else
4010 {
4011 // Add 10ms to "delay-since-last-tone" counter
4012 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4013 }
4014 return 0;
4015}
4016
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004017int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00004018Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00004019{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004020 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004021 if (_transportPtr == NULL)
4022 {
4023 return -1;
4024 }
4025 if (!RTCP)
4026 {
4027 return _transportPtr->SendPacket(_channelId, data, len);
4028 }
4029 else
4030 {
4031 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4032 }
4033}
4034
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004035// Called for incoming RTP packets after successful RTP header parsing.
4036void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4037 uint16_t sequence_number) {
4038 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4039 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4040 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004041
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004042 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004043 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004044
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004045 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004046 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004047
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004048 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4049 // every incoming packet.
4050 uint32_t timestamp_diff_ms = (rtp_timestamp -
4051 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004052 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4053 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4054 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4055 // timestamp, the resulting difference is negative, but is set to zero.
4056 // This can happen when a network glitch causes a packet to arrive late,
4057 // and during long comfort noise periods with clock drift.
4058 timestamp_diff_ms = 0;
4059 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004060
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004061 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4062 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004063
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004064 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004065
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004066 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004067
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004068 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4069 _recPacketDelayMs = packet_delay_ms;
4070 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004071
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004072 if (_average_jitter_buffer_delay_us == 0) {
4073 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4074 return;
4075 }
4076
4077 // Filter average delay value using exponential filter (alpha is
4078 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4079 // risk of rounding error) and compensate for it in GetDelayEstimate()
4080 // later.
4081 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4082 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004083}
4084
4085void
4086Channel::RegisterReceiveCodecsToRTPModule()
4087{
4088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4089 "Channel::RegisterReceiveCodecsToRTPModule()");
4090
4091
4092 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004093 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004094
4095 for (int idx = 0; idx < nSupportedCodecs; idx++)
4096 {
4097 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004098 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004099 (rtp_receiver_->RegisterReceivePayload(
4100 codec.plname,
4101 codec.pltype,
4102 codec.plfreq,
4103 codec.channels,
4104 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004105 {
4106 WEBRTC_TRACE(
4107 kTraceWarning,
4108 kTraceVoice,
4109 VoEId(_instanceId, _channelId),
4110 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4111 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4112 codec.plname, codec.pltype, codec.plfreq,
4113 codec.channels, codec.rate);
4114 }
4115 else
4116 {
4117 WEBRTC_TRACE(
4118 kTraceInfo,
4119 kTraceVoice,
4120 VoEId(_instanceId, _channelId),
4121 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004122 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004123 "receiver",
4124 codec.plname, codec.pltype, codec.plfreq,
4125 codec.channels, codec.rate);
4126 }
4127 }
4128}
4129
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004130// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004131int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004132 CodecInst codec;
4133 bool found_red = false;
4134
4135 // Get default RED settings from the ACM database
4136 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4137 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004138 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004139 if (!STR_CASE_CMP(codec.plname, "RED")) {
4140 found_red = true;
4141 break;
4142 }
4143 }
4144
4145 if (!found_red) {
4146 _engineStatisticsPtr->SetLastError(
4147 VE_CODEC_ERROR, kTraceError,
4148 "SetRedPayloadType() RED is not supported");
4149 return -1;
4150 }
4151
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004152 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004153 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004154 _engineStatisticsPtr->SetLastError(
4155 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4156 "SetRedPayloadType() RED registration in ACM module failed");
4157 return -1;
4158 }
4159
4160 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4161 _engineStatisticsPtr->SetLastError(
4162 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4163 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4164 return -1;
4165 }
4166 return 0;
4167}
4168
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004169int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4170 unsigned char id) {
4171 int error = 0;
4172 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4173 if (enable) {
4174 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4175 }
4176 return error;
4177}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004178
wu@webrtc.org94454b72014-06-05 20:34:08 +00004179int32_t Channel::GetPlayoutFrequency() {
4180 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4181 CodecInst current_recive_codec;
4182 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4183 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4184 // Even though the actual sampling rate for G.722 audio is
4185 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4186 // 8,000 Hz because that value was erroneously assigned in
4187 // RFC 1890 and must remain unchanged for backward compatibility.
4188 playout_frequency = 8000;
4189 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4190 // We are resampling Opus internally to 32,000 Hz until all our
4191 // DSP routines can operate at 48,000 Hz, but the RTP clock
4192 // rate for the Opus payload format is standardized to 48,000 Hz,
4193 // because that is the maximum supported decoding sampling rate.
4194 playout_frequency = 48000;
4195 }
4196 }
4197 return playout_frequency;
4198}
4199
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004200int64_t Channel::GetRTT() const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004201 RTCPMethod method = _rtpRtcpModule->RTCP();
4202 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004203 return 0;
4204 }
4205 std::vector<RTCPReportBlock> report_blocks;
4206 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4207 if (report_blocks.empty()) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004208 return 0;
4209 }
4210
4211 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4212 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4213 for (; it != report_blocks.end(); ++it) {
4214 if (it->remoteSSRC == remoteSSRC)
4215 break;
4216 }
4217 if (it == report_blocks.end()) {
4218 // We have not received packets with SSRC matching the report blocks.
4219 // To calculate RTT we try with the SSRC of the first report block.
4220 // This is very important for send-only channels where we don't know
4221 // the SSRC of the other end.
4222 remoteSSRC = report_blocks[0].remoteSSRC;
4223 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004224 int64_t rtt = 0;
4225 int64_t avg_rtt = 0;
4226 int64_t max_rtt= 0;
4227 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004228 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4229 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004230 return 0;
4231 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004232 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004233}
4234
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004235} // namespace voe
4236} // namespace webrtc