blob: a9af60584f30245ebfb00b6675e98176ba5cd179 [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
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000013#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000014#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000015#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000016#include "webrtc/modules/audio_device/include/audio_device.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000018#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000019#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
21#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
22#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000023#include "webrtc/modules/utility/interface/audio_frame_operations.h"
24#include "webrtc/modules/utility/interface/process_thread.h"
25#include "webrtc/modules/utility/interface/rtp_dump.h"
26#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/logging.h"
28#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000029#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000030#include "webrtc/voice_engine/include/voe_base.h"
31#include "webrtc/voice_engine/include/voe_external_media.h"
32#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
33#include "webrtc/voice_engine/output_mixer.h"
34#include "webrtc/voice_engine/statistics.h"
35#include "webrtc/voice_engine/transmit_mixer.h"
36#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000037
38#if defined(_WIN32)
39#include <Qos.h>
40#endif
41
andrew@webrtc.org50419b02012-11-14 19:07:54 +000042namespace webrtc {
43namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000044
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000045// Extend the default RTCP statistics struct with max_jitter, defined as the
46// maximum jitter value seen in an RTCP report block.
47struct ChannelStatistics : public RtcpStatistics {
48 ChannelStatistics() : rtcp(), max_jitter(0) {}
49
50 RtcpStatistics rtcp;
51 uint32_t max_jitter;
52};
53
54// Statistics callback, called at each generation of a new RTCP report block.
55class StatisticsProxy : public RtcpStatisticsCallback {
56 public:
57 StatisticsProxy(uint32_t ssrc)
58 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
59 ssrc_(ssrc) {}
60 virtual ~StatisticsProxy() {}
61
62 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
63 uint32_t ssrc) OVERRIDE {
64 if (ssrc != ssrc_)
65 return;
66
67 CriticalSectionScoped cs(stats_lock_.get());
68 stats_.rtcp = statistics;
69 if (statistics.jitter > stats_.max_jitter) {
70 stats_.max_jitter = statistics.jitter;
71 }
72 }
73
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +000074 virtual void CNameChanged(const char* cname, uint32_t ssrc) OVERRIDE {}
75
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000076 void ResetStatistics() {
77 CriticalSectionScoped cs(stats_lock_.get());
78 stats_ = ChannelStatistics();
79 }
80
81 ChannelStatistics GetStats() {
82 CriticalSectionScoped cs(stats_lock_.get());
83 return stats_;
84 }
85
86 private:
87 // StatisticsUpdated calls are triggered from threads in the RTP module,
88 // while GetStats calls can be triggered from the public voice engine API,
89 // hence synchronization is needed.
90 scoped_ptr<CriticalSectionWrapper> stats_lock_;
91 const uint32_t ssrc_;
92 ChannelStatistics stats_;
93};
94
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000095class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000096 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000097 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
98 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000099
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000100 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
101 // Not used for Voice Engine.
102 }
103
104 virtual void OnReceivedRtcpReceiverReport(
105 const ReportBlockList& report_blocks,
106 int64_t rtt,
107 int64_t now_ms) override {
108 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
109 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
110 // report for VoiceEngine?
111 if (report_blocks.empty())
112 return;
113
114 int fraction_lost_aggregate = 0;
115 int total_number_of_packets = 0;
116
117 // If receiving multiple report blocks, calculate the weighted average based
118 // on the number of packets a report refers to.
119 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
120 block_it != report_blocks.end(); ++block_it) {
121 // Find the previous extended high sequence number for this remote SSRC,
122 // to calculate the number of RTP packets this report refers to. Ignore if
123 // we haven't seen this SSRC before.
124 std::map<uint32_t, uint32_t>::iterator seq_num_it =
125 extended_max_sequence_number_.find(block_it->sourceSSRC);
126 int number_of_packets = 0;
127 if (seq_num_it != extended_max_sequence_number_.end()) {
128 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
129 }
130 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
131 total_number_of_packets += number_of_packets;
132
133 extended_max_sequence_number_[block_it->sourceSSRC] =
134 block_it->extendedHighSeqNum;
135 }
136 int weighted_fraction_lost = 0;
137 if (total_number_of_packets > 0) {
138 weighted_fraction_lost = (fraction_lost_aggregate +
139 total_number_of_packets / 2) / total_number_of_packets;
140 }
141 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000142 }
143
144 private:
145 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000146 // Maps remote side ssrc to extended highest sequence number received.
147 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000148};
149
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000151Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000152 uint8_t payloadType,
153 uint32_t timeStamp,
154 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 const RTPFragmentationHeader* fragmentation)
157{
158 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
159 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000160 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
161 frameType, payloadType, timeStamp,
162 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000163
164 if (_includeAudioLevelIndication)
165 {
166 // Store current audio level in the RTP/RTCP module.
167 // The level will be used in combination with voice-activity state
168 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000169 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000170 }
171
172 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
173 // packetization.
174 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000175 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 payloadType,
177 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000178 // Leaving the time when this frame was
179 // received from the capture device as
180 // undefined for voice for now.
181 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000182 payloadData,
183 payloadSize,
184 fragmentation) == -1)
185 {
186 _engineStatisticsPtr->SetLastError(
187 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
188 "Channel::SendData() failed to send data to RTP/RTCP module");
189 return -1;
190 }
191
192 _lastLocalTimeStamp = timeStamp;
193 _lastPayloadType = payloadType;
194
195 return 0;
196}
197
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000198int32_t
199Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000200{
201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
202 "Channel::InFrameType(frameType=%d)", frameType);
203
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000204 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 // 1 indicates speech
206 _sendFrameType = (frameType == 1) ? 1 : 0;
207 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()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000762 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000763 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000764 _rtpDumpIn(*RtpDump::CreateRtpDump()),
765 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000766 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000768 _inputFilePlayerPtr(NULL),
769 _outputFilePlayerPtr(NULL),
770 _outputFileRecorderPtr(NULL),
771 // Avoid conflict with other channels by adding 1024 - 1026,
772 // won't use as much as 1024 channels.
773 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
774 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
775 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
778 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000779 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000780 _inputExternalMediaCallbackPtr(NULL),
781 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000782 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
783 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000784 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000785 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000786 playout_timestamp_rtp_(0),
787 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000788 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000789 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000790 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000791 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000792 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
793 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000794 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000795 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000796 _outputMixerPtr(NULL),
797 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000798 _moduleProcessThreadPtr(NULL),
799 _audioDeviceModulePtr(NULL),
800 _voiceEngineObserverPtr(NULL),
801 _callbackCritSectPtr(NULL),
802 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000803 _rxVadObserverPtr(NULL),
804 _oldVadDecision(-1),
805 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000806 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000807 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000808 _mute(false),
809 _panLeft(1.0f),
810 _panRight(1.0f),
811 _outputGain(1.0f),
812 _playOutbandDtmfEvent(false),
813 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000814 _lastLocalTimeStamp(0),
815 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000816 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000818 vie_network_(NULL),
819 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000820 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000821 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 _previousTimestamp(0),
823 _recPacketDelayMs(20),
824 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000826 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000827 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000828 rtcp_observer_(new VoERtcpObserver(this)),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000829 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000830{
831 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
832 "Channel::Channel() - ctor");
833 _inbandDtmfQueue.ResetDtmf();
834 _inbandDtmfGenerator.Init();
835 _outputAudioLevel.Clear();
836
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000837 RtpRtcp::Configuration configuration;
838 configuration.id = VoEModuleId(instanceId, channelId);
839 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000840 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000841 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000842 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000843 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000844
845 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000846
847 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
848 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
849 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000850
851 Config audioproc_config;
852 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
853 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000854}
855
856Channel::~Channel()
857{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000858 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
860 "Channel::~Channel() - dtor");
861
862 if (_outputExternalMedia)
863 {
864 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
865 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000866 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 {
868 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
869 }
870 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000871 StopPlayout();
872
873 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000874 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 if (_inputFilePlayerPtr)
876 {
877 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
878 _inputFilePlayerPtr->StopPlayingFile();
879 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
880 _inputFilePlayerPtr = NULL;
881 }
882 if (_outputFilePlayerPtr)
883 {
884 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
885 _outputFilePlayerPtr->StopPlayingFile();
886 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
887 _outputFilePlayerPtr = NULL;
888 }
889 if (_outputFileRecorderPtr)
890 {
891 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
892 _outputFileRecorderPtr->StopRecording();
893 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
894 _outputFileRecorderPtr = NULL;
895 }
896 }
897
898 // The order to safely shutdown modules in a channel is:
899 // 1. De-register callbacks in modules
900 // 2. De-register modules in process thread
901 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000902 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 {
904 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
905 VoEId(_instanceId,_channelId),
906 "~Channel() failed to de-register transport callback"
907 " (Audio coding module)");
908 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000909 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 {
911 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
912 VoEId(_instanceId,_channelId),
913 "~Channel() failed to de-register VAD callback"
914 " (Audio coding module)");
915 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000917 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 {
919 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
920 VoEId(_instanceId,_channelId),
921 "~Channel() failed to deregister RTP/RTCP module");
922 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 // End of modules shutdown
924
925 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000926 if (vie_network_) {
927 vie_network_->Release();
928 vie_network_ = NULL;
929 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000930 RtpDump::DestroyRtpDump(&_rtpDumpIn);
931 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000934 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000935}
936
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000937int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000938Channel::Init()
939{
940 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
941 "Channel::Init()");
942
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000943 channel_state_.Reset();
944
niklase@google.com470e71d2011-07-07 08:21:25 +0000945 // --- Initial sanity
946
947 if ((_engineStatisticsPtr == NULL) ||
948 (_moduleProcessThreadPtr == NULL))
949 {
950 WEBRTC_TRACE(kTraceError, kTraceVoice,
951 VoEId(_instanceId,_channelId),
952 "Channel::Init() must call SetEngineInformation() first");
953 return -1;
954 }
955
956 // --- Add modules to process thread (for periodic schedulation)
957
958 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000959 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000961 if (processThreadFail)
962 {
963 _engineStatisticsPtr->SetLastError(
964 VE_CANNOT_INIT_CHANNEL, kTraceError,
965 "Channel::Init() modules not registered");
966 return -1;
967 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000968 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000969
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000970 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000971#ifdef WEBRTC_CODEC_AVT
972 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000973 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000974#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000975 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 {
977 _engineStatisticsPtr->SetLastError(
978 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
979 "Channel::Init() unable to initialize the ACM - 1");
980 return -1;
981 }
982
983 // --- RTP/RTCP module initialization
984
985 // Ensure that RTCP is enabled by default for the created channel.
986 // Note that, the module will keep generating RTCP until it is explicitly
987 // disabled by the user.
988 // After StopListen (when no sockets exists), RTCP packets will no longer
989 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000990 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
991 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000992 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
993 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000995 (audio_coding_->RegisterTransportCallback(this) == -1) ||
996 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000997
998 if (fail)
999 {
1000 _engineStatisticsPtr->SetLastError(
1001 VE_CANNOT_INIT_CHANNEL, kTraceError,
1002 "Channel::Init() callbacks not registered");
1003 return -1;
1004 }
1005
1006 // --- Register all supported codecs to the receiving side of the
1007 // RTP/RTCP module
1008
1009 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001010 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001011
1012 for (int idx = 0; idx < nSupportedCodecs; idx++)
1013 {
1014 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001015 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001016 (rtp_receiver_->RegisterReceivePayload(
1017 codec.plname,
1018 codec.pltype,
1019 codec.plfreq,
1020 codec.channels,
1021 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
1023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1026 "to RTP/RTCP receiver",
1027 codec.plname, codec.pltype, codec.plfreq,
1028 codec.channels, codec.rate);
1029 }
1030 else
1031 {
1032 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1033 VoEId(_instanceId,_channelId),
1034 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1035 "the RTP/RTCP receiver",
1036 codec.plname, codec.pltype, codec.plfreq,
1037 codec.channels, codec.rate);
1038 }
1039
1040 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001041 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 {
1043 SetSendCodec(codec);
1044 }
1045
1046 // Register default PT for outband 'telephone-event'
1047 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1048 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001049 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001050 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 {
1052 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1053 VoEId(_instanceId,_channelId),
1054 "Channel::Init() failed to register outband "
1055 "'telephone-event' (%d/%d) correctly",
1056 codec.pltype, codec.plfreq);
1057 }
1058 }
1059
1060 if (!STR_CASE_CMP(codec.plname, "CN"))
1061 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001062 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1063 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001064 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 {
1066 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1067 VoEId(_instanceId,_channelId),
1068 "Channel::Init() failed to register CN (%d/%d) "
1069 "correctly - 1",
1070 codec.pltype, codec.plfreq);
1071 }
1072 }
1073#ifdef WEBRTC_CODEC_RED
1074 // Register RED to the receiving side of the ACM.
1075 // We will not receive an OnInitializeDecoder() callback for RED.
1076 if (!STR_CASE_CMP(codec.plname, "RED"))
1077 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001078 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 {
1080 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1081 VoEId(_instanceId,_channelId),
1082 "Channel::Init() failed to register RED (%d/%d) "
1083 "correctly",
1084 codec.pltype, codec.plfreq);
1085 }
1086 }
1087#endif
1088 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001089
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001090 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1091 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1092 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001094 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1095 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1096 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 }
1098
1099 return 0;
1100}
1101
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001102int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001103Channel::SetEngineInformation(Statistics& engineStatistics,
1104 OutputMixer& outputMixer,
1105 voe::TransmitMixer& transmitMixer,
1106 ProcessThread& moduleProcessThread,
1107 AudioDeviceModule& audioDeviceModule,
1108 VoiceEngineObserver* voiceEngineObserver,
1109 CriticalSectionWrapper* callbackCritSect)
1110{
1111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1112 "Channel::SetEngineInformation()");
1113 _engineStatisticsPtr = &engineStatistics;
1114 _outputMixerPtr = &outputMixer;
1115 _transmitMixerPtr = &transmitMixer,
1116 _moduleProcessThreadPtr = &moduleProcessThread;
1117 _audioDeviceModulePtr = &audioDeviceModule;
1118 _voiceEngineObserverPtr = voiceEngineObserver;
1119 _callbackCritSectPtr = callbackCritSect;
1120 return 0;
1121}
1122
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001123int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001124Channel::UpdateLocalTimeStamp()
1125{
1126
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001127 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 return 0;
1129}
1130
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001131int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001132Channel::StartPlayout()
1133{
1134 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1135 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001136 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 {
1138 return 0;
1139 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001140
1141 if (!_externalMixing) {
1142 // Add participant as candidates for mixing.
1143 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1144 {
1145 _engineStatisticsPtr->SetLastError(
1146 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1147 "StartPlayout() failed to add participant to mixer");
1148 return -1;
1149 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 }
1151
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001152 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001153 if (RegisterFilePlayingToMixer() != 0)
1154 return -1;
1155
niklase@google.com470e71d2011-07-07 08:21:25 +00001156 return 0;
1157}
1158
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001159int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001160Channel::StopPlayout()
1161{
1162 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1163 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001164 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001165 {
1166 return 0;
1167 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001168
1169 if (!_externalMixing) {
1170 // Remove participant as candidates for mixing
1171 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1172 {
1173 _engineStatisticsPtr->SetLastError(
1174 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1175 "StopPlayout() failed to remove participant from mixer");
1176 return -1;
1177 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 }
1179
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001180 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 _outputAudioLevel.Clear();
1182
1183 return 0;
1184}
1185
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001186int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001187Channel::StartSend()
1188{
1189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1190 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001191 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001192 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001193 if (send_sequence_number_)
1194 SetInitSequenceNumber(send_sequence_number_);
1195
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001196 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001197 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001198 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001200 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001201
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001202 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 {
1204 _engineStatisticsPtr->SetLastError(
1205 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1206 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001207 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001208 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 return -1;
1210 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001211
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 return 0;
1213}
1214
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001215int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001216Channel::StopSend()
1217{
1218 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1219 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001220 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001221 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001222 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001223 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001224 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001225
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001226 // Store the sequence number to be able to pick up the same sequence for
1227 // the next StartSend(). This is needed for restarting device, otherwise
1228 // it might cause libSRTP to complain about packets being replayed.
1229 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1230 // CL is landed. See issue
1231 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1232 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1233
niklase@google.com470e71d2011-07-07 08:21:25 +00001234 // Reset sending SSRC and sequence number and triggers direct transmission
1235 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001236 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1237 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001238 {
1239 _engineStatisticsPtr->SetLastError(
1240 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1241 "StartSend() RTP/RTCP failed to stop sending");
1242 }
1243
niklase@google.com470e71d2011-07-07 08:21:25 +00001244 return 0;
1245}
1246
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001247int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001248Channel::StartReceiving()
1249{
1250 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1251 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001252 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 {
1254 return 0;
1255 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001256 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001257 _numberOfDiscardedPackets = 0;
1258 return 0;
1259}
1260
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001261int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001262Channel::StopReceiving()
1263{
1264 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1265 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001266 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001267 {
1268 return 0;
1269 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001270
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001271 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 return 0;
1273}
1274
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001275int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001276Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1277{
1278 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1279 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001280 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001281
1282 if (_voiceEngineObserverPtr)
1283 {
1284 _engineStatisticsPtr->SetLastError(
1285 VE_INVALID_OPERATION, kTraceError,
1286 "RegisterVoiceEngineObserver() observer already enabled");
1287 return -1;
1288 }
1289 _voiceEngineObserverPtr = &observer;
1290 return 0;
1291}
1292
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001293int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001294Channel::DeRegisterVoiceEngineObserver()
1295{
1296 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1297 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001298 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001299
1300 if (!_voiceEngineObserverPtr)
1301 {
1302 _engineStatisticsPtr->SetLastError(
1303 VE_INVALID_OPERATION, kTraceWarning,
1304 "DeRegisterVoiceEngineObserver() observer already disabled");
1305 return 0;
1306 }
1307 _voiceEngineObserverPtr = NULL;
1308 return 0;
1309}
1310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001312Channel::GetSendCodec(CodecInst& codec)
1313{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001314 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001315}
1316
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001317int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001318Channel::GetRecCodec(CodecInst& codec)
1319{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001320 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001321}
1322
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001323int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001324Channel::SetSendCodec(const CodecInst& codec)
1325{
1326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1327 "Channel::SetSendCodec()");
1328
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001329 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 {
1331 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1332 "SetSendCodec() failed to register codec to ACM");
1333 return -1;
1334 }
1335
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001336 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001338 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1339 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 {
1341 WEBRTC_TRACE(
1342 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1343 "SetSendCodec() failed to register codec to"
1344 " RTP/RTCP module");
1345 return -1;
1346 }
1347 }
1348
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001349 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 {
1351 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1352 "SetSendCodec() failed to set audio packet size");
1353 return -1;
1354 }
1355
1356 return 0;
1357}
1358
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001359void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001360 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001361 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1362
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001363 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001364 if (audio_coding_->SetPacketLossRate(
1365 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001366 assert(false); // This should not happen.
1367 }
1368}
1369
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001370int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001371Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1372{
1373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1374 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001375 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 // To disable VAD, DTX must be disabled too
1377 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001378 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001379 {
1380 _engineStatisticsPtr->SetLastError(
1381 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1382 "SetVADStatus() failed to set VAD");
1383 return -1;
1384 }
1385 return 0;
1386}
1387
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001388int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001389Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1390{
1391 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1392 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001393 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001394 {
1395 _engineStatisticsPtr->SetLastError(
1396 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1397 "GetVADStatus() failed to get VAD status");
1398 return -1;
1399 }
1400 disabledDTX = !disabledDTX;
1401 return 0;
1402}
1403
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001404int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001405Channel::SetRecPayloadType(const CodecInst& codec)
1406{
1407 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1408 "Channel::SetRecPayloadType()");
1409
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001410 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 {
1412 _engineStatisticsPtr->SetLastError(
1413 VE_ALREADY_PLAYING, kTraceError,
1414 "SetRecPayloadType() unable to set PT while playing");
1415 return -1;
1416 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001417 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001418 {
1419 _engineStatisticsPtr->SetLastError(
1420 VE_ALREADY_LISTENING, kTraceError,
1421 "SetRecPayloadType() unable to set PT while listening");
1422 return -1;
1423 }
1424
1425 if (codec.pltype == -1)
1426 {
1427 // De-register the selected codec (RTP/RTCP module and ACM)
1428
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001429 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 CodecInst rxCodec = codec;
1431
1432 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001433 rtp_payload_registry_->ReceivePayloadType(
1434 rxCodec.plname,
1435 rxCodec.plfreq,
1436 rxCodec.channels,
1437 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1438 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 rxCodec.pltype = pltype;
1440
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001441 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 {
1443 _engineStatisticsPtr->SetLastError(
1444 VE_RTP_RTCP_MODULE_ERROR,
1445 kTraceError,
1446 "SetRecPayloadType() RTP/RTCP-module deregistration "
1447 "failed");
1448 return -1;
1449 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001450 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001451 {
1452 _engineStatisticsPtr->SetLastError(
1453 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1454 "SetRecPayloadType() ACM deregistration failed - 1");
1455 return -1;
1456 }
1457 return 0;
1458 }
1459
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001460 if (rtp_receiver_->RegisterReceivePayload(
1461 codec.plname,
1462 codec.pltype,
1463 codec.plfreq,
1464 codec.channels,
1465 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001466 {
1467 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001468 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1469 if (rtp_receiver_->RegisterReceivePayload(
1470 codec.plname,
1471 codec.pltype,
1472 codec.plfreq,
1473 codec.channels,
1474 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 {
1476 _engineStatisticsPtr->SetLastError(
1477 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1478 "SetRecPayloadType() RTP/RTCP-module registration failed");
1479 return -1;
1480 }
1481 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001482 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001483 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001484 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1485 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001486 {
1487 _engineStatisticsPtr->SetLastError(
1488 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1489 "SetRecPayloadType() ACM registration failed - 1");
1490 return -1;
1491 }
1492 }
1493 return 0;
1494}
1495
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001496int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001497Channel::GetRecPayloadType(CodecInst& codec)
1498{
1499 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1500 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001501 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001502 if (rtp_payload_registry_->ReceivePayloadType(
1503 codec.plname,
1504 codec.plfreq,
1505 codec.channels,
1506 (codec.rate < 0) ? 0 : codec.rate,
1507 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001508 {
1509 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001510 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 "GetRecPayloadType() failed to retrieve RX payload type");
1512 return -1;
1513 }
1514 codec.pltype = payloadType;
1515 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001516 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001517 return 0;
1518}
1519
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001520int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001521Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1522{
1523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1524 "Channel::SetSendCNPayloadType()");
1525
1526 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001527 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001528 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001529 if (frequency == kFreq32000Hz)
1530 samplingFreqHz = 32000;
1531 else if (frequency == kFreq16000Hz)
1532 samplingFreqHz = 16000;
1533
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001534 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
1536 _engineStatisticsPtr->SetLastError(
1537 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1538 "SetSendCNPayloadType() failed to retrieve default CN codec "
1539 "settings");
1540 return -1;
1541 }
1542
1543 // Modify the payload type (must be set to dynamic range)
1544 codec.pltype = type;
1545
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001546 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001547 {
1548 _engineStatisticsPtr->SetLastError(
1549 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1550 "SetSendCNPayloadType() failed to register CN to ACM");
1551 return -1;
1552 }
1553
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001554 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001555 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001556 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1557 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001558 {
1559 _engineStatisticsPtr->SetLastError(
1560 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1561 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1562 "module");
1563 return -1;
1564 }
1565 }
1566 return 0;
1567}
1568
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001569int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001571 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001572
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001573 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001574 _engineStatisticsPtr->SetLastError(
1575 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001576 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001577 return -1;
1578 }
1579 return 0;
1580}
1581
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001582int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001583{
1584 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1585 "Channel::RegisterExternalTransport()");
1586
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001587 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001588
niklase@google.com470e71d2011-07-07 08:21:25 +00001589 if (_externalTransport)
1590 {
1591 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1592 kTraceError,
1593 "RegisterExternalTransport() external transport already enabled");
1594 return -1;
1595 }
1596 _externalTransport = true;
1597 _transportPtr = &transport;
1598 return 0;
1599}
1600
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001601int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001602Channel::DeRegisterExternalTransport()
1603{
1604 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1605 "Channel::DeRegisterExternalTransport()");
1606
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001607 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001608
niklase@google.com470e71d2011-07-07 08:21:25 +00001609 if (!_transportPtr)
1610 {
1611 _engineStatisticsPtr->SetLastError(
1612 VE_INVALID_OPERATION, kTraceWarning,
1613 "DeRegisterExternalTransport() external transport already "
1614 "disabled");
1615 return 0;
1616 }
1617 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001618 _transportPtr = NULL;
1619 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1620 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 return 0;
1622}
1623
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001624int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001625 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001626 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1627 "Channel::ReceivedRTPPacket()");
1628
1629 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001630 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001631
1632 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001633 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1634 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001635 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1636 VoEId(_instanceId,_channelId),
1637 "Channel::SendPacket() RTP dump to input file failed");
1638 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001639 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001640 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001641 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1642 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1643 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001644 return -1;
1645 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001646 header.payload_type_frequency =
1647 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001648 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001649 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001650 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001651 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001652 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001653 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001654
1655 // Forward any packets to ViE bandwidth estimator, if enabled.
1656 {
1657 CriticalSectionScoped cs(&_callbackCritSect);
1658 if (vie_network_) {
1659 int64_t arrival_time_ms;
1660 if (packet_time.timestamp != -1) {
1661 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1662 } else {
1663 arrival_time_ms = TickTime::MillisecondTimestamp();
1664 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001665 size_t payload_length = length - header.headerLength;
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001666 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1667 payload_length, header);
1668 }
1669 }
1670
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001671 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001672}
1673
1674bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001675 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001676 const RTPHeader& header,
1677 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001678 if (rtp_payload_registry_->IsRtx(header)) {
1679 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001680 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001681 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001682 assert(packet_length >= header.headerLength);
1683 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001684 PayloadUnion payload_specific;
1685 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001686 &payload_specific)) {
1687 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001688 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001689 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1690 payload_specific, in_order);
1691}
1692
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001693bool Channel::HandleRtxPacket(const uint8_t* packet,
1694 size_t packet_length,
1695 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001696 if (!rtp_payload_registry_->IsRtx(header))
1697 return false;
1698
1699 // Remove the RTX header and parse the original RTP header.
1700 if (packet_length < header.headerLength)
1701 return false;
1702 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1703 return false;
1704 if (restored_packet_in_use_) {
1705 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1706 "Multiple RTX headers detected, dropping packet");
1707 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001708 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001709 uint8_t* restored_packet_ptr = restored_packet_;
1710 if (!rtp_payload_registry_->RestoreOriginalPacket(
1711 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1712 header)) {
1713 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1714 "Incoming RTX packet: invalid RTP header");
1715 return false;
1716 }
1717 restored_packet_in_use_ = true;
1718 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1719 restored_packet_in_use_ = false;
1720 return ret;
1721}
1722
1723bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1724 StreamStatistician* statistician =
1725 rtp_receive_statistics_->GetStatistician(header.ssrc);
1726 if (!statistician)
1727 return false;
1728 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001729}
1730
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001731bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1732 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001733 // Retransmissions are handled separately if RTX is enabled.
1734 if (rtp_payload_registry_->RtxEnabled())
1735 return false;
1736 StreamStatistician* statistician =
1737 rtp_receive_statistics_->GetStatistician(header.ssrc);
1738 if (!statistician)
1739 return false;
1740 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001741 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001742 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001743 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001744 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001745}
1746
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001747int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001748 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1749 "Channel::ReceivedRTCPPacket()");
1750 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001751 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001752
1753 // Dump the RTCP packet to a file (if RTP dump is enabled).
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001754 if (_rtpDumpIn.DumpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001755 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1756 VoEId(_instanceId,_channelId),
1757 "Channel::SendPacket() RTCP dump to input file failed");
1758 }
1759
1760 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001761 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001762 _engineStatisticsPtr->SetLastError(
1763 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1764 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1765 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001766
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001767 {
1768 CriticalSectionScoped lock(ts_stats_lock_.get());
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001769 int64_t rtt = GetRTT();
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001770 if (rtt == 0) {
1771 // Waiting for valid RTT.
1772 return 0;
1773 }
1774 uint32_t ntp_secs = 0;
1775 uint32_t ntp_frac = 0;
1776 uint32_t rtp_timestamp = 0;
1777 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1778 &rtp_timestamp)) {
1779 // Waiting for RTCP.
1780 return 0;
1781 }
1782 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001783 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001784 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001785}
1786
niklase@google.com470e71d2011-07-07 08:21:25 +00001787int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001788 bool loop,
1789 FileFormats format,
1790 int startPosition,
1791 float volumeScaling,
1792 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001793 const CodecInst* codecInst)
1794{
1795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1796 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1797 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1798 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1799 startPosition, stopPosition);
1800
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001801 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001802 {
1803 _engineStatisticsPtr->SetLastError(
1804 VE_ALREADY_PLAYING, kTraceError,
1805 "StartPlayingFileLocally() is already playing");
1806 return -1;
1807 }
1808
niklase@google.com470e71d2011-07-07 08:21:25 +00001809 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001810 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001811
1812 if (_outputFilePlayerPtr)
1813 {
1814 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1815 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1816 _outputFilePlayerPtr = NULL;
1817 }
1818
1819 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1820 _outputFilePlayerId, (const FileFormats)format);
1821
1822 if (_outputFilePlayerPtr == NULL)
1823 {
1824 _engineStatisticsPtr->SetLastError(
1825 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001826 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001827 return -1;
1828 }
1829
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001830 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001831
1832 if (_outputFilePlayerPtr->StartPlayingFile(
1833 fileName,
1834 loop,
1835 startPosition,
1836 volumeScaling,
1837 notificationTime,
1838 stopPosition,
1839 (const CodecInst*)codecInst) != 0)
1840 {
1841 _engineStatisticsPtr->SetLastError(
1842 VE_BAD_FILE, kTraceError,
1843 "StartPlayingFile() failed to start file playout");
1844 _outputFilePlayerPtr->StopPlayingFile();
1845 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1846 _outputFilePlayerPtr = NULL;
1847 return -1;
1848 }
1849 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001850 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001851 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001852
1853 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001854 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001855
1856 return 0;
1857}
1858
1859int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001860 FileFormats format,
1861 int startPosition,
1862 float volumeScaling,
1863 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001864 const CodecInst* codecInst)
1865{
1866 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1867 "Channel::StartPlayingFileLocally(format=%d,"
1868 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1869 format, volumeScaling, startPosition, stopPosition);
1870
1871 if(stream == NULL)
1872 {
1873 _engineStatisticsPtr->SetLastError(
1874 VE_BAD_FILE, kTraceError,
1875 "StartPlayingFileLocally() NULL as input stream");
1876 return -1;
1877 }
1878
1879
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001880 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001881 {
1882 _engineStatisticsPtr->SetLastError(
1883 VE_ALREADY_PLAYING, kTraceError,
1884 "StartPlayingFileLocally() is already playing");
1885 return -1;
1886 }
1887
niklase@google.com470e71d2011-07-07 08:21:25 +00001888 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001889 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001890
1891 // Destroy the old instance
1892 if (_outputFilePlayerPtr)
1893 {
1894 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1895 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1896 _outputFilePlayerPtr = NULL;
1897 }
1898
1899 // Create the instance
1900 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1901 _outputFilePlayerId,
1902 (const FileFormats)format);
1903
1904 if (_outputFilePlayerPtr == NULL)
1905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_INVALID_ARGUMENT, kTraceError,
1908 "StartPlayingFileLocally() filePlayer format isnot correct");
1909 return -1;
1910 }
1911
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001912 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001913
1914 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1915 volumeScaling,
1916 notificationTime,
1917 stopPosition, codecInst) != 0)
1918 {
1919 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1920 "StartPlayingFile() failed to "
1921 "start file playout");
1922 _outputFilePlayerPtr->StopPlayingFile();
1923 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1924 _outputFilePlayerPtr = NULL;
1925 return -1;
1926 }
1927 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001928 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001929 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001930
1931 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001932 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001933
niklase@google.com470e71d2011-07-07 08:21:25 +00001934 return 0;
1935}
1936
1937int Channel::StopPlayingFileLocally()
1938{
1939 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1940 "Channel::StopPlayingFileLocally()");
1941
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001942 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001943 {
1944 _engineStatisticsPtr->SetLastError(
1945 VE_INVALID_OPERATION, kTraceWarning,
1946 "StopPlayingFileLocally() isnot playing");
1947 return 0;
1948 }
1949
niklase@google.com470e71d2011-07-07 08:21:25 +00001950 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001951 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001952
1953 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1954 {
1955 _engineStatisticsPtr->SetLastError(
1956 VE_STOP_RECORDING_FAILED, kTraceError,
1957 "StopPlayingFile() could not stop playing");
1958 return -1;
1959 }
1960 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1961 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1962 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001963 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001964 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001965 // _fileCritSect cannot be taken while calling
1966 // SetAnonymousMixibilityStatus. Refer to comments in
1967 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001968 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1969 {
1970 _engineStatisticsPtr->SetLastError(
1971 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001972 "StopPlayingFile() failed to stop participant from playing as"
1973 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001974 return -1;
1975 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001976
1977 return 0;
1978}
1979
1980int Channel::IsPlayingFileLocally() const
1981{
1982 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1983 "Channel::IsPlayingFileLocally()");
1984
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001985 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001986}
1987
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001988int Channel::RegisterFilePlayingToMixer()
1989{
1990 // Return success for not registering for file playing to mixer if:
1991 // 1. playing file before playout is started on that channel.
1992 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001993 if (!channel_state_.Get().playing ||
1994 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001995 {
1996 return 0;
1997 }
1998
1999 // |_fileCritSect| cannot be taken while calling
2000 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2001 // frames can be pulled by the mixer. Since the frames are generated from
2002 // the file, _fileCritSect will be taken. This would result in a deadlock.
2003 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2004 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002005 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002006 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002007 _engineStatisticsPtr->SetLastError(
2008 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2009 "StartPlayingFile() failed to add participant as file to mixer");
2010 _outputFilePlayerPtr->StopPlayingFile();
2011 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2012 _outputFilePlayerPtr = NULL;
2013 return -1;
2014 }
2015
2016 return 0;
2017}
2018
niklase@google.com470e71d2011-07-07 08:21:25 +00002019int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002020 bool loop,
2021 FileFormats format,
2022 int startPosition,
2023 float volumeScaling,
2024 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002025 const CodecInst* codecInst)
2026{
2027 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2028 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2029 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2030 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2031 startPosition, stopPosition);
2032
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002033 CriticalSectionScoped cs(&_fileCritSect);
2034
2035 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002036 {
2037 _engineStatisticsPtr->SetLastError(
2038 VE_ALREADY_PLAYING, kTraceWarning,
2039 "StartPlayingFileAsMicrophone() filePlayer is playing");
2040 return 0;
2041 }
2042
niklase@google.com470e71d2011-07-07 08:21:25 +00002043 // Destroy the old instance
2044 if (_inputFilePlayerPtr)
2045 {
2046 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2047 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2048 _inputFilePlayerPtr = NULL;
2049 }
2050
2051 // Create the instance
2052 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2053 _inputFilePlayerId, (const FileFormats)format);
2054
2055 if (_inputFilePlayerPtr == NULL)
2056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_INVALID_ARGUMENT, kTraceError,
2059 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2060 return -1;
2061 }
2062
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002063 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002064
2065 if (_inputFilePlayerPtr->StartPlayingFile(
2066 fileName,
2067 loop,
2068 startPosition,
2069 volumeScaling,
2070 notificationTime,
2071 stopPosition,
2072 (const CodecInst*)codecInst) != 0)
2073 {
2074 _engineStatisticsPtr->SetLastError(
2075 VE_BAD_FILE, kTraceError,
2076 "StartPlayingFile() failed to start file playout");
2077 _inputFilePlayerPtr->StopPlayingFile();
2078 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2079 _inputFilePlayerPtr = NULL;
2080 return -1;
2081 }
2082 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002083 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002084
2085 return 0;
2086}
2087
2088int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002089 FileFormats format,
2090 int startPosition,
2091 float volumeScaling,
2092 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002093 const CodecInst* codecInst)
2094{
2095 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2096 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2097 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2098 format, volumeScaling, startPosition, stopPosition);
2099
2100 if(stream == NULL)
2101 {
2102 _engineStatisticsPtr->SetLastError(
2103 VE_BAD_FILE, kTraceError,
2104 "StartPlayingFileAsMicrophone NULL as input stream");
2105 return -1;
2106 }
2107
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002108 CriticalSectionScoped cs(&_fileCritSect);
2109
2110 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002111 {
2112 _engineStatisticsPtr->SetLastError(
2113 VE_ALREADY_PLAYING, kTraceWarning,
2114 "StartPlayingFileAsMicrophone() is playing");
2115 return 0;
2116 }
2117
niklase@google.com470e71d2011-07-07 08:21:25 +00002118 // Destroy the old instance
2119 if (_inputFilePlayerPtr)
2120 {
2121 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2122 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2123 _inputFilePlayerPtr = NULL;
2124 }
2125
2126 // Create the instance
2127 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2128 _inputFilePlayerId, (const FileFormats)format);
2129
2130 if (_inputFilePlayerPtr == NULL)
2131 {
2132 _engineStatisticsPtr->SetLastError(
2133 VE_INVALID_ARGUMENT, kTraceError,
2134 "StartPlayingInputFile() filePlayer format isnot correct");
2135 return -1;
2136 }
2137
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002138 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002139
2140 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2141 volumeScaling, notificationTime,
2142 stopPosition, codecInst) != 0)
2143 {
2144 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2145 "StartPlayingFile() failed to start "
2146 "file playout");
2147 _inputFilePlayerPtr->StopPlayingFile();
2148 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2149 _inputFilePlayerPtr = NULL;
2150 return -1;
2151 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002152
niklase@google.com470e71d2011-07-07 08:21:25 +00002153 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002154 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002155
2156 return 0;
2157}
2158
2159int Channel::StopPlayingFileAsMicrophone()
2160{
2161 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2162 "Channel::StopPlayingFileAsMicrophone()");
2163
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002164 CriticalSectionScoped cs(&_fileCritSect);
2165
2166 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002167 {
2168 _engineStatisticsPtr->SetLastError(
2169 VE_INVALID_OPERATION, kTraceWarning,
2170 "StopPlayingFileAsMicrophone() isnot playing");
2171 return 0;
2172 }
2173
niklase@google.com470e71d2011-07-07 08:21:25 +00002174 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2175 {
2176 _engineStatisticsPtr->SetLastError(
2177 VE_STOP_RECORDING_FAILED, kTraceError,
2178 "StopPlayingFile() could not stop playing");
2179 return -1;
2180 }
2181 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2182 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2183 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002184 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002185
2186 return 0;
2187}
2188
2189int Channel::IsPlayingFileAsMicrophone() const
2190{
2191 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2192 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002193 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002194}
2195
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002196int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002197 const CodecInst* codecInst)
2198{
2199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2200 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2201
2202 if (_outputFileRecording)
2203 {
2204 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2205 "StartRecordingPlayout() is already recording");
2206 return 0;
2207 }
2208
2209 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002210 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002211 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2212
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002213 if ((codecInst != NULL) &&
2214 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002215 {
2216 _engineStatisticsPtr->SetLastError(
2217 VE_BAD_ARGUMENT, kTraceError,
2218 "StartRecordingPlayout() invalid compression");
2219 return(-1);
2220 }
2221 if(codecInst == NULL)
2222 {
2223 format = kFileFormatPcm16kHzFile;
2224 codecInst=&dummyCodec;
2225 }
2226 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2227 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2228 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2229 {
2230 format = kFileFormatWavFile;
2231 }
2232 else
2233 {
2234 format = kFileFormatCompressedFile;
2235 }
2236
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002237 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002238
2239 // Destroy the old instance
2240 if (_outputFileRecorderPtr)
2241 {
2242 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2243 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2244 _outputFileRecorderPtr = NULL;
2245 }
2246
2247 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2248 _outputFileRecorderId, (const FileFormats)format);
2249 if (_outputFileRecorderPtr == NULL)
2250 {
2251 _engineStatisticsPtr->SetLastError(
2252 VE_INVALID_ARGUMENT, kTraceError,
2253 "StartRecordingPlayout() fileRecorder format isnot correct");
2254 return -1;
2255 }
2256
2257 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2258 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2259 {
2260 _engineStatisticsPtr->SetLastError(
2261 VE_BAD_FILE, kTraceError,
2262 "StartRecordingAudioFile() failed to start file recording");
2263 _outputFileRecorderPtr->StopRecording();
2264 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2265 _outputFileRecorderPtr = NULL;
2266 return -1;
2267 }
2268 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2269 _outputFileRecording = true;
2270
2271 return 0;
2272}
2273
2274int Channel::StartRecordingPlayout(OutStream* stream,
2275 const CodecInst* codecInst)
2276{
2277 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2278 "Channel::StartRecordingPlayout()");
2279
2280 if (_outputFileRecording)
2281 {
2282 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2283 "StartRecordingPlayout() is already recording");
2284 return 0;
2285 }
2286
2287 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002288 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002289 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2290
2291 if (codecInst != NULL && codecInst->channels != 1)
2292 {
2293 _engineStatisticsPtr->SetLastError(
2294 VE_BAD_ARGUMENT, kTraceError,
2295 "StartRecordingPlayout() invalid compression");
2296 return(-1);
2297 }
2298 if(codecInst == NULL)
2299 {
2300 format = kFileFormatPcm16kHzFile;
2301 codecInst=&dummyCodec;
2302 }
2303 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2304 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2305 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2306 {
2307 format = kFileFormatWavFile;
2308 }
2309 else
2310 {
2311 format = kFileFormatCompressedFile;
2312 }
2313
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002314 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002315
2316 // Destroy the old instance
2317 if (_outputFileRecorderPtr)
2318 {
2319 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2320 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2321 _outputFileRecorderPtr = NULL;
2322 }
2323
2324 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2325 _outputFileRecorderId, (const FileFormats)format);
2326 if (_outputFileRecorderPtr == NULL)
2327 {
2328 _engineStatisticsPtr->SetLastError(
2329 VE_INVALID_ARGUMENT, kTraceError,
2330 "StartRecordingPlayout() fileRecorder format isnot correct");
2331 return -1;
2332 }
2333
2334 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2335 notificationTime) != 0)
2336 {
2337 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2338 "StartRecordingPlayout() failed to "
2339 "start file recording");
2340 _outputFileRecorderPtr->StopRecording();
2341 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2342 _outputFileRecorderPtr = NULL;
2343 return -1;
2344 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002345
niklase@google.com470e71d2011-07-07 08:21:25 +00002346 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2347 _outputFileRecording = true;
2348
2349 return 0;
2350}
2351
2352int Channel::StopRecordingPlayout()
2353{
2354 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2355 "Channel::StopRecordingPlayout()");
2356
2357 if (!_outputFileRecording)
2358 {
2359 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2360 "StopRecordingPlayout() isnot recording");
2361 return -1;
2362 }
2363
2364
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002365 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002366
2367 if (_outputFileRecorderPtr->StopRecording() != 0)
2368 {
2369 _engineStatisticsPtr->SetLastError(
2370 VE_STOP_RECORDING_FAILED, kTraceError,
2371 "StopRecording() could not stop recording");
2372 return(-1);
2373 }
2374 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2375 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2376 _outputFileRecorderPtr = NULL;
2377 _outputFileRecording = false;
2378
2379 return 0;
2380}
2381
2382void
2383Channel::SetMixWithMicStatus(bool mix)
2384{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002385 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002386 _mixFileWithMicrophone=mix;
2387}
2388
2389int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002390Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002391{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002392 int8_t currentLevel = _outputAudioLevel.Level();
2393 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002394 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2395 VoEId(_instanceId,_channelId),
2396 "GetSpeechOutputLevel() => level=%u", level);
2397 return 0;
2398}
2399
2400int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002401Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002402{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002403 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2404 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002405 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2406 VoEId(_instanceId,_channelId),
2407 "GetSpeechOutputLevelFullRange() => level=%u", level);
2408 return 0;
2409}
2410
2411int
2412Channel::SetMute(bool enable)
2413{
wu@webrtc.org63420662013-10-17 18:28:55 +00002414 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002415 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2416 "Channel::SetMute(enable=%d)", enable);
2417 _mute = enable;
2418 return 0;
2419}
2420
2421bool
2422Channel::Mute() const
2423{
wu@webrtc.org63420662013-10-17 18:28:55 +00002424 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002425 return _mute;
2426}
2427
2428int
2429Channel::SetOutputVolumePan(float left, float right)
2430{
wu@webrtc.org63420662013-10-17 18:28:55 +00002431 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002432 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2433 "Channel::SetOutputVolumePan()");
2434 _panLeft = left;
2435 _panRight = right;
2436 return 0;
2437}
2438
2439int
2440Channel::GetOutputVolumePan(float& left, float& right) const
2441{
wu@webrtc.org63420662013-10-17 18:28:55 +00002442 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002443 left = _panLeft;
2444 right = _panRight;
2445 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2446 VoEId(_instanceId,_channelId),
2447 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2448 return 0;
2449}
2450
2451int
2452Channel::SetChannelOutputVolumeScaling(float scaling)
2453{
wu@webrtc.org63420662013-10-17 18:28:55 +00002454 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002455 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2456 "Channel::SetChannelOutputVolumeScaling()");
2457 _outputGain = scaling;
2458 return 0;
2459}
2460
2461int
2462Channel::GetChannelOutputVolumeScaling(float& scaling) const
2463{
wu@webrtc.org63420662013-10-17 18:28:55 +00002464 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002465 scaling = _outputGain;
2466 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2467 VoEId(_instanceId,_channelId),
2468 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2469 return 0;
2470}
2471
niklase@google.com470e71d2011-07-07 08:21:25 +00002472int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002473 int lengthMs, int attenuationDb,
2474 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002475{
2476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2477 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2478 playDtmfEvent);
2479
2480 _playOutbandDtmfEvent = playDtmfEvent;
2481
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002482 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002483 attenuationDb) != 0)
2484 {
2485 _engineStatisticsPtr->SetLastError(
2486 VE_SEND_DTMF_FAILED,
2487 kTraceWarning,
2488 "SendTelephoneEventOutband() failed to send event");
2489 return -1;
2490 }
2491 return 0;
2492}
2493
2494int Channel::SendTelephoneEventInband(unsigned char eventCode,
2495 int lengthMs,
2496 int attenuationDb,
2497 bool playDtmfEvent)
2498{
2499 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2500 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2501 playDtmfEvent);
2502
2503 _playInbandDtmfEvent = playDtmfEvent;
2504 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2505
2506 return 0;
2507}
2508
2509int
niklase@google.com470e71d2011-07-07 08:21:25 +00002510Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2511{
2512 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2513 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002514 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002515 {
2516 _engineStatisticsPtr->SetLastError(
2517 VE_INVALID_ARGUMENT, kTraceError,
2518 "SetSendTelephoneEventPayloadType() invalid type");
2519 return -1;
2520 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002521 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002522 codec.plfreq = 8000;
2523 codec.pltype = type;
2524 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002525 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002526 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002527 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2528 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2529 _engineStatisticsPtr->SetLastError(
2530 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2531 "SetSendTelephoneEventPayloadType() failed to register send"
2532 "payload type");
2533 return -1;
2534 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002535 }
2536 _sendTelephoneEventPayloadType = type;
2537 return 0;
2538}
2539
2540int
2541Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2542{
2543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2544 "Channel::GetSendTelephoneEventPayloadType()");
2545 type = _sendTelephoneEventPayloadType;
2546 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2547 VoEId(_instanceId,_channelId),
2548 "GetSendTelephoneEventPayloadType() => type=%u", type);
2549 return 0;
2550}
2551
niklase@google.com470e71d2011-07-07 08:21:25 +00002552int
2553Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2554{
2555 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2556 "Channel::UpdateRxVadDetection()");
2557
2558 int vadDecision = 1;
2559
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002560 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002561
2562 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2563 {
2564 OnRxVadDetected(vadDecision);
2565 _oldVadDecision = vadDecision;
2566 }
2567
2568 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2569 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2570 vadDecision);
2571 return 0;
2572}
2573
2574int
2575Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2576{
2577 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2578 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002579 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002580
2581 if (_rxVadObserverPtr)
2582 {
2583 _engineStatisticsPtr->SetLastError(
2584 VE_INVALID_OPERATION, kTraceError,
2585 "RegisterRxVadObserver() observer already enabled");
2586 return -1;
2587 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002588 _rxVadObserverPtr = &observer;
2589 _RxVadDetection = true;
2590 return 0;
2591}
2592
2593int
2594Channel::DeRegisterRxVadObserver()
2595{
2596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2597 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002598 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002599
2600 if (!_rxVadObserverPtr)
2601 {
2602 _engineStatisticsPtr->SetLastError(
2603 VE_INVALID_OPERATION, kTraceWarning,
2604 "DeRegisterRxVadObserver() observer already disabled");
2605 return 0;
2606 }
2607 _rxVadObserverPtr = NULL;
2608 _RxVadDetection = false;
2609 return 0;
2610}
2611
2612int
2613Channel::VoiceActivityIndicator(int &activity)
2614{
2615 activity = _sendFrameType;
2616
2617 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002618 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002619 return 0;
2620}
2621
2622#ifdef WEBRTC_VOICE_ENGINE_AGC
2623
2624int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002625Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002626{
2627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2628 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2629 (int)enable, (int)mode);
2630
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002631 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002632 switch (mode)
2633 {
2634 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002635 break;
2636 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002637 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002638 break;
2639 case kAgcFixedDigital:
2640 agcMode = GainControl::kFixedDigital;
2641 break;
2642 case kAgcAdaptiveDigital:
2643 agcMode =GainControl::kAdaptiveDigital;
2644 break;
2645 default:
2646 _engineStatisticsPtr->SetLastError(
2647 VE_INVALID_ARGUMENT, kTraceError,
2648 "SetRxAgcStatus() invalid Agc mode");
2649 return -1;
2650 }
2651
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002652 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002653 {
2654 _engineStatisticsPtr->SetLastError(
2655 VE_APM_ERROR, kTraceError,
2656 "SetRxAgcStatus() failed to set Agc mode");
2657 return -1;
2658 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002659 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002660 {
2661 _engineStatisticsPtr->SetLastError(
2662 VE_APM_ERROR, kTraceError,
2663 "SetRxAgcStatus() failed to set Agc state");
2664 return -1;
2665 }
2666
2667 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002668 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002669
2670 return 0;
2671}
2672
2673int
2674Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2675{
2676 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2677 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2678
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002679 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002681 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002682
2683 enabled = enable;
2684
2685 switch (agcMode)
2686 {
2687 case GainControl::kFixedDigital:
2688 mode = kAgcFixedDigital;
2689 break;
2690 case GainControl::kAdaptiveDigital:
2691 mode = kAgcAdaptiveDigital;
2692 break;
2693 default:
2694 _engineStatisticsPtr->SetLastError(
2695 VE_APM_ERROR, kTraceError,
2696 "GetRxAgcStatus() invalid Agc mode");
2697 return -1;
2698 }
2699
2700 return 0;
2701}
2702
2703int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002704Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002705{
2706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2707 "Channel::SetRxAgcConfig()");
2708
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002709 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002710 config.targetLeveldBOv) != 0)
2711 {
2712 _engineStatisticsPtr->SetLastError(
2713 VE_APM_ERROR, kTraceError,
2714 "SetRxAgcConfig() failed to set target peak |level|"
2715 "(or envelope) of the Agc");
2716 return -1;
2717 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002718 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002719 config.digitalCompressionGaindB) != 0)
2720 {
2721 _engineStatisticsPtr->SetLastError(
2722 VE_APM_ERROR, kTraceError,
2723 "SetRxAgcConfig() failed to set the range in |gain| the"
2724 " digital compression stage may apply");
2725 return -1;
2726 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002727 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 config.limiterEnable) != 0)
2729 {
2730 _engineStatisticsPtr->SetLastError(
2731 VE_APM_ERROR, kTraceError,
2732 "SetRxAgcConfig() failed to set hard limiter to the signal");
2733 return -1;
2734 }
2735
2736 return 0;
2737}
2738
2739int
2740Channel::GetRxAgcConfig(AgcConfig& config)
2741{
2742 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2743 "Channel::GetRxAgcConfig(config=%?)");
2744
2745 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002746 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002747 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002748 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002749 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002750 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002751
2752 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2753 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2754 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2755 " limiterEnable=%d",
2756 config.targetLeveldBOv,
2757 config.digitalCompressionGaindB,
2758 config.limiterEnable);
2759
2760 return 0;
2761}
2762
2763#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2764
2765#ifdef WEBRTC_VOICE_ENGINE_NR
2766
2767int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002768Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002769{
2770 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2771 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2772 (int)enable, (int)mode);
2773
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002774 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002775 switch (mode)
2776 {
2777
2778 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002779 break;
2780 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002781 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002782 break;
2783 case kNsConference:
2784 nsLevel = NoiseSuppression::kHigh;
2785 break;
2786 case kNsLowSuppression:
2787 nsLevel = NoiseSuppression::kLow;
2788 break;
2789 case kNsModerateSuppression:
2790 nsLevel = NoiseSuppression::kModerate;
2791 break;
2792 case kNsHighSuppression:
2793 nsLevel = NoiseSuppression::kHigh;
2794 break;
2795 case kNsVeryHighSuppression:
2796 nsLevel = NoiseSuppression::kVeryHigh;
2797 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002798 }
2799
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002800 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002801 != 0)
2802 {
2803 _engineStatisticsPtr->SetLastError(
2804 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002805 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002806 return -1;
2807 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002808 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002809 {
2810 _engineStatisticsPtr->SetLastError(
2811 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002812 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002813 return -1;
2814 }
2815
2816 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002817 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002818
2819 return 0;
2820}
2821
2822int
2823Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2824{
2825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2826 "Channel::GetRxNsStatus(enable=?, mode=?)");
2827
2828 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002829 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002830 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002831 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002832
2833 enabled = enable;
2834
2835 switch (ncLevel)
2836 {
2837 case NoiseSuppression::kLow:
2838 mode = kNsLowSuppression;
2839 break;
2840 case NoiseSuppression::kModerate:
2841 mode = kNsModerateSuppression;
2842 break;
2843 case NoiseSuppression::kHigh:
2844 mode = kNsHighSuppression;
2845 break;
2846 case NoiseSuppression::kVeryHigh:
2847 mode = kNsVeryHighSuppression;
2848 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002849 }
2850
2851 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2852 VoEId(_instanceId,_channelId),
2853 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2854 return 0;
2855}
2856
2857#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2858
2859int
niklase@google.com470e71d2011-07-07 08:21:25 +00002860Channel::SetLocalSSRC(unsigned int ssrc)
2861{
2862 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2863 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002864 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002865 {
2866 _engineStatisticsPtr->SetLastError(
2867 VE_ALREADY_SENDING, kTraceError,
2868 "SetLocalSSRC() already sending");
2869 return -1;
2870 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002871 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002872 return 0;
2873}
2874
2875int
2876Channel::GetLocalSSRC(unsigned int& ssrc)
2877{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002878 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2880 VoEId(_instanceId,_channelId),
2881 "GetLocalSSRC() => ssrc=%lu", ssrc);
2882 return 0;
2883}
2884
2885int
2886Channel::GetRemoteSSRC(unsigned int& ssrc)
2887{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002888 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002889 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2890 VoEId(_instanceId,_channelId),
2891 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2892 return 0;
2893}
2894
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002895int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002896 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002897 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002898}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002899
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002900int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2901 unsigned char id) {
2902 rtp_header_parser_->DeregisterRtpHeaderExtension(
2903 kRtpExtensionAudioLevel);
2904 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2905 kRtpExtensionAudioLevel, id)) {
2906 return -1;
2907 }
2908 return 0;
2909}
2910
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002911int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2912 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2913}
2914
2915int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2916 rtp_header_parser_->DeregisterRtpHeaderExtension(
2917 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002918 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2919 kRtpExtensionAbsoluteSendTime, id)) {
2920 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002921 }
2922 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002923}
2924
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002925void Channel::SetRTCPStatus(bool enable) {
2926 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2927 "Channel::SetRTCPStatus()");
2928 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002929}
2930
2931int
2932Channel::GetRTCPStatus(bool& enabled)
2933{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002934 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002935 enabled = (method != kRtcpOff);
2936 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2937 VoEId(_instanceId,_channelId),
2938 "GetRTCPStatus() => enabled=%d", enabled);
2939 return 0;
2940}
2941
2942int
2943Channel::SetRTCP_CNAME(const char cName[256])
2944{
2945 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2946 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002947 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002948 {
2949 _engineStatisticsPtr->SetLastError(
2950 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2951 "SetRTCP_CNAME() failed to set RTCP CNAME");
2952 return -1;
2953 }
2954 return 0;
2955}
2956
2957int
niklase@google.com470e71d2011-07-07 08:21:25 +00002958Channel::GetRemoteRTCP_CNAME(char cName[256])
2959{
2960 if (cName == NULL)
2961 {
2962 _engineStatisticsPtr->SetLastError(
2963 VE_INVALID_ARGUMENT, kTraceError,
2964 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2965 return -1;
2966 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002967 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002968 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002969 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002970 {
2971 _engineStatisticsPtr->SetLastError(
2972 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2973 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2974 return -1;
2975 }
2976 strcpy(cName, cname);
2977 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2978 VoEId(_instanceId, _channelId),
2979 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2980 return 0;
2981}
2982
2983int
2984Channel::GetRemoteRTCPData(
2985 unsigned int& NTPHigh,
2986 unsigned int& NTPLow,
2987 unsigned int& timestamp,
2988 unsigned int& playoutTimestamp,
2989 unsigned int* jitter,
2990 unsigned short* fractionLost)
2991{
2992 // --- Information from sender info in received Sender Reports
2993
2994 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002995 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002996 {
2997 _engineStatisticsPtr->SetLastError(
2998 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002999 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003000 "side");
3001 return -1;
3002 }
3003
3004 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3005 // and octet count)
3006 NTPHigh = senderInfo.NTPseconds;
3007 NTPLow = senderInfo.NTPfraction;
3008 timestamp = senderInfo.RTPtimeStamp;
3009
3010 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3011 VoEId(_instanceId, _channelId),
3012 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3013 "timestamp=%lu",
3014 NTPHigh, NTPLow, timestamp);
3015
3016 // --- Locally derived information
3017
3018 // This value is updated on each incoming RTCP packet (0 when no packet
3019 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003020 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003021
3022 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3023 VoEId(_instanceId, _channelId),
3024 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003025 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003026
3027 if (NULL != jitter || NULL != fractionLost)
3028 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003029 // Get all RTCP receiver report blocks that have been received on this
3030 // channel. If we receive RTP packets from a remote source we know the
3031 // remote SSRC and use the report block from him.
3032 // Otherwise use the first report block.
3033 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003034 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003035 remote_stats.empty()) {
3036 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3037 VoEId(_instanceId, _channelId),
3038 "GetRemoteRTCPData() failed to measure statistics due"
3039 " to lack of received RTP and/or RTCP packets");
3040 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003041 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003042
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003043 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003044 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3045 for (; it != remote_stats.end(); ++it) {
3046 if (it->remoteSSRC == remoteSSRC)
3047 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003048 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003049
3050 if (it == remote_stats.end()) {
3051 // If we have not received any RTCP packets from this SSRC it probably
3052 // means that we have not received any RTP packets.
3053 // Use the first received report block instead.
3054 it = remote_stats.begin();
3055 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003056 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003057
xians@webrtc.org79af7342012-01-31 12:22:14 +00003058 if (jitter) {
3059 *jitter = it->jitter;
3060 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3061 VoEId(_instanceId, _channelId),
3062 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3063 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003064
xians@webrtc.org79af7342012-01-31 12:22:14 +00003065 if (fractionLost) {
3066 *fractionLost = it->fractionLost;
3067 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3068 VoEId(_instanceId, _channelId),
3069 "GetRemoteRTCPData() => fractionLost = %lu",
3070 *fractionLost);
3071 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003072 }
3073 return 0;
3074}
3075
3076int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003077Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003078 unsigned int name,
3079 const char* data,
3080 unsigned short dataLengthInBytes)
3081{
3082 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3083 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003084 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003085 {
3086 _engineStatisticsPtr->SetLastError(
3087 VE_NOT_SENDING, kTraceError,
3088 "SendApplicationDefinedRTCPPacket() not sending");
3089 return -1;
3090 }
3091 if (NULL == data)
3092 {
3093 _engineStatisticsPtr->SetLastError(
3094 VE_INVALID_ARGUMENT, kTraceError,
3095 "SendApplicationDefinedRTCPPacket() invalid data value");
3096 return -1;
3097 }
3098 if (dataLengthInBytes % 4 != 0)
3099 {
3100 _engineStatisticsPtr->SetLastError(
3101 VE_INVALID_ARGUMENT, kTraceError,
3102 "SendApplicationDefinedRTCPPacket() invalid length value");
3103 return -1;
3104 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003105 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003106 if (status == kRtcpOff)
3107 {
3108 _engineStatisticsPtr->SetLastError(
3109 VE_RTCP_ERROR, kTraceError,
3110 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3111 return -1;
3112 }
3113
3114 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003115 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003116 subType,
3117 name,
3118 (const unsigned char*) data,
3119 dataLengthInBytes) != 0)
3120 {
3121 _engineStatisticsPtr->SetLastError(
3122 VE_SEND_ERROR, kTraceError,
3123 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3124 return -1;
3125 }
3126 return 0;
3127}
3128
3129int
3130Channel::GetRTPStatistics(
3131 unsigned int& averageJitterMs,
3132 unsigned int& maxJitterMs,
3133 unsigned int& discardedPackets)
3134{
niklase@google.com470e71d2011-07-07 08:21:25 +00003135 // The jitter statistics is updated for each received RTP packet and is
3136 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003137 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3138 // If RTCP is off, there is no timed thread in the RTCP module regularly
3139 // generating new stats, trigger the update manually here instead.
3140 StreamStatistician* statistician =
3141 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3142 if (statistician) {
3143 // Don't use returned statistics, use data from proxy instead so that
3144 // max jitter can be fetched atomically.
3145 RtcpStatistics s;
3146 statistician->GetStatistics(&s, true);
3147 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003148 }
3149
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003150 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003151 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003152 if (playoutFrequency > 0) {
3153 // Scale RTP statistics given the current playout frequency
3154 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3155 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003156 }
3157
3158 discardedPackets = _numberOfDiscardedPackets;
3159
3160 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3161 VoEId(_instanceId, _channelId),
3162 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003163 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003164 averageJitterMs, maxJitterMs, discardedPackets);
3165 return 0;
3166}
3167
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003168int Channel::GetRemoteRTCPReportBlocks(
3169 std::vector<ReportBlock>* report_blocks) {
3170 if (report_blocks == NULL) {
3171 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3172 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3173 return -1;
3174 }
3175
3176 // Get the report blocks from the latest received RTCP Sender or Receiver
3177 // Report. Each element in the vector contains the sender's SSRC and a
3178 // report block according to RFC 3550.
3179 std::vector<RTCPReportBlock> rtcp_report_blocks;
3180 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3181 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3182 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3183 return -1;
3184 }
3185
3186 if (rtcp_report_blocks.empty())
3187 return 0;
3188
3189 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3190 for (; it != rtcp_report_blocks.end(); ++it) {
3191 ReportBlock report_block;
3192 report_block.sender_SSRC = it->remoteSSRC;
3193 report_block.source_SSRC = it->sourceSSRC;
3194 report_block.fraction_lost = it->fractionLost;
3195 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3196 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3197 report_block.interarrival_jitter = it->jitter;
3198 report_block.last_SR_timestamp = it->lastSR;
3199 report_block.delay_since_last_SR = it->delaySinceLastSR;
3200 report_blocks->push_back(report_block);
3201 }
3202 return 0;
3203}
3204
niklase@google.com470e71d2011-07-07 08:21:25 +00003205int
3206Channel::GetRTPStatistics(CallStatistics& stats)
3207{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003208 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003209
3210 // The jitter statistics is updated for each received RTP packet and is
3211 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003212 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003213 StreamStatistician* statistician =
3214 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3215 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003216 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3217 _engineStatisticsPtr->SetLastError(
3218 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3219 "GetRTPStatistics() failed to read RTP statistics from the "
3220 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003221 }
3222
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003223 stats.fractionLost = statistics.fraction_lost;
3224 stats.cumulativeLost = statistics.cumulative_lost;
3225 stats.extendedMax = statistics.extended_max_sequence_number;
3226 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003227
3228 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3229 VoEId(_instanceId, _channelId),
3230 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003231 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003232 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3233 stats.jitterSamples);
3234
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003235 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003236 stats.rttMs = GetRTT();
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003237 if (stats.rttMs == 0) {
3238 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3239 "GetRTPStatistics() failed to get RTT");
3240 } else {
3241 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003242 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003243 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003244
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003245 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003246
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003247 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003248 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003249 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003250 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003251
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003252 if (statistician) {
3253 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3254 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003255
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003256 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003257 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003258 {
3259 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3260 VoEId(_instanceId, _channelId),
3261 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003262 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003263 }
3264
3265 stats.bytesSent = bytesSent;
3266 stats.packetsSent = packetsSent;
3267 stats.bytesReceived = bytesReceived;
3268 stats.packetsReceived = packetsReceived;
3269
3270 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3271 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003272 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3273 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003274 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3275 stats.packetsReceived);
3276
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003277 // --- Timestamps
3278 {
3279 CriticalSectionScoped lock(ts_stats_lock_.get());
3280 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3281 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003282 return 0;
3283}
3284
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003285int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003286 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003287 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003288
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003289 if (enable) {
3290 if (redPayloadtype < 0 || redPayloadtype > 127) {
3291 _engineStatisticsPtr->SetLastError(
3292 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003293 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003294 return -1;
3295 }
3296
3297 if (SetRedPayloadType(redPayloadtype) < 0) {
3298 _engineStatisticsPtr->SetLastError(
3299 VE_CODEC_ERROR, kTraceError,
3300 "SetSecondarySendCodec() Failed to register RED ACM");
3301 return -1;
3302 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003303 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003304
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003305 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003306 _engineStatisticsPtr->SetLastError(
3307 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003308 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003309 return -1;
3310 }
3311 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003312}
3313
3314int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003315Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003316{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003317 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003318 if (enabled)
3319 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003320 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003321 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003322 {
3323 _engineStatisticsPtr->SetLastError(
3324 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003325 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003326 "module");
3327 return -1;
3328 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003329 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003330 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3331 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003332 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003333 enabled, redPayloadtype);
3334 return 0;
3335 }
3336 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3337 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003338 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003339 return 0;
3340}
3341
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003342int Channel::SetCodecFECStatus(bool enable) {
3343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3344 "Channel::SetCodecFECStatus()");
3345
3346 if (audio_coding_->SetCodecFEC(enable) != 0) {
3347 _engineStatisticsPtr->SetLastError(
3348 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3349 "SetCodecFECStatus() failed to set FEC state");
3350 return -1;
3351 }
3352 return 0;
3353}
3354
3355bool Channel::GetCodecFECStatus() {
3356 bool enabled = audio_coding_->CodecFEC();
3357 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3358 VoEId(_instanceId, _channelId),
3359 "GetCodecFECStatus() => enabled=%d", enabled);
3360 return enabled;
3361}
3362
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003363void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3364 // None of these functions can fail.
3365 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003366 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3367 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003368 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003369 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003370 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003371 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003372}
3373
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003374// Called when we are missing one or more packets.
3375int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003376 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3377}
3378
niklase@google.com470e71d2011-07-07 08:21:25 +00003379int
niklase@google.com470e71d2011-07-07 08:21:25 +00003380Channel::StartRTPDump(const char fileNameUTF8[1024],
3381 RTPDirections direction)
3382{
3383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3384 "Channel::StartRTPDump()");
3385 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3386 {
3387 _engineStatisticsPtr->SetLastError(
3388 VE_INVALID_ARGUMENT, kTraceError,
3389 "StartRTPDump() invalid RTP direction");
3390 return -1;
3391 }
3392 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3393 &_rtpDumpIn : &_rtpDumpOut;
3394 if (rtpDumpPtr == NULL)
3395 {
3396 assert(false);
3397 return -1;
3398 }
3399 if (rtpDumpPtr->IsActive())
3400 {
3401 rtpDumpPtr->Stop();
3402 }
3403 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3404 {
3405 _engineStatisticsPtr->SetLastError(
3406 VE_BAD_FILE, kTraceError,
3407 "StartRTPDump() failed to create file");
3408 return -1;
3409 }
3410 return 0;
3411}
3412
3413int
3414Channel::StopRTPDump(RTPDirections direction)
3415{
3416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3417 "Channel::StopRTPDump()");
3418 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3419 {
3420 _engineStatisticsPtr->SetLastError(
3421 VE_INVALID_ARGUMENT, kTraceError,
3422 "StopRTPDump() invalid RTP direction");
3423 return -1;
3424 }
3425 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3426 &_rtpDumpIn : &_rtpDumpOut;
3427 if (rtpDumpPtr == NULL)
3428 {
3429 assert(false);
3430 return -1;
3431 }
3432 if (!rtpDumpPtr->IsActive())
3433 {
3434 return 0;
3435 }
3436 return rtpDumpPtr->Stop();
3437}
3438
3439bool
3440Channel::RTPDumpIsActive(RTPDirections direction)
3441{
3442 if ((direction != kRtpIncoming) &&
3443 (direction != kRtpOutgoing))
3444 {
3445 _engineStatisticsPtr->SetLastError(
3446 VE_INVALID_ARGUMENT, kTraceError,
3447 "RTPDumpIsActive() invalid RTP direction");
3448 return false;
3449 }
3450 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3451 &_rtpDumpIn : &_rtpDumpOut;
3452 return rtpDumpPtr->IsActive();
3453}
3454
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003455void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3456 int video_channel) {
3457 CriticalSectionScoped cs(&_callbackCritSect);
3458 if (vie_network_) {
3459 vie_network_->Release();
3460 vie_network_ = NULL;
3461 }
3462 video_channel_ = -1;
3463
3464 if (vie_network != NULL && video_channel != -1) {
3465 vie_network_ = vie_network;
3466 video_channel_ = video_channel;
3467 }
3468}
3469
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003470uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003471Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003472{
3473 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003474 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003475 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003476 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003477 return 0;
3478}
3479
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003480void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003481 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003482 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003483 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003484 CodecInst codec;
3485 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003486
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003487 if (!mono_recording_audio_.get()) {
3488 // Temporary space for DownConvertToCodecFormat.
3489 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003490 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003491 DownConvertToCodecFormat(audio_data,
3492 number_of_frames,
3493 number_of_channels,
3494 sample_rate,
3495 codec.channels,
3496 codec.plfreq,
3497 mono_recording_audio_.get(),
3498 &input_resampler_,
3499 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003500}
3501
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003502uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003503Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003504{
3505 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3506 "Channel::PrepareEncodeAndSend()");
3507
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003508 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003509 {
3510 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3511 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003512 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003513 }
3514
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003515 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003516 {
3517 MixOrReplaceAudioWithFile(mixingFrequency);
3518 }
3519
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003520 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3521 if (is_muted) {
3522 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003523 }
3524
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003525 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003526 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003527 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003528 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003529 if (_inputExternalMediaCallbackPtr)
3530 {
3531 _inputExternalMediaCallbackPtr->Process(
3532 _channelId,
3533 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003534 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003535 _audioFrame.samples_per_channel_,
3536 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003537 isStereo);
3538 }
3539 }
3540
3541 InsertInbandDtmfTone();
3542
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003543 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003544 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003545 if (is_muted) {
3546 rms_level_.ProcessMuted(length);
3547 } else {
3548 rms_level_.Process(_audioFrame.data_, length);
3549 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003550 }
3551
niklase@google.com470e71d2011-07-07 08:21:25 +00003552 return 0;
3553}
3554
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003555uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003556Channel::EncodeAndSend()
3557{
3558 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3559 "Channel::EncodeAndSend()");
3560
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003561 assert(_audioFrame.num_channels_ <= 2);
3562 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003563 {
3564 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3565 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003566 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003567 }
3568
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003569 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003570
3571 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3572
3573 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003574 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003575 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003576 {
3577 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3578 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003579 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003580 }
3581
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003582 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003583
3584 // --- Encode if complete frame is ready
3585
3586 // This call will trigger AudioPacketizationCallback::SendData if encoding
3587 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003588 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003589}
3590
3591int Channel::RegisterExternalMediaProcessing(
3592 ProcessingTypes type,
3593 VoEMediaProcess& processObject)
3594{
3595 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3596 "Channel::RegisterExternalMediaProcessing()");
3597
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003598 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003599
3600 if (kPlaybackPerChannel == type)
3601 {
3602 if (_outputExternalMediaCallbackPtr)
3603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_INVALID_OPERATION, kTraceError,
3606 "Channel::RegisterExternalMediaProcessing() "
3607 "output external media already enabled");
3608 return -1;
3609 }
3610 _outputExternalMediaCallbackPtr = &processObject;
3611 _outputExternalMedia = true;
3612 }
3613 else if (kRecordingPerChannel == type)
3614 {
3615 if (_inputExternalMediaCallbackPtr)
3616 {
3617 _engineStatisticsPtr->SetLastError(
3618 VE_INVALID_OPERATION, kTraceError,
3619 "Channel::RegisterExternalMediaProcessing() "
3620 "output external media already enabled");
3621 return -1;
3622 }
3623 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003624 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003625 }
3626 return 0;
3627}
3628
3629int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3630{
3631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3632 "Channel::DeRegisterExternalMediaProcessing()");
3633
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003634 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003635
3636 if (kPlaybackPerChannel == type)
3637 {
3638 if (!_outputExternalMediaCallbackPtr)
3639 {
3640 _engineStatisticsPtr->SetLastError(
3641 VE_INVALID_OPERATION, kTraceWarning,
3642 "Channel::DeRegisterExternalMediaProcessing() "
3643 "output external media already disabled");
3644 return 0;
3645 }
3646 _outputExternalMedia = false;
3647 _outputExternalMediaCallbackPtr = NULL;
3648 }
3649 else if (kRecordingPerChannel == type)
3650 {
3651 if (!_inputExternalMediaCallbackPtr)
3652 {
3653 _engineStatisticsPtr->SetLastError(
3654 VE_INVALID_OPERATION, kTraceWarning,
3655 "Channel::DeRegisterExternalMediaProcessing() "
3656 "input external media already disabled");
3657 return 0;
3658 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003659 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003660 _inputExternalMediaCallbackPtr = NULL;
3661 }
3662
3663 return 0;
3664}
3665
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003666int Channel::SetExternalMixing(bool enabled) {
3667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3668 "Channel::SetExternalMixing(enabled=%d)", enabled);
3669
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003670 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003671 {
3672 _engineStatisticsPtr->SetLastError(
3673 VE_INVALID_OPERATION, kTraceError,
3674 "Channel::SetExternalMixing() "
3675 "external mixing cannot be changed while playing.");
3676 return -1;
3677 }
3678
3679 _externalMixing = enabled;
3680
3681 return 0;
3682}
3683
niklase@google.com470e71d2011-07-07 08:21:25 +00003684int
niklase@google.com470e71d2011-07-07 08:21:25 +00003685Channel::GetNetworkStatistics(NetworkStatistics& stats)
3686{
3687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3688 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003689 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003690}
3691
wu@webrtc.org24301a62013-12-13 19:17:43 +00003692void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3693 audio_coding_->GetDecodingCallStatistics(stats);
3694}
3695
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003696bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3697 int* playout_buffer_delay_ms) const {
3698 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003700 "Channel::GetDelayEstimate() no valid estimate.");
3701 return false;
3702 }
3703 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3704 _recPacketDelayMs;
3705 *playout_buffer_delay_ms = playout_delay_ms_;
3706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3707 "Channel::GetDelayEstimate()");
3708 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003709}
3710
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003711int Channel::SetInitialPlayoutDelay(int delay_ms)
3712{
3713 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3714 "Channel::SetInitialPlayoutDelay()");
3715 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3716 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3717 {
3718 _engineStatisticsPtr->SetLastError(
3719 VE_INVALID_ARGUMENT, kTraceError,
3720 "SetInitialPlayoutDelay() invalid min delay");
3721 return -1;
3722 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003723 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3727 "SetInitialPlayoutDelay() failed to set min playout delay");
3728 return -1;
3729 }
3730 return 0;
3731}
3732
3733
niklase@google.com470e71d2011-07-07 08:21:25 +00003734int
3735Channel::SetMinimumPlayoutDelay(int delayMs)
3736{
3737 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3738 "Channel::SetMinimumPlayoutDelay()");
3739 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3740 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3741 {
3742 _engineStatisticsPtr->SetLastError(
3743 VE_INVALID_ARGUMENT, kTraceError,
3744 "SetMinimumPlayoutDelay() invalid min delay");
3745 return -1;
3746 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003747 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003748 {
3749 _engineStatisticsPtr->SetLastError(
3750 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3751 "SetMinimumPlayoutDelay() failed to set min playout delay");
3752 return -1;
3753 }
3754 return 0;
3755}
3756
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003757void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3758 uint32_t playout_timestamp = 0;
3759
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003760 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003761 // This can happen if this channel has not been received any RTP packet. In
3762 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003763 return;
3764 }
3765
3766 uint16_t delay_ms = 0;
3767 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3768 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3769 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3770 " delay from the ADM");
3771 _engineStatisticsPtr->SetLastError(
3772 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3773 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3774 return;
3775 }
3776
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003777 jitter_buffer_playout_timestamp_ = playout_timestamp;
3778
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003779 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003780 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003781
3782 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3783 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3784 playout_timestamp);
3785
3786 if (rtcp) {
3787 playout_timestamp_rtcp_ = playout_timestamp;
3788 } else {
3789 playout_timestamp_rtp_ = playout_timestamp;
3790 }
3791 playout_delay_ms_ = delay_ms;
3792}
3793
3794int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3796 "Channel::GetPlayoutTimestamp()");
3797 if (playout_timestamp_rtp_ == 0) {
3798 _engineStatisticsPtr->SetLastError(
3799 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3800 "GetPlayoutTimestamp() failed to retrieve timestamp");
3801 return -1;
3802 }
3803 timestamp = playout_timestamp_rtp_;
3804 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3805 VoEId(_instanceId,_channelId),
3806 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3807 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003808}
3809
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003810int Channel::SetInitTimestamp(unsigned int timestamp) {
3811 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003812 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003813 if (channel_state_.Get().sending) {
3814 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3815 "SetInitTimestamp() already sending");
3816 return -1;
3817 }
3818 _rtpRtcpModule->SetStartTimestamp(timestamp);
3819 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003820}
3821
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003822int Channel::SetInitSequenceNumber(short sequenceNumber) {
3823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3824 "Channel::SetInitSequenceNumber()");
3825 if (channel_state_.Get().sending) {
3826 _engineStatisticsPtr->SetLastError(
3827 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3828 return -1;
3829 }
3830 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3831 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003832}
3833
3834int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003835Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003836{
3837 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3838 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003839 *rtpRtcpModule = _rtpRtcpModule.get();
3840 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003841 return 0;
3842}
3843
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003844// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3845// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003846int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003847Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003848{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00003849 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003850 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003851
3852 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003853 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003854
3855 if (_inputFilePlayerPtr == NULL)
3856 {
3857 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3858 VoEId(_instanceId, _channelId),
3859 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3860 " doesnt exist");
3861 return -1;
3862 }
3863
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003864 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003865 fileSamples,
3866 mixingFrequency) == -1)
3867 {
3868 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3869 VoEId(_instanceId, _channelId),
3870 "Channel::MixOrReplaceAudioWithFile() file mixing "
3871 "failed");
3872 return -1;
3873 }
3874 if (fileSamples == 0)
3875 {
3876 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3877 VoEId(_instanceId, _channelId),
3878 "Channel::MixOrReplaceAudioWithFile() file is ended");
3879 return 0;
3880 }
3881 }
3882
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003883 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003884
3885 if (_mixFileWithMicrophone)
3886 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003887 // Currently file stream is always mono.
3888 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003889 MixWithSat(_audioFrame.data_,
3890 _audioFrame.num_channels_,
3891 fileBuffer.get(),
3892 1,
3893 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003894 }
3895 else
3896 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003897 // Replace ACM audio with file.
3898 // Currently file stream is always mono.
3899 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003900 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003901 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003902 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003903 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003904 mixingFrequency,
3905 AudioFrame::kNormalSpeech,
3906 AudioFrame::kVadUnknown,
3907 1);
3908
3909 }
3910 return 0;
3911}
3912
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003913int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003914Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003915 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003916{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003917 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003918
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003919 scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003920 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003921
3922 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003923 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003924
3925 if (_outputFilePlayerPtr == NULL)
3926 {
3927 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3928 VoEId(_instanceId, _channelId),
3929 "Channel::MixAudioWithFile() file mixing failed");
3930 return -1;
3931 }
3932
3933 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003934 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003935 fileSamples,
3936 mixingFrequency) == -1)
3937 {
3938 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3939 VoEId(_instanceId, _channelId),
3940 "Channel::MixAudioWithFile() file mixing failed");
3941 return -1;
3942 }
3943 }
3944
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003945 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003946 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003947 // Currently file stream is always mono.
3948 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003949 MixWithSat(audioFrame.data_,
3950 audioFrame.num_channels_,
3951 fileBuffer.get(),
3952 1,
3953 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003954 }
3955 else
3956 {
3957 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003958 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003959 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003960 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003961 return -1;
3962 }
3963
3964 return 0;
3965}
3966
3967int
3968Channel::InsertInbandDtmfTone()
3969{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003970 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003971 if (_inbandDtmfQueue.PendingDtmf() &&
3972 !_inbandDtmfGenerator.IsAddingTone() &&
3973 _inbandDtmfGenerator.DelaySinceLastTone() >
3974 kMinTelephoneEventSeparationMs)
3975 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003976 int8_t eventCode(0);
3977 uint16_t lengthMs(0);
3978 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003979
3980 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3981 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3982 if (_playInbandDtmfEvent)
3983 {
3984 // Add tone to output mixer using a reduced length to minimize
3985 // risk of echo.
3986 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3987 attenuationDb);
3988 }
3989 }
3990
3991 if (_inbandDtmfGenerator.IsAddingTone())
3992 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003993 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003994 _inbandDtmfGenerator.GetSampleRate(frequency);
3995
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003996 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003997 {
3998 // Update sample rate of Dtmf tone since the mixing frequency
3999 // has changed.
4000 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004001 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004002 // Reset the tone to be added taking the new sample rate into
4003 // account.
4004 _inbandDtmfGenerator.ResetTone();
4005 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004006
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004007 int16_t toneBuffer[320];
4008 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004009 // Get 10ms tone segment and set time since last tone to zero
4010 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4011 {
4012 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4013 VoEId(_instanceId, _channelId),
4014 "Channel::EncodeAndSend() inserting Dtmf failed");
4015 return -1;
4016 }
4017
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004018 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004019 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004020 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004021 sample++)
4022 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004023 for (int channel = 0;
4024 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004025 channel++)
4026 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004027 const int index = sample * _audioFrame.num_channels_ + channel;
4028 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004029 }
4030 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004031
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004032 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004033 } else
4034 {
4035 // Add 10ms to "delay-since-last-tone" counter
4036 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4037 }
4038 return 0;
4039}
4040
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004041int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00004042Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00004043{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004044 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004045 if (_transportPtr == NULL)
4046 {
4047 return -1;
4048 }
4049 if (!RTCP)
4050 {
4051 return _transportPtr->SendPacket(_channelId, data, len);
4052 }
4053 else
4054 {
4055 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4056 }
4057}
4058
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004059// Called for incoming RTP packets after successful RTP header parsing.
4060void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4061 uint16_t sequence_number) {
4062 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4063 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4064 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004065
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004066 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004067 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004068
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004069 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004070 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004071
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004072 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4073 // every incoming packet.
4074 uint32_t timestamp_diff_ms = (rtp_timestamp -
4075 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004076 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4077 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4078 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4079 // timestamp, the resulting difference is negative, but is set to zero.
4080 // This can happen when a network glitch causes a packet to arrive late,
4081 // and during long comfort noise periods with clock drift.
4082 timestamp_diff_ms = 0;
4083 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004084
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004085 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4086 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004087
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004088 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004089
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004090 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004091
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004092 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4093 _recPacketDelayMs = packet_delay_ms;
4094 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004095
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004096 if (_average_jitter_buffer_delay_us == 0) {
4097 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4098 return;
4099 }
4100
4101 // Filter average delay value using exponential filter (alpha is
4102 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4103 // risk of rounding error) and compensate for it in GetDelayEstimate()
4104 // later.
4105 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4106 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004107}
4108
4109void
4110Channel::RegisterReceiveCodecsToRTPModule()
4111{
4112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4113 "Channel::RegisterReceiveCodecsToRTPModule()");
4114
4115
4116 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004117 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004118
4119 for (int idx = 0; idx < nSupportedCodecs; idx++)
4120 {
4121 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004122 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004123 (rtp_receiver_->RegisterReceivePayload(
4124 codec.plname,
4125 codec.pltype,
4126 codec.plfreq,
4127 codec.channels,
4128 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004129 {
4130 WEBRTC_TRACE(
4131 kTraceWarning,
4132 kTraceVoice,
4133 VoEId(_instanceId, _channelId),
4134 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4135 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4136 codec.plname, codec.pltype, codec.plfreq,
4137 codec.channels, codec.rate);
4138 }
4139 else
4140 {
4141 WEBRTC_TRACE(
4142 kTraceInfo,
4143 kTraceVoice,
4144 VoEId(_instanceId, _channelId),
4145 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004146 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004147 "receiver",
4148 codec.plname, codec.pltype, codec.plfreq,
4149 codec.channels, codec.rate);
4150 }
4151 }
4152}
4153
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004154// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004155int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004156 CodecInst codec;
4157 bool found_red = false;
4158
4159 // Get default RED settings from the ACM database
4160 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4161 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004162 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004163 if (!STR_CASE_CMP(codec.plname, "RED")) {
4164 found_red = true;
4165 break;
4166 }
4167 }
4168
4169 if (!found_red) {
4170 _engineStatisticsPtr->SetLastError(
4171 VE_CODEC_ERROR, kTraceError,
4172 "SetRedPayloadType() RED is not supported");
4173 return -1;
4174 }
4175
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004176 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004177 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004178 _engineStatisticsPtr->SetLastError(
4179 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4180 "SetRedPayloadType() RED registration in ACM module failed");
4181 return -1;
4182 }
4183
4184 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4185 _engineStatisticsPtr->SetLastError(
4186 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4187 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4188 return -1;
4189 }
4190 return 0;
4191}
4192
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004193int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4194 unsigned char id) {
4195 int error = 0;
4196 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4197 if (enable) {
4198 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4199 }
4200 return error;
4201}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004202
wu@webrtc.org94454b72014-06-05 20:34:08 +00004203int32_t Channel::GetPlayoutFrequency() {
4204 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4205 CodecInst current_recive_codec;
4206 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4207 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4208 // Even though the actual sampling rate for G.722 audio is
4209 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4210 // 8,000 Hz because that value was erroneously assigned in
4211 // RFC 1890 and must remain unchanged for backward compatibility.
4212 playout_frequency = 8000;
4213 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4214 // We are resampling Opus internally to 32,000 Hz until all our
4215 // DSP routines can operate at 48,000 Hz, but the RTP clock
4216 // rate for the Opus payload format is standardized to 48,000 Hz,
4217 // because that is the maximum supported decoding sampling rate.
4218 playout_frequency = 48000;
4219 }
4220 }
4221 return playout_frequency;
4222}
4223
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004224int64_t Channel::GetRTT() const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004225 RTCPMethod method = _rtpRtcpModule->RTCP();
4226 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004227 return 0;
4228 }
4229 std::vector<RTCPReportBlock> report_blocks;
4230 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4231 if (report_blocks.empty()) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004232 return 0;
4233 }
4234
4235 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4236 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4237 for (; it != report_blocks.end(); ++it) {
4238 if (it->remoteSSRC == remoteSSRC)
4239 break;
4240 }
4241 if (it == report_blocks.end()) {
4242 // We have not received packets with SSRC matching the report blocks.
4243 // To calculate RTT we try with the SSRC of the first report block.
4244 // This is very important for send-only channels where we don't know
4245 // the SSRC of the other end.
4246 remoteSSRC = report_blocks[0].remoteSSRC;
4247 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004248 int64_t rtt = 0;
4249 int64_t avg_rtt = 0;
4250 int64_t max_rtt= 0;
4251 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004252 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4253 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004254 return 0;
4255 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004256 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004257}
4258
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004259} // namespace voe
4260} // namespace webrtc