blob: 927440a88e51ca6a6dc6c3be56ea7dbcfc7d653f [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.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000090 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000091 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
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000917 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
918
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 // End of modules shutdown
920
921 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000922 if (vie_network_) {
923 vie_network_->Release();
924 vie_network_ = NULL;
925 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 RtpDump::DestroyRtpDump(&_rtpDumpIn);
927 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000930 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931}
932
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000933int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000934Channel::Init()
935{
936 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
937 "Channel::Init()");
938
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000939 channel_state_.Reset();
940
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 // --- Initial sanity
942
943 if ((_engineStatisticsPtr == NULL) ||
944 (_moduleProcessThreadPtr == NULL))
945 {
946 WEBRTC_TRACE(kTraceError, kTraceVoice,
947 VoEId(_instanceId,_channelId),
948 "Channel::Init() must call SetEngineInformation() first");
949 return -1;
950 }
951
952 // --- Add modules to process thread (for periodic schedulation)
953
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000954 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
955
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000956 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000957
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000958 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000959#ifdef WEBRTC_CODEC_AVT
960 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000961 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +0000962#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000963 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 {
965 _engineStatisticsPtr->SetLastError(
966 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
967 "Channel::Init() unable to initialize the ACM - 1");
968 return -1;
969 }
970
971 // --- RTP/RTCP module initialization
972
973 // Ensure that RTCP is enabled by default for the created channel.
974 // Note that, the module will keep generating RTCP until it is explicitly
975 // disabled by the user.
976 // After StopListen (when no sockets exists), RTCP packets will no longer
977 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000978 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
979 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000980 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
981 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000983 (audio_coding_->RegisterTransportCallback(this) == -1) ||
984 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000985
986 if (fail)
987 {
988 _engineStatisticsPtr->SetLastError(
989 VE_CANNOT_INIT_CHANNEL, kTraceError,
990 "Channel::Init() callbacks not registered");
991 return -1;
992 }
993
994 // --- Register all supported codecs to the receiving side of the
995 // RTP/RTCP module
996
997 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000998 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000999
1000 for (int idx = 0; idx < nSupportedCodecs; idx++)
1001 {
1002 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001003 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001004 (rtp_receiver_->RegisterReceivePayload(
1005 codec.plname,
1006 codec.pltype,
1007 codec.plfreq,
1008 codec.channels,
1009 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 {
1011 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1012 VoEId(_instanceId,_channelId),
1013 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1014 "to RTP/RTCP receiver",
1015 codec.plname, codec.pltype, codec.plfreq,
1016 codec.channels, codec.rate);
1017 }
1018 else
1019 {
1020 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1021 VoEId(_instanceId,_channelId),
1022 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1023 "the RTP/RTCP receiver",
1024 codec.plname, codec.pltype, codec.plfreq,
1025 codec.channels, codec.rate);
1026 }
1027
1028 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001029 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 {
1031 SetSendCodec(codec);
1032 }
1033
1034 // Register default PT for outband 'telephone-event'
1035 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1036 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001037 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001038 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 {
1040 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1041 VoEId(_instanceId,_channelId),
1042 "Channel::Init() failed to register outband "
1043 "'telephone-event' (%d/%d) correctly",
1044 codec.pltype, codec.plfreq);
1045 }
1046 }
1047
1048 if (!STR_CASE_CMP(codec.plname, "CN"))
1049 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001050 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1051 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001052 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 {
1054 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1055 VoEId(_instanceId,_channelId),
1056 "Channel::Init() failed to register CN (%d/%d) "
1057 "correctly - 1",
1058 codec.pltype, codec.plfreq);
1059 }
1060 }
1061#ifdef WEBRTC_CODEC_RED
1062 // Register RED to the receiving side of the ACM.
1063 // We will not receive an OnInitializeDecoder() callback for RED.
1064 if (!STR_CASE_CMP(codec.plname, "RED"))
1065 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001066 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 {
1068 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1069 VoEId(_instanceId,_channelId),
1070 "Channel::Init() failed to register RED (%d/%d) "
1071 "correctly",
1072 codec.pltype, codec.plfreq);
1073 }
1074 }
1075#endif
1076 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001077
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001078 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1079 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1080 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001081 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001082 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1083 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1084 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 }
1086
1087 return 0;
1088}
1089
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001090int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001091Channel::SetEngineInformation(Statistics& engineStatistics,
1092 OutputMixer& outputMixer,
1093 voe::TransmitMixer& transmitMixer,
1094 ProcessThread& moduleProcessThread,
1095 AudioDeviceModule& audioDeviceModule,
1096 VoiceEngineObserver* voiceEngineObserver,
1097 CriticalSectionWrapper* callbackCritSect)
1098{
1099 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1100 "Channel::SetEngineInformation()");
1101 _engineStatisticsPtr = &engineStatistics;
1102 _outputMixerPtr = &outputMixer;
1103 _transmitMixerPtr = &transmitMixer,
1104 _moduleProcessThreadPtr = &moduleProcessThread;
1105 _audioDeviceModulePtr = &audioDeviceModule;
1106 _voiceEngineObserverPtr = voiceEngineObserver;
1107 _callbackCritSectPtr = callbackCritSect;
1108 return 0;
1109}
1110
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001111int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001112Channel::UpdateLocalTimeStamp()
1113{
1114
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001115 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 return 0;
1117}
1118
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001119int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001120Channel::StartPlayout()
1121{
1122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1123 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001124 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001125 {
1126 return 0;
1127 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001128
1129 if (!_externalMixing) {
1130 // Add participant as candidates for mixing.
1131 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1132 {
1133 _engineStatisticsPtr->SetLastError(
1134 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1135 "StartPlayout() failed to add participant to mixer");
1136 return -1;
1137 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 }
1139
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001140 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001141 if (RegisterFilePlayingToMixer() != 0)
1142 return -1;
1143
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 return 0;
1145}
1146
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001147int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001148Channel::StopPlayout()
1149{
1150 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1151 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001152 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 {
1154 return 0;
1155 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001156
1157 if (!_externalMixing) {
1158 // Remove participant as candidates for mixing
1159 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1160 {
1161 _engineStatisticsPtr->SetLastError(
1162 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1163 "StopPlayout() failed to remove participant from mixer");
1164 return -1;
1165 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001166 }
1167
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001168 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 _outputAudioLevel.Clear();
1170
1171 return 0;
1172}
1173
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001174int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001175Channel::StartSend()
1176{
1177 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1178 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001179 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001180 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001181 if (send_sequence_number_)
1182 SetInitSequenceNumber(send_sequence_number_);
1183
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001184 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001186 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001189
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001190 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 {
1192 _engineStatisticsPtr->SetLastError(
1193 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1194 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001195 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001196 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001197 return -1;
1198 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001199
niklase@google.com470e71d2011-07-07 08:21:25 +00001200 return 0;
1201}
1202
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001203int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001204Channel::StopSend()
1205{
1206 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1207 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001208 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001210 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001212 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001213
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001214 // Store the sequence number to be able to pick up the same sequence for
1215 // the next StartSend(). This is needed for restarting device, otherwise
1216 // it might cause libSRTP to complain about packets being replayed.
1217 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1218 // CL is landed. See issue
1219 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1220 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1221
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 // Reset sending SSRC and sequence number and triggers direct transmission
1223 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001224 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1225 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 {
1227 _engineStatisticsPtr->SetLastError(
1228 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1229 "StartSend() RTP/RTCP failed to stop sending");
1230 }
1231
niklase@google.com470e71d2011-07-07 08:21:25 +00001232 return 0;
1233}
1234
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001235int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001236Channel::StartReceiving()
1237{
1238 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1239 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001240 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 {
1242 return 0;
1243 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001244 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001245 _numberOfDiscardedPackets = 0;
1246 return 0;
1247}
1248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001249int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001250Channel::StopReceiving()
1251{
1252 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1253 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001254 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 {
1256 return 0;
1257 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001258
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001259 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 return 0;
1261}
1262
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001263int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001264Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1265{
1266 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1267 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001268 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001269
1270 if (_voiceEngineObserverPtr)
1271 {
1272 _engineStatisticsPtr->SetLastError(
1273 VE_INVALID_OPERATION, kTraceError,
1274 "RegisterVoiceEngineObserver() observer already enabled");
1275 return -1;
1276 }
1277 _voiceEngineObserverPtr = &observer;
1278 return 0;
1279}
1280
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001281int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001282Channel::DeRegisterVoiceEngineObserver()
1283{
1284 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1285 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001286 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001287
1288 if (!_voiceEngineObserverPtr)
1289 {
1290 _engineStatisticsPtr->SetLastError(
1291 VE_INVALID_OPERATION, kTraceWarning,
1292 "DeRegisterVoiceEngineObserver() observer already disabled");
1293 return 0;
1294 }
1295 _voiceEngineObserverPtr = NULL;
1296 return 0;
1297}
1298
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001299int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001300Channel::GetSendCodec(CodecInst& codec)
1301{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001302 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001303}
1304
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001305int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001306Channel::GetRecCodec(CodecInst& codec)
1307{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001308 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001309}
1310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001312Channel::SetSendCodec(const CodecInst& codec)
1313{
1314 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1315 "Channel::SetSendCodec()");
1316
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001317 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 {
1319 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1320 "SetSendCodec() failed to register codec to ACM");
1321 return -1;
1322 }
1323
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001324 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001326 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1327 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 {
1329 WEBRTC_TRACE(
1330 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1331 "SetSendCodec() failed to register codec to"
1332 " RTP/RTCP module");
1333 return -1;
1334 }
1335 }
1336
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001337 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001338 {
1339 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "SetSendCodec() failed to set audio packet size");
1341 return -1;
1342 }
1343
1344 return 0;
1345}
1346
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001347void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001348 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001349 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1350
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001351 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001352 if (audio_coding_->SetPacketLossRate(
1353 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001354 assert(false); // This should not happen.
1355 }
1356}
1357
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001358int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001359Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1360{
1361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1362 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001363 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001364 // To disable VAD, DTX must be disabled too
1365 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001366 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 {
1368 _engineStatisticsPtr->SetLastError(
1369 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1370 "SetVADStatus() failed to set VAD");
1371 return -1;
1372 }
1373 return 0;
1374}
1375
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001376int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001377Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1378{
1379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1380 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001381 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001382 {
1383 _engineStatisticsPtr->SetLastError(
1384 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1385 "GetVADStatus() failed to get VAD status");
1386 return -1;
1387 }
1388 disabledDTX = !disabledDTX;
1389 return 0;
1390}
1391
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001392int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001393Channel::SetRecPayloadType(const CodecInst& codec)
1394{
1395 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1396 "Channel::SetRecPayloadType()");
1397
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001398 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001399 {
1400 _engineStatisticsPtr->SetLastError(
1401 VE_ALREADY_PLAYING, kTraceError,
1402 "SetRecPayloadType() unable to set PT while playing");
1403 return -1;
1404 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001405 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 {
1407 _engineStatisticsPtr->SetLastError(
1408 VE_ALREADY_LISTENING, kTraceError,
1409 "SetRecPayloadType() unable to set PT while listening");
1410 return -1;
1411 }
1412
1413 if (codec.pltype == -1)
1414 {
1415 // De-register the selected codec (RTP/RTCP module and ACM)
1416
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001417 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001418 CodecInst rxCodec = codec;
1419
1420 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001421 rtp_payload_registry_->ReceivePayloadType(
1422 rxCodec.plname,
1423 rxCodec.plfreq,
1424 rxCodec.channels,
1425 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1426 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001427 rxCodec.pltype = pltype;
1428
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001429 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 {
1431 _engineStatisticsPtr->SetLastError(
1432 VE_RTP_RTCP_MODULE_ERROR,
1433 kTraceError,
1434 "SetRecPayloadType() RTP/RTCP-module deregistration "
1435 "failed");
1436 return -1;
1437 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001438 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 {
1440 _engineStatisticsPtr->SetLastError(
1441 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1442 "SetRecPayloadType() ACM deregistration failed - 1");
1443 return -1;
1444 }
1445 return 0;
1446 }
1447
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001448 if (rtp_receiver_->RegisterReceivePayload(
1449 codec.plname,
1450 codec.pltype,
1451 codec.plfreq,
1452 codec.channels,
1453 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001454 {
1455 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001456 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1457 if (rtp_receiver_->RegisterReceivePayload(
1458 codec.plname,
1459 codec.pltype,
1460 codec.plfreq,
1461 codec.channels,
1462 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001463 {
1464 _engineStatisticsPtr->SetLastError(
1465 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1466 "SetRecPayloadType() RTP/RTCP-module registration failed");
1467 return -1;
1468 }
1469 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001470 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001471 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001472 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1473 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001474 {
1475 _engineStatisticsPtr->SetLastError(
1476 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1477 "SetRecPayloadType() ACM registration failed - 1");
1478 return -1;
1479 }
1480 }
1481 return 0;
1482}
1483
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001484int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001485Channel::GetRecPayloadType(CodecInst& codec)
1486{
1487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001489 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001490 if (rtp_payload_registry_->ReceivePayloadType(
1491 codec.plname,
1492 codec.plfreq,
1493 codec.channels,
1494 (codec.rate < 0) ? 0 : codec.rate,
1495 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001496 {
1497 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001498 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 "GetRecPayloadType() failed to retrieve RX payload type");
1500 return -1;
1501 }
1502 codec.pltype = payloadType;
1503 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001504 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001505 return 0;
1506}
1507
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001508int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001509Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1510{
1511 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1512 "Channel::SetSendCNPayloadType()");
1513
1514 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001515 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001516 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001517 if (frequency == kFreq32000Hz)
1518 samplingFreqHz = 32000;
1519 else if (frequency == kFreq16000Hz)
1520 samplingFreqHz = 16000;
1521
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001522 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001523 {
1524 _engineStatisticsPtr->SetLastError(
1525 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1526 "SetSendCNPayloadType() failed to retrieve default CN codec "
1527 "settings");
1528 return -1;
1529 }
1530
1531 // Modify the payload type (must be set to dynamic range)
1532 codec.pltype = type;
1533
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001534 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
1536 _engineStatisticsPtr->SetLastError(
1537 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1538 "SetSendCNPayloadType() failed to register CN to ACM");
1539 return -1;
1540 }
1541
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001542 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001543 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001544 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1545 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001546 {
1547 _engineStatisticsPtr->SetLastError(
1548 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1549 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1550 "module");
1551 return -1;
1552 }
1553 }
1554 return 0;
1555}
1556
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001557int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001559 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001560
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001561 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001562 _engineStatisticsPtr->SetLastError(
1563 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001564 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001565 return -1;
1566 }
1567 return 0;
1568}
1569
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001571{
1572 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1573 "Channel::RegisterExternalTransport()");
1574
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001575 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001576
niklase@google.com470e71d2011-07-07 08:21:25 +00001577 if (_externalTransport)
1578 {
1579 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1580 kTraceError,
1581 "RegisterExternalTransport() external transport already enabled");
1582 return -1;
1583 }
1584 _externalTransport = true;
1585 _transportPtr = &transport;
1586 return 0;
1587}
1588
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001589int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001590Channel::DeRegisterExternalTransport()
1591{
1592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1593 "Channel::DeRegisterExternalTransport()");
1594
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001595 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001596
niklase@google.com470e71d2011-07-07 08:21:25 +00001597 if (!_transportPtr)
1598 {
1599 _engineStatisticsPtr->SetLastError(
1600 VE_INVALID_OPERATION, kTraceWarning,
1601 "DeRegisterExternalTransport() external transport already "
1602 "disabled");
1603 return 0;
1604 }
1605 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 _transportPtr = NULL;
1607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1608 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001609 return 0;
1610}
1611
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001612int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001613 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001614 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1615 "Channel::ReceivedRTPPacket()");
1616
1617 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001618 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001619
1620 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001621 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1622 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001623 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1624 VoEId(_instanceId,_channelId),
1625 "Channel::SendPacket() RTP dump to input file failed");
1626 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001627 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001628 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001629 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1630 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1631 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001632 return -1;
1633 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001634 header.payload_type_frequency =
1635 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001636 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001637 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001638 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001639 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001640 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001641 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001642
1643 // Forward any packets to ViE bandwidth estimator, if enabled.
1644 {
1645 CriticalSectionScoped cs(&_callbackCritSect);
1646 if (vie_network_) {
1647 int64_t arrival_time_ms;
1648 if (packet_time.timestamp != -1) {
1649 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1650 } else {
1651 arrival_time_ms = TickTime::MillisecondTimestamp();
1652 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001653 size_t payload_length = length - header.headerLength;
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001654 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1655 payload_length, header);
1656 }
1657 }
1658
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001659 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001660}
1661
1662bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001663 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001664 const RTPHeader& header,
1665 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001666 if (rtp_payload_registry_->IsRtx(header)) {
1667 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001668 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001669 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001670 assert(packet_length >= header.headerLength);
1671 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001672 PayloadUnion payload_specific;
1673 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001674 &payload_specific)) {
1675 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001676 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001677 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1678 payload_specific, in_order);
1679}
1680
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001681bool Channel::HandleRtxPacket(const uint8_t* packet,
1682 size_t packet_length,
1683 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001684 if (!rtp_payload_registry_->IsRtx(header))
1685 return false;
1686
1687 // Remove the RTX header and parse the original RTP header.
1688 if (packet_length < header.headerLength)
1689 return false;
1690 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1691 return false;
1692 if (restored_packet_in_use_) {
1693 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1694 "Multiple RTX headers detected, dropping packet");
1695 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001696 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001697 uint8_t* restored_packet_ptr = restored_packet_;
1698 if (!rtp_payload_registry_->RestoreOriginalPacket(
1699 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1700 header)) {
1701 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1702 "Incoming RTX packet: invalid RTP header");
1703 return false;
1704 }
1705 restored_packet_in_use_ = true;
1706 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1707 restored_packet_in_use_ = false;
1708 return ret;
1709}
1710
1711bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1712 StreamStatistician* statistician =
1713 rtp_receive_statistics_->GetStatistician(header.ssrc);
1714 if (!statistician)
1715 return false;
1716 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001717}
1718
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001719bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1720 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001721 // Retransmissions are handled separately if RTX is enabled.
1722 if (rtp_payload_registry_->RtxEnabled())
1723 return false;
1724 StreamStatistician* statistician =
1725 rtp_receive_statistics_->GetStatistician(header.ssrc);
1726 if (!statistician)
1727 return false;
1728 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001729 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001730 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001731 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001732 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001733}
1734
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001735int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001736 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1737 "Channel::ReceivedRTCPPacket()");
1738 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001739 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001740
1741 // Dump the RTCP packet to a file (if RTP dump is enabled).
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001742 if (_rtpDumpIn.DumpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001743 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1744 VoEId(_instanceId,_channelId),
1745 "Channel::SendPacket() RTCP dump to input file failed");
1746 }
1747
1748 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001749 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001750 _engineStatisticsPtr->SetLastError(
1751 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1752 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1753 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001754
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001755 {
1756 CriticalSectionScoped lock(ts_stats_lock_.get());
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001757 int64_t rtt = GetRTT();
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001758 if (rtt == 0) {
1759 // Waiting for valid RTT.
1760 return 0;
1761 }
1762 uint32_t ntp_secs = 0;
1763 uint32_t ntp_frac = 0;
1764 uint32_t rtp_timestamp = 0;
1765 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1766 &rtp_timestamp)) {
1767 // Waiting for RTCP.
1768 return 0;
1769 }
1770 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001771 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001772 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001773}
1774
niklase@google.com470e71d2011-07-07 08:21:25 +00001775int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001776 bool loop,
1777 FileFormats format,
1778 int startPosition,
1779 float volumeScaling,
1780 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 const CodecInst* codecInst)
1782{
1783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1784 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1785 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1786 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1787 startPosition, stopPosition);
1788
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001789 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001790 {
1791 _engineStatisticsPtr->SetLastError(
1792 VE_ALREADY_PLAYING, kTraceError,
1793 "StartPlayingFileLocally() is already playing");
1794 return -1;
1795 }
1796
niklase@google.com470e71d2011-07-07 08:21:25 +00001797 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001798 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001799
1800 if (_outputFilePlayerPtr)
1801 {
1802 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1803 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1804 _outputFilePlayerPtr = NULL;
1805 }
1806
1807 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1808 _outputFilePlayerId, (const FileFormats)format);
1809
1810 if (_outputFilePlayerPtr == NULL)
1811 {
1812 _engineStatisticsPtr->SetLastError(
1813 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001814 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001815 return -1;
1816 }
1817
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001818 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001819
1820 if (_outputFilePlayerPtr->StartPlayingFile(
1821 fileName,
1822 loop,
1823 startPosition,
1824 volumeScaling,
1825 notificationTime,
1826 stopPosition,
1827 (const CodecInst*)codecInst) != 0)
1828 {
1829 _engineStatisticsPtr->SetLastError(
1830 VE_BAD_FILE, kTraceError,
1831 "StartPlayingFile() failed to start file playout");
1832 _outputFilePlayerPtr->StopPlayingFile();
1833 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1834 _outputFilePlayerPtr = NULL;
1835 return -1;
1836 }
1837 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001838 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001839 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001840
1841 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001842 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001843
1844 return 0;
1845}
1846
1847int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001848 FileFormats format,
1849 int startPosition,
1850 float volumeScaling,
1851 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001852 const CodecInst* codecInst)
1853{
1854 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1855 "Channel::StartPlayingFileLocally(format=%d,"
1856 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1857 format, volumeScaling, startPosition, stopPosition);
1858
1859 if(stream == NULL)
1860 {
1861 _engineStatisticsPtr->SetLastError(
1862 VE_BAD_FILE, kTraceError,
1863 "StartPlayingFileLocally() NULL as input stream");
1864 return -1;
1865 }
1866
1867
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001868 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001869 {
1870 _engineStatisticsPtr->SetLastError(
1871 VE_ALREADY_PLAYING, kTraceError,
1872 "StartPlayingFileLocally() is already playing");
1873 return -1;
1874 }
1875
niklase@google.com470e71d2011-07-07 08:21:25 +00001876 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001877 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001878
1879 // Destroy the old instance
1880 if (_outputFilePlayerPtr)
1881 {
1882 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1883 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1884 _outputFilePlayerPtr = NULL;
1885 }
1886
1887 // Create the instance
1888 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1889 _outputFilePlayerId,
1890 (const FileFormats)format);
1891
1892 if (_outputFilePlayerPtr == NULL)
1893 {
1894 _engineStatisticsPtr->SetLastError(
1895 VE_INVALID_ARGUMENT, kTraceError,
1896 "StartPlayingFileLocally() filePlayer format isnot correct");
1897 return -1;
1898 }
1899
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001900 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001901
1902 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1903 volumeScaling,
1904 notificationTime,
1905 stopPosition, codecInst) != 0)
1906 {
1907 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1908 "StartPlayingFile() failed to "
1909 "start file playout");
1910 _outputFilePlayerPtr->StopPlayingFile();
1911 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1912 _outputFilePlayerPtr = NULL;
1913 return -1;
1914 }
1915 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001916 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001917 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001918
1919 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001920 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001921
niklase@google.com470e71d2011-07-07 08:21:25 +00001922 return 0;
1923}
1924
1925int Channel::StopPlayingFileLocally()
1926{
1927 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1928 "Channel::StopPlayingFileLocally()");
1929
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001930 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001931 {
1932 _engineStatisticsPtr->SetLastError(
1933 VE_INVALID_OPERATION, kTraceWarning,
1934 "StopPlayingFileLocally() isnot playing");
1935 return 0;
1936 }
1937
niklase@google.com470e71d2011-07-07 08:21:25 +00001938 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001939 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001940
1941 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1942 {
1943 _engineStatisticsPtr->SetLastError(
1944 VE_STOP_RECORDING_FAILED, kTraceError,
1945 "StopPlayingFile() could not stop playing");
1946 return -1;
1947 }
1948 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1949 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1950 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001951 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001952 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001953 // _fileCritSect cannot be taken while calling
1954 // SetAnonymousMixibilityStatus. Refer to comments in
1955 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001956 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1957 {
1958 _engineStatisticsPtr->SetLastError(
1959 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001960 "StopPlayingFile() failed to stop participant from playing as"
1961 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001962 return -1;
1963 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001964
1965 return 0;
1966}
1967
1968int Channel::IsPlayingFileLocally() const
1969{
1970 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1971 "Channel::IsPlayingFileLocally()");
1972
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001973 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001974}
1975
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001976int Channel::RegisterFilePlayingToMixer()
1977{
1978 // Return success for not registering for file playing to mixer if:
1979 // 1. playing file before playout is started on that channel.
1980 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001981 if (!channel_state_.Get().playing ||
1982 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001983 {
1984 return 0;
1985 }
1986
1987 // |_fileCritSect| cannot be taken while calling
1988 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1989 // frames can be pulled by the mixer. Since the frames are generated from
1990 // the file, _fileCritSect will be taken. This would result in a deadlock.
1991 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1992 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001993 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001994 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001995 _engineStatisticsPtr->SetLastError(
1996 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1997 "StartPlayingFile() failed to add participant as file to mixer");
1998 _outputFilePlayerPtr->StopPlayingFile();
1999 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2000 _outputFilePlayerPtr = NULL;
2001 return -1;
2002 }
2003
2004 return 0;
2005}
2006
niklase@google.com470e71d2011-07-07 08:21:25 +00002007int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002008 bool loop,
2009 FileFormats format,
2010 int startPosition,
2011 float volumeScaling,
2012 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002013 const CodecInst* codecInst)
2014{
2015 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2016 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2017 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2018 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2019 startPosition, stopPosition);
2020
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002021 CriticalSectionScoped cs(&_fileCritSect);
2022
2023 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002024 {
2025 _engineStatisticsPtr->SetLastError(
2026 VE_ALREADY_PLAYING, kTraceWarning,
2027 "StartPlayingFileAsMicrophone() filePlayer is playing");
2028 return 0;
2029 }
2030
niklase@google.com470e71d2011-07-07 08:21:25 +00002031 // Destroy the old instance
2032 if (_inputFilePlayerPtr)
2033 {
2034 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2035 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2036 _inputFilePlayerPtr = NULL;
2037 }
2038
2039 // Create the instance
2040 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2041 _inputFilePlayerId, (const FileFormats)format);
2042
2043 if (_inputFilePlayerPtr == NULL)
2044 {
2045 _engineStatisticsPtr->SetLastError(
2046 VE_INVALID_ARGUMENT, kTraceError,
2047 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2048 return -1;
2049 }
2050
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002051 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002052
2053 if (_inputFilePlayerPtr->StartPlayingFile(
2054 fileName,
2055 loop,
2056 startPosition,
2057 volumeScaling,
2058 notificationTime,
2059 stopPosition,
2060 (const CodecInst*)codecInst) != 0)
2061 {
2062 _engineStatisticsPtr->SetLastError(
2063 VE_BAD_FILE, kTraceError,
2064 "StartPlayingFile() failed to start file playout");
2065 _inputFilePlayerPtr->StopPlayingFile();
2066 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2067 _inputFilePlayerPtr = NULL;
2068 return -1;
2069 }
2070 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002071 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002072
2073 return 0;
2074}
2075
2076int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002077 FileFormats format,
2078 int startPosition,
2079 float volumeScaling,
2080 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002081 const CodecInst* codecInst)
2082{
2083 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2084 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2085 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2086 format, volumeScaling, startPosition, stopPosition);
2087
2088 if(stream == NULL)
2089 {
2090 _engineStatisticsPtr->SetLastError(
2091 VE_BAD_FILE, kTraceError,
2092 "StartPlayingFileAsMicrophone NULL as input stream");
2093 return -1;
2094 }
2095
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002096 CriticalSectionScoped cs(&_fileCritSect);
2097
2098 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002099 {
2100 _engineStatisticsPtr->SetLastError(
2101 VE_ALREADY_PLAYING, kTraceWarning,
2102 "StartPlayingFileAsMicrophone() is playing");
2103 return 0;
2104 }
2105
niklase@google.com470e71d2011-07-07 08:21:25 +00002106 // Destroy the old instance
2107 if (_inputFilePlayerPtr)
2108 {
2109 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2110 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2111 _inputFilePlayerPtr = NULL;
2112 }
2113
2114 // Create the instance
2115 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2116 _inputFilePlayerId, (const FileFormats)format);
2117
2118 if (_inputFilePlayerPtr == NULL)
2119 {
2120 _engineStatisticsPtr->SetLastError(
2121 VE_INVALID_ARGUMENT, kTraceError,
2122 "StartPlayingInputFile() filePlayer format isnot correct");
2123 return -1;
2124 }
2125
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002126 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002127
2128 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2129 volumeScaling, notificationTime,
2130 stopPosition, codecInst) != 0)
2131 {
2132 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2133 "StartPlayingFile() failed to start "
2134 "file playout");
2135 _inputFilePlayerPtr->StopPlayingFile();
2136 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2137 _inputFilePlayerPtr = NULL;
2138 return -1;
2139 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002140
niklase@google.com470e71d2011-07-07 08:21:25 +00002141 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002142 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002143
2144 return 0;
2145}
2146
2147int Channel::StopPlayingFileAsMicrophone()
2148{
2149 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2150 "Channel::StopPlayingFileAsMicrophone()");
2151
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002152 CriticalSectionScoped cs(&_fileCritSect);
2153
2154 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002155 {
2156 _engineStatisticsPtr->SetLastError(
2157 VE_INVALID_OPERATION, kTraceWarning,
2158 "StopPlayingFileAsMicrophone() isnot playing");
2159 return 0;
2160 }
2161
niklase@google.com470e71d2011-07-07 08:21:25 +00002162 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2163 {
2164 _engineStatisticsPtr->SetLastError(
2165 VE_STOP_RECORDING_FAILED, kTraceError,
2166 "StopPlayingFile() could not stop playing");
2167 return -1;
2168 }
2169 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2170 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2171 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002172 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002173
2174 return 0;
2175}
2176
2177int Channel::IsPlayingFileAsMicrophone() const
2178{
2179 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2180 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002181 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002182}
2183
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002184int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002185 const CodecInst* codecInst)
2186{
2187 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2188 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2189
2190 if (_outputFileRecording)
2191 {
2192 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2193 "StartRecordingPlayout() is already recording");
2194 return 0;
2195 }
2196
2197 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002198 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002199 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2200
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002201 if ((codecInst != NULL) &&
2202 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002203 {
2204 _engineStatisticsPtr->SetLastError(
2205 VE_BAD_ARGUMENT, kTraceError,
2206 "StartRecordingPlayout() invalid compression");
2207 return(-1);
2208 }
2209 if(codecInst == NULL)
2210 {
2211 format = kFileFormatPcm16kHzFile;
2212 codecInst=&dummyCodec;
2213 }
2214 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2215 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2216 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2217 {
2218 format = kFileFormatWavFile;
2219 }
2220 else
2221 {
2222 format = kFileFormatCompressedFile;
2223 }
2224
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002225 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002226
2227 // Destroy the old instance
2228 if (_outputFileRecorderPtr)
2229 {
2230 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2231 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2232 _outputFileRecorderPtr = NULL;
2233 }
2234
2235 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2236 _outputFileRecorderId, (const FileFormats)format);
2237 if (_outputFileRecorderPtr == NULL)
2238 {
2239 _engineStatisticsPtr->SetLastError(
2240 VE_INVALID_ARGUMENT, kTraceError,
2241 "StartRecordingPlayout() fileRecorder format isnot correct");
2242 return -1;
2243 }
2244
2245 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2246 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2247 {
2248 _engineStatisticsPtr->SetLastError(
2249 VE_BAD_FILE, kTraceError,
2250 "StartRecordingAudioFile() failed to start file recording");
2251 _outputFileRecorderPtr->StopRecording();
2252 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2253 _outputFileRecorderPtr = NULL;
2254 return -1;
2255 }
2256 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2257 _outputFileRecording = true;
2258
2259 return 0;
2260}
2261
2262int Channel::StartRecordingPlayout(OutStream* stream,
2263 const CodecInst* codecInst)
2264{
2265 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2266 "Channel::StartRecordingPlayout()");
2267
2268 if (_outputFileRecording)
2269 {
2270 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2271 "StartRecordingPlayout() is already recording");
2272 return 0;
2273 }
2274
2275 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002276 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002277 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2278
2279 if (codecInst != NULL && codecInst->channels != 1)
2280 {
2281 _engineStatisticsPtr->SetLastError(
2282 VE_BAD_ARGUMENT, kTraceError,
2283 "StartRecordingPlayout() invalid compression");
2284 return(-1);
2285 }
2286 if(codecInst == NULL)
2287 {
2288 format = kFileFormatPcm16kHzFile;
2289 codecInst=&dummyCodec;
2290 }
2291 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2292 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2293 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2294 {
2295 format = kFileFormatWavFile;
2296 }
2297 else
2298 {
2299 format = kFileFormatCompressedFile;
2300 }
2301
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002302 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002303
2304 // Destroy the old instance
2305 if (_outputFileRecorderPtr)
2306 {
2307 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2308 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2309 _outputFileRecorderPtr = NULL;
2310 }
2311
2312 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2313 _outputFileRecorderId, (const FileFormats)format);
2314 if (_outputFileRecorderPtr == NULL)
2315 {
2316 _engineStatisticsPtr->SetLastError(
2317 VE_INVALID_ARGUMENT, kTraceError,
2318 "StartRecordingPlayout() fileRecorder format isnot correct");
2319 return -1;
2320 }
2321
2322 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2323 notificationTime) != 0)
2324 {
2325 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2326 "StartRecordingPlayout() failed to "
2327 "start file recording");
2328 _outputFileRecorderPtr->StopRecording();
2329 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2330 _outputFileRecorderPtr = NULL;
2331 return -1;
2332 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002333
niklase@google.com470e71d2011-07-07 08:21:25 +00002334 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2335 _outputFileRecording = true;
2336
2337 return 0;
2338}
2339
2340int Channel::StopRecordingPlayout()
2341{
2342 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2343 "Channel::StopRecordingPlayout()");
2344
2345 if (!_outputFileRecording)
2346 {
2347 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2348 "StopRecordingPlayout() isnot recording");
2349 return -1;
2350 }
2351
2352
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002353 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002354
2355 if (_outputFileRecorderPtr->StopRecording() != 0)
2356 {
2357 _engineStatisticsPtr->SetLastError(
2358 VE_STOP_RECORDING_FAILED, kTraceError,
2359 "StopRecording() could not stop recording");
2360 return(-1);
2361 }
2362 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2363 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2364 _outputFileRecorderPtr = NULL;
2365 _outputFileRecording = false;
2366
2367 return 0;
2368}
2369
2370void
2371Channel::SetMixWithMicStatus(bool mix)
2372{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002373 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002374 _mixFileWithMicrophone=mix;
2375}
2376
2377int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002378Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002379{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002380 int8_t currentLevel = _outputAudioLevel.Level();
2381 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002382 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2383 VoEId(_instanceId,_channelId),
2384 "GetSpeechOutputLevel() => level=%u", level);
2385 return 0;
2386}
2387
2388int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002389Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002390{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002391 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2392 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002393 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2394 VoEId(_instanceId,_channelId),
2395 "GetSpeechOutputLevelFullRange() => level=%u", level);
2396 return 0;
2397}
2398
2399int
2400Channel::SetMute(bool enable)
2401{
wu@webrtc.org63420662013-10-17 18:28:55 +00002402 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2404 "Channel::SetMute(enable=%d)", enable);
2405 _mute = enable;
2406 return 0;
2407}
2408
2409bool
2410Channel::Mute() const
2411{
wu@webrtc.org63420662013-10-17 18:28:55 +00002412 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002413 return _mute;
2414}
2415
2416int
2417Channel::SetOutputVolumePan(float left, float right)
2418{
wu@webrtc.org63420662013-10-17 18:28:55 +00002419 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002420 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2421 "Channel::SetOutputVolumePan()");
2422 _panLeft = left;
2423 _panRight = right;
2424 return 0;
2425}
2426
2427int
2428Channel::GetOutputVolumePan(float& left, float& right) const
2429{
wu@webrtc.org63420662013-10-17 18:28:55 +00002430 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002431 left = _panLeft;
2432 right = _panRight;
2433 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2434 VoEId(_instanceId,_channelId),
2435 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2436 return 0;
2437}
2438
2439int
2440Channel::SetChannelOutputVolumeScaling(float scaling)
2441{
wu@webrtc.org63420662013-10-17 18:28:55 +00002442 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002443 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2444 "Channel::SetChannelOutputVolumeScaling()");
2445 _outputGain = scaling;
2446 return 0;
2447}
2448
2449int
2450Channel::GetChannelOutputVolumeScaling(float& scaling) const
2451{
wu@webrtc.org63420662013-10-17 18:28:55 +00002452 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002453 scaling = _outputGain;
2454 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2455 VoEId(_instanceId,_channelId),
2456 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2457 return 0;
2458}
2459
niklase@google.com470e71d2011-07-07 08:21:25 +00002460int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002461 int lengthMs, int attenuationDb,
2462 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002463{
2464 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2465 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2466 playDtmfEvent);
2467
2468 _playOutbandDtmfEvent = playDtmfEvent;
2469
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002470 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002471 attenuationDb) != 0)
2472 {
2473 _engineStatisticsPtr->SetLastError(
2474 VE_SEND_DTMF_FAILED,
2475 kTraceWarning,
2476 "SendTelephoneEventOutband() failed to send event");
2477 return -1;
2478 }
2479 return 0;
2480}
2481
2482int Channel::SendTelephoneEventInband(unsigned char eventCode,
2483 int lengthMs,
2484 int attenuationDb,
2485 bool playDtmfEvent)
2486{
2487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2488 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2489 playDtmfEvent);
2490
2491 _playInbandDtmfEvent = playDtmfEvent;
2492 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2493
2494 return 0;
2495}
2496
2497int
niklase@google.com470e71d2011-07-07 08:21:25 +00002498Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2499{
2500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2501 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002502 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002503 {
2504 _engineStatisticsPtr->SetLastError(
2505 VE_INVALID_ARGUMENT, kTraceError,
2506 "SetSendTelephoneEventPayloadType() invalid type");
2507 return -1;
2508 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002509 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002510 codec.plfreq = 8000;
2511 codec.pltype = type;
2512 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002513 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002514 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002515 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2516 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2517 _engineStatisticsPtr->SetLastError(
2518 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2519 "SetSendTelephoneEventPayloadType() failed to register send"
2520 "payload type");
2521 return -1;
2522 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002523 }
2524 _sendTelephoneEventPayloadType = type;
2525 return 0;
2526}
2527
2528int
2529Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2530{
2531 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2532 "Channel::GetSendTelephoneEventPayloadType()");
2533 type = _sendTelephoneEventPayloadType;
2534 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2535 VoEId(_instanceId,_channelId),
2536 "GetSendTelephoneEventPayloadType() => type=%u", type);
2537 return 0;
2538}
2539
niklase@google.com470e71d2011-07-07 08:21:25 +00002540int
2541Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2542{
2543 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2544 "Channel::UpdateRxVadDetection()");
2545
2546 int vadDecision = 1;
2547
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002548 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002549
2550 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2551 {
2552 OnRxVadDetected(vadDecision);
2553 _oldVadDecision = vadDecision;
2554 }
2555
2556 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2557 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2558 vadDecision);
2559 return 0;
2560}
2561
2562int
2563Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2564{
2565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2566 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002567 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002568
2569 if (_rxVadObserverPtr)
2570 {
2571 _engineStatisticsPtr->SetLastError(
2572 VE_INVALID_OPERATION, kTraceError,
2573 "RegisterRxVadObserver() observer already enabled");
2574 return -1;
2575 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002576 _rxVadObserverPtr = &observer;
2577 _RxVadDetection = true;
2578 return 0;
2579}
2580
2581int
2582Channel::DeRegisterRxVadObserver()
2583{
2584 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2585 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002586 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002587
2588 if (!_rxVadObserverPtr)
2589 {
2590 _engineStatisticsPtr->SetLastError(
2591 VE_INVALID_OPERATION, kTraceWarning,
2592 "DeRegisterRxVadObserver() observer already disabled");
2593 return 0;
2594 }
2595 _rxVadObserverPtr = NULL;
2596 _RxVadDetection = false;
2597 return 0;
2598}
2599
2600int
2601Channel::VoiceActivityIndicator(int &activity)
2602{
2603 activity = _sendFrameType;
2604
2605 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002606 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002607 return 0;
2608}
2609
2610#ifdef WEBRTC_VOICE_ENGINE_AGC
2611
2612int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002613Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002614{
2615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2616 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2617 (int)enable, (int)mode);
2618
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002619 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002620 switch (mode)
2621 {
2622 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002623 break;
2624 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002625 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002626 break;
2627 case kAgcFixedDigital:
2628 agcMode = GainControl::kFixedDigital;
2629 break;
2630 case kAgcAdaptiveDigital:
2631 agcMode =GainControl::kAdaptiveDigital;
2632 break;
2633 default:
2634 _engineStatisticsPtr->SetLastError(
2635 VE_INVALID_ARGUMENT, kTraceError,
2636 "SetRxAgcStatus() invalid Agc mode");
2637 return -1;
2638 }
2639
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002640 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002641 {
2642 _engineStatisticsPtr->SetLastError(
2643 VE_APM_ERROR, kTraceError,
2644 "SetRxAgcStatus() failed to set Agc mode");
2645 return -1;
2646 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002647 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002648 {
2649 _engineStatisticsPtr->SetLastError(
2650 VE_APM_ERROR, kTraceError,
2651 "SetRxAgcStatus() failed to set Agc state");
2652 return -1;
2653 }
2654
2655 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002656 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002657
2658 return 0;
2659}
2660
2661int
2662Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2663{
2664 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2665 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2666
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002667 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002668 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002669 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002670
2671 enabled = enable;
2672
2673 switch (agcMode)
2674 {
2675 case GainControl::kFixedDigital:
2676 mode = kAgcFixedDigital;
2677 break;
2678 case GainControl::kAdaptiveDigital:
2679 mode = kAgcAdaptiveDigital;
2680 break;
2681 default:
2682 _engineStatisticsPtr->SetLastError(
2683 VE_APM_ERROR, kTraceError,
2684 "GetRxAgcStatus() invalid Agc mode");
2685 return -1;
2686 }
2687
2688 return 0;
2689}
2690
2691int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002692Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002693{
2694 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2695 "Channel::SetRxAgcConfig()");
2696
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002697 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002698 config.targetLeveldBOv) != 0)
2699 {
2700 _engineStatisticsPtr->SetLastError(
2701 VE_APM_ERROR, kTraceError,
2702 "SetRxAgcConfig() failed to set target peak |level|"
2703 "(or envelope) of the Agc");
2704 return -1;
2705 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002706 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002707 config.digitalCompressionGaindB) != 0)
2708 {
2709 _engineStatisticsPtr->SetLastError(
2710 VE_APM_ERROR, kTraceError,
2711 "SetRxAgcConfig() failed to set the range in |gain| the"
2712 " digital compression stage may apply");
2713 return -1;
2714 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002715 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002716 config.limiterEnable) != 0)
2717 {
2718 _engineStatisticsPtr->SetLastError(
2719 VE_APM_ERROR, kTraceError,
2720 "SetRxAgcConfig() failed to set hard limiter to the signal");
2721 return -1;
2722 }
2723
2724 return 0;
2725}
2726
2727int
2728Channel::GetRxAgcConfig(AgcConfig& config)
2729{
2730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2731 "Channel::GetRxAgcConfig(config=%?)");
2732
2733 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002734 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002735 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002736 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002737 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002738 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002739
2740 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2741 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2742 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2743 " limiterEnable=%d",
2744 config.targetLeveldBOv,
2745 config.digitalCompressionGaindB,
2746 config.limiterEnable);
2747
2748 return 0;
2749}
2750
2751#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2752
2753#ifdef WEBRTC_VOICE_ENGINE_NR
2754
2755int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002756Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002757{
2758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2759 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2760 (int)enable, (int)mode);
2761
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002762 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002763 switch (mode)
2764 {
2765
2766 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002767 break;
2768 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002769 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002770 break;
2771 case kNsConference:
2772 nsLevel = NoiseSuppression::kHigh;
2773 break;
2774 case kNsLowSuppression:
2775 nsLevel = NoiseSuppression::kLow;
2776 break;
2777 case kNsModerateSuppression:
2778 nsLevel = NoiseSuppression::kModerate;
2779 break;
2780 case kNsHighSuppression:
2781 nsLevel = NoiseSuppression::kHigh;
2782 break;
2783 case kNsVeryHighSuppression:
2784 nsLevel = NoiseSuppression::kVeryHigh;
2785 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002786 }
2787
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002788 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002789 != 0)
2790 {
2791 _engineStatisticsPtr->SetLastError(
2792 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002793 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002794 return -1;
2795 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002796 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002800 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002801 return -1;
2802 }
2803
2804 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002805 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002806
2807 return 0;
2808}
2809
2810int
2811Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2812{
2813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2814 "Channel::GetRxNsStatus(enable=?, mode=?)");
2815
2816 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002817 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002818 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002819 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002820
2821 enabled = enable;
2822
2823 switch (ncLevel)
2824 {
2825 case NoiseSuppression::kLow:
2826 mode = kNsLowSuppression;
2827 break;
2828 case NoiseSuppression::kModerate:
2829 mode = kNsModerateSuppression;
2830 break;
2831 case NoiseSuppression::kHigh:
2832 mode = kNsHighSuppression;
2833 break;
2834 case NoiseSuppression::kVeryHigh:
2835 mode = kNsVeryHighSuppression;
2836 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002837 }
2838
2839 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2840 VoEId(_instanceId,_channelId),
2841 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2842 return 0;
2843}
2844
2845#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2846
2847int
niklase@google.com470e71d2011-07-07 08:21:25 +00002848Channel::SetLocalSSRC(unsigned int ssrc)
2849{
2850 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2851 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002852 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002853 {
2854 _engineStatisticsPtr->SetLastError(
2855 VE_ALREADY_SENDING, kTraceError,
2856 "SetLocalSSRC() already sending");
2857 return -1;
2858 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002859 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002860 return 0;
2861}
2862
2863int
2864Channel::GetLocalSSRC(unsigned int& ssrc)
2865{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002866 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002867 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2868 VoEId(_instanceId,_channelId),
2869 "GetLocalSSRC() => ssrc=%lu", ssrc);
2870 return 0;
2871}
2872
2873int
2874Channel::GetRemoteSSRC(unsigned int& ssrc)
2875{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002876 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002877 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2878 VoEId(_instanceId,_channelId),
2879 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2880 return 0;
2881}
2882
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002883int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002884 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002885 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002886}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002887
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002888int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2889 unsigned char id) {
2890 rtp_header_parser_->DeregisterRtpHeaderExtension(
2891 kRtpExtensionAudioLevel);
2892 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2893 kRtpExtensionAudioLevel, id)) {
2894 return -1;
2895 }
2896 return 0;
2897}
2898
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002899int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2900 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2901}
2902
2903int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2904 rtp_header_parser_->DeregisterRtpHeaderExtension(
2905 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002906 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2907 kRtpExtensionAbsoluteSendTime, id)) {
2908 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002909 }
2910 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002911}
2912
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002913void Channel::SetRTCPStatus(bool enable) {
2914 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2915 "Channel::SetRTCPStatus()");
2916 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002917}
2918
2919int
2920Channel::GetRTCPStatus(bool& enabled)
2921{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002922 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002923 enabled = (method != kRtcpOff);
2924 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2925 VoEId(_instanceId,_channelId),
2926 "GetRTCPStatus() => enabled=%d", enabled);
2927 return 0;
2928}
2929
2930int
2931Channel::SetRTCP_CNAME(const char cName[256])
2932{
2933 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2934 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002935 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002936 {
2937 _engineStatisticsPtr->SetLastError(
2938 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2939 "SetRTCP_CNAME() failed to set RTCP CNAME");
2940 return -1;
2941 }
2942 return 0;
2943}
2944
2945int
niklase@google.com470e71d2011-07-07 08:21:25 +00002946Channel::GetRemoteRTCP_CNAME(char cName[256])
2947{
2948 if (cName == NULL)
2949 {
2950 _engineStatisticsPtr->SetLastError(
2951 VE_INVALID_ARGUMENT, kTraceError,
2952 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2953 return -1;
2954 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002955 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002956 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002957 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002958 {
2959 _engineStatisticsPtr->SetLastError(
2960 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2961 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2962 return -1;
2963 }
2964 strcpy(cName, cname);
2965 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2966 VoEId(_instanceId, _channelId),
2967 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2968 return 0;
2969}
2970
2971int
2972Channel::GetRemoteRTCPData(
2973 unsigned int& NTPHigh,
2974 unsigned int& NTPLow,
2975 unsigned int& timestamp,
2976 unsigned int& playoutTimestamp,
2977 unsigned int* jitter,
2978 unsigned short* fractionLost)
2979{
2980 // --- Information from sender info in received Sender Reports
2981
2982 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002983 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002984 {
2985 _engineStatisticsPtr->SetLastError(
2986 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002987 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002988 "side");
2989 return -1;
2990 }
2991
2992 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2993 // and octet count)
2994 NTPHigh = senderInfo.NTPseconds;
2995 NTPLow = senderInfo.NTPfraction;
2996 timestamp = senderInfo.RTPtimeStamp;
2997
2998 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2999 VoEId(_instanceId, _channelId),
3000 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3001 "timestamp=%lu",
3002 NTPHigh, NTPLow, timestamp);
3003
3004 // --- Locally derived information
3005
3006 // This value is updated on each incoming RTCP packet (0 when no packet
3007 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003008 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003009
3010 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3011 VoEId(_instanceId, _channelId),
3012 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003013 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003014
3015 if (NULL != jitter || NULL != fractionLost)
3016 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003017 // Get all RTCP receiver report blocks that have been received on this
3018 // channel. If we receive RTP packets from a remote source we know the
3019 // remote SSRC and use the report block from him.
3020 // Otherwise use the first report block.
3021 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003022 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003023 remote_stats.empty()) {
3024 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3025 VoEId(_instanceId, _channelId),
3026 "GetRemoteRTCPData() failed to measure statistics due"
3027 " to lack of received RTP and/or RTCP packets");
3028 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003029 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003030
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003031 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003032 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3033 for (; it != remote_stats.end(); ++it) {
3034 if (it->remoteSSRC == remoteSSRC)
3035 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003036 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003037
3038 if (it == remote_stats.end()) {
3039 // If we have not received any RTCP packets from this SSRC it probably
3040 // means that we have not received any RTP packets.
3041 // Use the first received report block instead.
3042 it = remote_stats.begin();
3043 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003044 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003045
xians@webrtc.org79af7342012-01-31 12:22:14 +00003046 if (jitter) {
3047 *jitter = it->jitter;
3048 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3049 VoEId(_instanceId, _channelId),
3050 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3051 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003052
xians@webrtc.org79af7342012-01-31 12:22:14 +00003053 if (fractionLost) {
3054 *fractionLost = it->fractionLost;
3055 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3056 VoEId(_instanceId, _channelId),
3057 "GetRemoteRTCPData() => fractionLost = %lu",
3058 *fractionLost);
3059 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003060 }
3061 return 0;
3062}
3063
3064int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003065Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003066 unsigned int name,
3067 const char* data,
3068 unsigned short dataLengthInBytes)
3069{
3070 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3071 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003072 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003073 {
3074 _engineStatisticsPtr->SetLastError(
3075 VE_NOT_SENDING, kTraceError,
3076 "SendApplicationDefinedRTCPPacket() not sending");
3077 return -1;
3078 }
3079 if (NULL == data)
3080 {
3081 _engineStatisticsPtr->SetLastError(
3082 VE_INVALID_ARGUMENT, kTraceError,
3083 "SendApplicationDefinedRTCPPacket() invalid data value");
3084 return -1;
3085 }
3086 if (dataLengthInBytes % 4 != 0)
3087 {
3088 _engineStatisticsPtr->SetLastError(
3089 VE_INVALID_ARGUMENT, kTraceError,
3090 "SendApplicationDefinedRTCPPacket() invalid length value");
3091 return -1;
3092 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003093 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003094 if (status == kRtcpOff)
3095 {
3096 _engineStatisticsPtr->SetLastError(
3097 VE_RTCP_ERROR, kTraceError,
3098 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3099 return -1;
3100 }
3101
3102 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003103 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003104 subType,
3105 name,
3106 (const unsigned char*) data,
3107 dataLengthInBytes) != 0)
3108 {
3109 _engineStatisticsPtr->SetLastError(
3110 VE_SEND_ERROR, kTraceError,
3111 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3112 return -1;
3113 }
3114 return 0;
3115}
3116
3117int
3118Channel::GetRTPStatistics(
3119 unsigned int& averageJitterMs,
3120 unsigned int& maxJitterMs,
3121 unsigned int& discardedPackets)
3122{
niklase@google.com470e71d2011-07-07 08:21:25 +00003123 // The jitter statistics is updated for each received RTP packet and is
3124 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003125 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3126 // If RTCP is off, there is no timed thread in the RTCP module regularly
3127 // generating new stats, trigger the update manually here instead.
3128 StreamStatistician* statistician =
3129 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3130 if (statistician) {
3131 // Don't use returned statistics, use data from proxy instead so that
3132 // max jitter can be fetched atomically.
3133 RtcpStatistics s;
3134 statistician->GetStatistics(&s, true);
3135 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003136 }
3137
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003138 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003139 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003140 if (playoutFrequency > 0) {
3141 // Scale RTP statistics given the current playout frequency
3142 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3143 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003144 }
3145
3146 discardedPackets = _numberOfDiscardedPackets;
3147
3148 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3149 VoEId(_instanceId, _channelId),
3150 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003151 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003152 averageJitterMs, maxJitterMs, discardedPackets);
3153 return 0;
3154}
3155
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003156int Channel::GetRemoteRTCPReportBlocks(
3157 std::vector<ReportBlock>* report_blocks) {
3158 if (report_blocks == NULL) {
3159 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3160 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3161 return -1;
3162 }
3163
3164 // Get the report blocks from the latest received RTCP Sender or Receiver
3165 // Report. Each element in the vector contains the sender's SSRC and a
3166 // report block according to RFC 3550.
3167 std::vector<RTCPReportBlock> rtcp_report_blocks;
3168 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3169 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3170 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3171 return -1;
3172 }
3173
3174 if (rtcp_report_blocks.empty())
3175 return 0;
3176
3177 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3178 for (; it != rtcp_report_blocks.end(); ++it) {
3179 ReportBlock report_block;
3180 report_block.sender_SSRC = it->remoteSSRC;
3181 report_block.source_SSRC = it->sourceSSRC;
3182 report_block.fraction_lost = it->fractionLost;
3183 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3184 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3185 report_block.interarrival_jitter = it->jitter;
3186 report_block.last_SR_timestamp = it->lastSR;
3187 report_block.delay_since_last_SR = it->delaySinceLastSR;
3188 report_blocks->push_back(report_block);
3189 }
3190 return 0;
3191}
3192
niklase@google.com470e71d2011-07-07 08:21:25 +00003193int
3194Channel::GetRTPStatistics(CallStatistics& stats)
3195{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003196 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003197
3198 // The jitter statistics is updated for each received RTP packet and is
3199 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003200 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003201 StreamStatistician* statistician =
3202 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3203 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003204 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3205 _engineStatisticsPtr->SetLastError(
3206 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3207 "GetRTPStatistics() failed to read RTP statistics from the "
3208 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003209 }
3210
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003211 stats.fractionLost = statistics.fraction_lost;
3212 stats.cumulativeLost = statistics.cumulative_lost;
3213 stats.extendedMax = statistics.extended_max_sequence_number;
3214 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003215
3216 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3217 VoEId(_instanceId, _channelId),
3218 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003219 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003220 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3221 stats.jitterSamples);
3222
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003223 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003224 stats.rttMs = GetRTT();
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003225 if (stats.rttMs == 0) {
3226 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3227 "GetRTPStatistics() failed to get RTT");
3228 } else {
3229 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003230 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003231 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003232
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003233 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003234
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003235 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003236 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003237 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003238 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003239
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003240 if (statistician) {
3241 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3242 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003243
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003244 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003245 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003246 {
3247 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3248 VoEId(_instanceId, _channelId),
3249 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003250 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003251 }
3252
3253 stats.bytesSent = bytesSent;
3254 stats.packetsSent = packetsSent;
3255 stats.bytesReceived = bytesReceived;
3256 stats.packetsReceived = packetsReceived;
3257
3258 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3259 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003260 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3261 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003262 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3263 stats.packetsReceived);
3264
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003265 // --- Timestamps
3266 {
3267 CriticalSectionScoped lock(ts_stats_lock_.get());
3268 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3269 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 return 0;
3271}
3272
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003273int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003274 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003275 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003276
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003277 if (enable) {
3278 if (redPayloadtype < 0 || redPayloadtype > 127) {
3279 _engineStatisticsPtr->SetLastError(
3280 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003281 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003282 return -1;
3283 }
3284
3285 if (SetRedPayloadType(redPayloadtype) < 0) {
3286 _engineStatisticsPtr->SetLastError(
3287 VE_CODEC_ERROR, kTraceError,
3288 "SetSecondarySendCodec() Failed to register RED ACM");
3289 return -1;
3290 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003291 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003292
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003293 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003294 _engineStatisticsPtr->SetLastError(
3295 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003296 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003297 return -1;
3298 }
3299 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003300}
3301
3302int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003303Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003304{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003305 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003306 if (enabled)
3307 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003308 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003309 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003310 {
3311 _engineStatisticsPtr->SetLastError(
3312 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003313 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003314 "module");
3315 return -1;
3316 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003317 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003318 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3319 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003320 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003321 enabled, redPayloadtype);
3322 return 0;
3323 }
3324 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3325 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003326 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003327 return 0;
3328}
3329
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003330int Channel::SetCodecFECStatus(bool enable) {
3331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3332 "Channel::SetCodecFECStatus()");
3333
3334 if (audio_coding_->SetCodecFEC(enable) != 0) {
3335 _engineStatisticsPtr->SetLastError(
3336 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3337 "SetCodecFECStatus() failed to set FEC state");
3338 return -1;
3339 }
3340 return 0;
3341}
3342
3343bool Channel::GetCodecFECStatus() {
3344 bool enabled = audio_coding_->CodecFEC();
3345 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3346 VoEId(_instanceId, _channelId),
3347 "GetCodecFECStatus() => enabled=%d", enabled);
3348 return enabled;
3349}
3350
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003351void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3352 // None of these functions can fail.
3353 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003354 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3355 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003356 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003357 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003358 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003359 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003360}
3361
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003362// Called when we are missing one or more packets.
3363int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003364 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3365}
3366
niklase@google.com470e71d2011-07-07 08:21:25 +00003367int
niklase@google.com470e71d2011-07-07 08:21:25 +00003368Channel::StartRTPDump(const char fileNameUTF8[1024],
3369 RTPDirections direction)
3370{
3371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3372 "Channel::StartRTPDump()");
3373 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3374 {
3375 _engineStatisticsPtr->SetLastError(
3376 VE_INVALID_ARGUMENT, kTraceError,
3377 "StartRTPDump() invalid RTP direction");
3378 return -1;
3379 }
3380 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3381 &_rtpDumpIn : &_rtpDumpOut;
3382 if (rtpDumpPtr == NULL)
3383 {
3384 assert(false);
3385 return -1;
3386 }
3387 if (rtpDumpPtr->IsActive())
3388 {
3389 rtpDumpPtr->Stop();
3390 }
3391 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3392 {
3393 _engineStatisticsPtr->SetLastError(
3394 VE_BAD_FILE, kTraceError,
3395 "StartRTPDump() failed to create file");
3396 return -1;
3397 }
3398 return 0;
3399}
3400
3401int
3402Channel::StopRTPDump(RTPDirections direction)
3403{
3404 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3405 "Channel::StopRTPDump()");
3406 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3407 {
3408 _engineStatisticsPtr->SetLastError(
3409 VE_INVALID_ARGUMENT, kTraceError,
3410 "StopRTPDump() invalid RTP direction");
3411 return -1;
3412 }
3413 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3414 &_rtpDumpIn : &_rtpDumpOut;
3415 if (rtpDumpPtr == NULL)
3416 {
3417 assert(false);
3418 return -1;
3419 }
3420 if (!rtpDumpPtr->IsActive())
3421 {
3422 return 0;
3423 }
3424 return rtpDumpPtr->Stop();
3425}
3426
3427bool
3428Channel::RTPDumpIsActive(RTPDirections direction)
3429{
3430 if ((direction != kRtpIncoming) &&
3431 (direction != kRtpOutgoing))
3432 {
3433 _engineStatisticsPtr->SetLastError(
3434 VE_INVALID_ARGUMENT, kTraceError,
3435 "RTPDumpIsActive() invalid RTP direction");
3436 return false;
3437 }
3438 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3439 &_rtpDumpIn : &_rtpDumpOut;
3440 return rtpDumpPtr->IsActive();
3441}
3442
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003443void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3444 int video_channel) {
3445 CriticalSectionScoped cs(&_callbackCritSect);
3446 if (vie_network_) {
3447 vie_network_->Release();
3448 vie_network_ = NULL;
3449 }
3450 video_channel_ = -1;
3451
3452 if (vie_network != NULL && video_channel != -1) {
3453 vie_network_ = vie_network;
3454 video_channel_ = video_channel;
3455 }
3456}
3457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003458uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003459Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003460{
3461 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003462 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003463 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003464 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003465 return 0;
3466}
3467
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003468void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003469 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003470 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003471 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003472 CodecInst codec;
3473 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003474
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003475 if (!mono_recording_audio_.get()) {
3476 // Temporary space for DownConvertToCodecFormat.
3477 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003478 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003479 DownConvertToCodecFormat(audio_data,
3480 number_of_frames,
3481 number_of_channels,
3482 sample_rate,
3483 codec.channels,
3484 codec.plfreq,
3485 mono_recording_audio_.get(),
3486 &input_resampler_,
3487 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003488}
3489
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003490uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003491Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003492{
3493 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3494 "Channel::PrepareEncodeAndSend()");
3495
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003496 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003497 {
3498 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3499 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003500 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003501 }
3502
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003503 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 {
3505 MixOrReplaceAudioWithFile(mixingFrequency);
3506 }
3507
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003508 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3509 if (is_muted) {
3510 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003511 }
3512
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003513 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003514 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003515 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003516 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003517 if (_inputExternalMediaCallbackPtr)
3518 {
3519 _inputExternalMediaCallbackPtr->Process(
3520 _channelId,
3521 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003522 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003523 _audioFrame.samples_per_channel_,
3524 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003525 isStereo);
3526 }
3527 }
3528
3529 InsertInbandDtmfTone();
3530
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003531 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003532 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003533 if (is_muted) {
3534 rms_level_.ProcessMuted(length);
3535 } else {
3536 rms_level_.Process(_audioFrame.data_, length);
3537 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003538 }
3539
niklase@google.com470e71d2011-07-07 08:21:25 +00003540 return 0;
3541}
3542
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003543uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003544Channel::EncodeAndSend()
3545{
3546 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3547 "Channel::EncodeAndSend()");
3548
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003549 assert(_audioFrame.num_channels_ <= 2);
3550 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003551 {
3552 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3553 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003554 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003555 }
3556
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003557 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003558
3559 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3560
3561 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003562 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003563 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003564 {
3565 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3566 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003567 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003568 }
3569
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003570 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003571
3572 // --- Encode if complete frame is ready
3573
3574 // This call will trigger AudioPacketizationCallback::SendData if encoding
3575 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003576 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003577}
3578
3579int Channel::RegisterExternalMediaProcessing(
3580 ProcessingTypes type,
3581 VoEMediaProcess& processObject)
3582{
3583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3584 "Channel::RegisterExternalMediaProcessing()");
3585
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003586 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003587
3588 if (kPlaybackPerChannel == type)
3589 {
3590 if (_outputExternalMediaCallbackPtr)
3591 {
3592 _engineStatisticsPtr->SetLastError(
3593 VE_INVALID_OPERATION, kTraceError,
3594 "Channel::RegisterExternalMediaProcessing() "
3595 "output external media already enabled");
3596 return -1;
3597 }
3598 _outputExternalMediaCallbackPtr = &processObject;
3599 _outputExternalMedia = true;
3600 }
3601 else if (kRecordingPerChannel == type)
3602 {
3603 if (_inputExternalMediaCallbackPtr)
3604 {
3605 _engineStatisticsPtr->SetLastError(
3606 VE_INVALID_OPERATION, kTraceError,
3607 "Channel::RegisterExternalMediaProcessing() "
3608 "output external media already enabled");
3609 return -1;
3610 }
3611 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003612 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003613 }
3614 return 0;
3615}
3616
3617int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3618{
3619 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3620 "Channel::DeRegisterExternalMediaProcessing()");
3621
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003622 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003623
3624 if (kPlaybackPerChannel == type)
3625 {
3626 if (!_outputExternalMediaCallbackPtr)
3627 {
3628 _engineStatisticsPtr->SetLastError(
3629 VE_INVALID_OPERATION, kTraceWarning,
3630 "Channel::DeRegisterExternalMediaProcessing() "
3631 "output external media already disabled");
3632 return 0;
3633 }
3634 _outputExternalMedia = false;
3635 _outputExternalMediaCallbackPtr = NULL;
3636 }
3637 else if (kRecordingPerChannel == type)
3638 {
3639 if (!_inputExternalMediaCallbackPtr)
3640 {
3641 _engineStatisticsPtr->SetLastError(
3642 VE_INVALID_OPERATION, kTraceWarning,
3643 "Channel::DeRegisterExternalMediaProcessing() "
3644 "input external media already disabled");
3645 return 0;
3646 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003647 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003648 _inputExternalMediaCallbackPtr = NULL;
3649 }
3650
3651 return 0;
3652}
3653
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003654int Channel::SetExternalMixing(bool enabled) {
3655 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3656 "Channel::SetExternalMixing(enabled=%d)", enabled);
3657
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003658 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003659 {
3660 _engineStatisticsPtr->SetLastError(
3661 VE_INVALID_OPERATION, kTraceError,
3662 "Channel::SetExternalMixing() "
3663 "external mixing cannot be changed while playing.");
3664 return -1;
3665 }
3666
3667 _externalMixing = enabled;
3668
3669 return 0;
3670}
3671
niklase@google.com470e71d2011-07-07 08:21:25 +00003672int
niklase@google.com470e71d2011-07-07 08:21:25 +00003673Channel::GetNetworkStatistics(NetworkStatistics& stats)
3674{
3675 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3676 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003677 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003678}
3679
wu@webrtc.org24301a62013-12-13 19:17:43 +00003680void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3681 audio_coding_->GetDecodingCallStatistics(stats);
3682}
3683
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003684bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3685 int* playout_buffer_delay_ms) const {
3686 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003688 "Channel::GetDelayEstimate() no valid estimate.");
3689 return false;
3690 }
3691 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3692 _recPacketDelayMs;
3693 *playout_buffer_delay_ms = playout_delay_ms_;
3694 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3695 "Channel::GetDelayEstimate()");
3696 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003697}
3698
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003699int Channel::SetInitialPlayoutDelay(int delay_ms)
3700{
3701 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3702 "Channel::SetInitialPlayoutDelay()");
3703 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3704 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3705 {
3706 _engineStatisticsPtr->SetLastError(
3707 VE_INVALID_ARGUMENT, kTraceError,
3708 "SetInitialPlayoutDelay() invalid min delay");
3709 return -1;
3710 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003711 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003712 {
3713 _engineStatisticsPtr->SetLastError(
3714 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3715 "SetInitialPlayoutDelay() failed to set min playout delay");
3716 return -1;
3717 }
3718 return 0;
3719}
3720
3721
niklase@google.com470e71d2011-07-07 08:21:25 +00003722int
3723Channel::SetMinimumPlayoutDelay(int delayMs)
3724{
3725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3726 "Channel::SetMinimumPlayoutDelay()");
3727 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3728 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3729 {
3730 _engineStatisticsPtr->SetLastError(
3731 VE_INVALID_ARGUMENT, kTraceError,
3732 "SetMinimumPlayoutDelay() invalid min delay");
3733 return -1;
3734 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003735 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003736 {
3737 _engineStatisticsPtr->SetLastError(
3738 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3739 "SetMinimumPlayoutDelay() failed to set min playout delay");
3740 return -1;
3741 }
3742 return 0;
3743}
3744
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003745void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3746 uint32_t playout_timestamp = 0;
3747
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003748 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003749 // This can happen if this channel has not been received any RTP packet. In
3750 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003751 return;
3752 }
3753
3754 uint16_t delay_ms = 0;
3755 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3756 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3757 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3758 " delay from the ADM");
3759 _engineStatisticsPtr->SetLastError(
3760 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3761 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3762 return;
3763 }
3764
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003765 jitter_buffer_playout_timestamp_ = playout_timestamp;
3766
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003767 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003768 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003769
3770 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3771 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3772 playout_timestamp);
3773
3774 if (rtcp) {
3775 playout_timestamp_rtcp_ = playout_timestamp;
3776 } else {
3777 playout_timestamp_rtp_ = playout_timestamp;
3778 }
3779 playout_delay_ms_ = delay_ms;
3780}
3781
3782int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3784 "Channel::GetPlayoutTimestamp()");
3785 if (playout_timestamp_rtp_ == 0) {
3786 _engineStatisticsPtr->SetLastError(
3787 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3788 "GetPlayoutTimestamp() failed to retrieve timestamp");
3789 return -1;
3790 }
3791 timestamp = playout_timestamp_rtp_;
3792 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3793 VoEId(_instanceId,_channelId),
3794 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3795 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003796}
3797
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003798int Channel::SetInitTimestamp(unsigned int timestamp) {
3799 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003800 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003801 if (channel_state_.Get().sending) {
3802 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3803 "SetInitTimestamp() already sending");
3804 return -1;
3805 }
3806 _rtpRtcpModule->SetStartTimestamp(timestamp);
3807 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003808}
3809
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003810int Channel::SetInitSequenceNumber(short sequenceNumber) {
3811 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3812 "Channel::SetInitSequenceNumber()");
3813 if (channel_state_.Get().sending) {
3814 _engineStatisticsPtr->SetLastError(
3815 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3816 return -1;
3817 }
3818 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3819 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003820}
3821
3822int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003823Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003824{
3825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3826 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003827 *rtpRtcpModule = _rtpRtcpModule.get();
3828 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003829 return 0;
3830}
3831
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003832// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3833// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003834int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003835Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003836{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003837 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003838 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003839
3840 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003841 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003842
3843 if (_inputFilePlayerPtr == NULL)
3844 {
3845 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3846 VoEId(_instanceId, _channelId),
3847 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3848 " doesnt exist");
3849 return -1;
3850 }
3851
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003852 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003853 fileSamples,
3854 mixingFrequency) == -1)
3855 {
3856 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3857 VoEId(_instanceId, _channelId),
3858 "Channel::MixOrReplaceAudioWithFile() file mixing "
3859 "failed");
3860 return -1;
3861 }
3862 if (fileSamples == 0)
3863 {
3864 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3865 VoEId(_instanceId, _channelId),
3866 "Channel::MixOrReplaceAudioWithFile() file is ended");
3867 return 0;
3868 }
3869 }
3870
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003871 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003872
3873 if (_mixFileWithMicrophone)
3874 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003875 // Currently file stream is always mono.
3876 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003877 MixWithSat(_audioFrame.data_,
3878 _audioFrame.num_channels_,
3879 fileBuffer.get(),
3880 1,
3881 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003882 }
3883 else
3884 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003885 // Replace ACM audio with file.
3886 // Currently file stream is always mono.
3887 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003888 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003889 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003890 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003891 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003892 mixingFrequency,
3893 AudioFrame::kNormalSpeech,
3894 AudioFrame::kVadUnknown,
3895 1);
3896
3897 }
3898 return 0;
3899}
3900
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003901int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003902Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003903 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003904{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003905 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003906
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003907 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003908 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003909
3910 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003911 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003912
3913 if (_outputFilePlayerPtr == NULL)
3914 {
3915 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3916 VoEId(_instanceId, _channelId),
3917 "Channel::MixAudioWithFile() file mixing failed");
3918 return -1;
3919 }
3920
3921 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003922 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 fileSamples,
3924 mixingFrequency) == -1)
3925 {
3926 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3927 VoEId(_instanceId, _channelId),
3928 "Channel::MixAudioWithFile() file mixing failed");
3929 return -1;
3930 }
3931 }
3932
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003933 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003934 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003935 // Currently file stream is always mono.
3936 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003937 MixWithSat(audioFrame.data_,
3938 audioFrame.num_channels_,
3939 fileBuffer.get(),
3940 1,
3941 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003942 }
3943 else
3944 {
3945 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003946 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003947 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003948 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003949 return -1;
3950 }
3951
3952 return 0;
3953}
3954
3955int
3956Channel::InsertInbandDtmfTone()
3957{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003958 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003959 if (_inbandDtmfQueue.PendingDtmf() &&
3960 !_inbandDtmfGenerator.IsAddingTone() &&
3961 _inbandDtmfGenerator.DelaySinceLastTone() >
3962 kMinTelephoneEventSeparationMs)
3963 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003964 int8_t eventCode(0);
3965 uint16_t lengthMs(0);
3966 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003967
3968 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3969 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3970 if (_playInbandDtmfEvent)
3971 {
3972 // Add tone to output mixer using a reduced length to minimize
3973 // risk of echo.
3974 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3975 attenuationDb);
3976 }
3977 }
3978
3979 if (_inbandDtmfGenerator.IsAddingTone())
3980 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003981 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003982 _inbandDtmfGenerator.GetSampleRate(frequency);
3983
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003984 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003985 {
3986 // Update sample rate of Dtmf tone since the mixing frequency
3987 // has changed.
3988 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003989 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003990 // Reset the tone to be added taking the new sample rate into
3991 // account.
3992 _inbandDtmfGenerator.ResetTone();
3993 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003994
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003995 int16_t toneBuffer[320];
3996 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003997 // Get 10ms tone segment and set time since last tone to zero
3998 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3999 {
4000 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4001 VoEId(_instanceId, _channelId),
4002 "Channel::EncodeAndSend() inserting Dtmf failed");
4003 return -1;
4004 }
4005
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004006 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004007 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004008 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004009 sample++)
4010 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004011 for (int channel = 0;
4012 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004013 channel++)
4014 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004015 const int index = sample * _audioFrame.num_channels_ + channel;
4016 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004017 }
4018 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004019
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004020 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004021 } else
4022 {
4023 // Add 10ms to "delay-since-last-tone" counter
4024 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4025 }
4026 return 0;
4027}
4028
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004029int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00004030Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00004031{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004032 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004033 if (_transportPtr == NULL)
4034 {
4035 return -1;
4036 }
4037 if (!RTCP)
4038 {
4039 return _transportPtr->SendPacket(_channelId, data, len);
4040 }
4041 else
4042 {
4043 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4044 }
4045}
4046
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004047// Called for incoming RTP packets after successful RTP header parsing.
4048void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4049 uint16_t sequence_number) {
4050 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4051 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4052 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004053
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004054 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004055 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004056
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004057 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004058 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004059
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004060 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4061 // every incoming packet.
4062 uint32_t timestamp_diff_ms = (rtp_timestamp -
4063 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004064 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4065 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4066 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4067 // timestamp, the resulting difference is negative, but is set to zero.
4068 // This can happen when a network glitch causes a packet to arrive late,
4069 // and during long comfort noise periods with clock drift.
4070 timestamp_diff_ms = 0;
4071 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004072
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004073 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4074 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004075
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004076 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004077
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004078 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004079
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004080 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4081 _recPacketDelayMs = packet_delay_ms;
4082 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004083
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004084 if (_average_jitter_buffer_delay_us == 0) {
4085 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4086 return;
4087 }
4088
4089 // Filter average delay value using exponential filter (alpha is
4090 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4091 // risk of rounding error) and compensate for it in GetDelayEstimate()
4092 // later.
4093 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4094 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004095}
4096
4097void
4098Channel::RegisterReceiveCodecsToRTPModule()
4099{
4100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4101 "Channel::RegisterReceiveCodecsToRTPModule()");
4102
4103
4104 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004105 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004106
4107 for (int idx = 0; idx < nSupportedCodecs; idx++)
4108 {
4109 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004110 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004111 (rtp_receiver_->RegisterReceivePayload(
4112 codec.plname,
4113 codec.pltype,
4114 codec.plfreq,
4115 codec.channels,
4116 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004117 {
4118 WEBRTC_TRACE(
4119 kTraceWarning,
4120 kTraceVoice,
4121 VoEId(_instanceId, _channelId),
4122 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4123 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4124 codec.plname, codec.pltype, codec.plfreq,
4125 codec.channels, codec.rate);
4126 }
4127 else
4128 {
4129 WEBRTC_TRACE(
4130 kTraceInfo,
4131 kTraceVoice,
4132 VoEId(_instanceId, _channelId),
4133 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004134 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004135 "receiver",
4136 codec.plname, codec.pltype, codec.plfreq,
4137 codec.channels, codec.rate);
4138 }
4139 }
4140}
4141
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004142// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004143int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004144 CodecInst codec;
4145 bool found_red = false;
4146
4147 // Get default RED settings from the ACM database
4148 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4149 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004150 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004151 if (!STR_CASE_CMP(codec.plname, "RED")) {
4152 found_red = true;
4153 break;
4154 }
4155 }
4156
4157 if (!found_red) {
4158 _engineStatisticsPtr->SetLastError(
4159 VE_CODEC_ERROR, kTraceError,
4160 "SetRedPayloadType() RED is not supported");
4161 return -1;
4162 }
4163
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004164 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004165 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004166 _engineStatisticsPtr->SetLastError(
4167 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4168 "SetRedPayloadType() RED registration in ACM module failed");
4169 return -1;
4170 }
4171
4172 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4173 _engineStatisticsPtr->SetLastError(
4174 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4175 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4176 return -1;
4177 }
4178 return 0;
4179}
4180
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004181int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4182 unsigned char id) {
4183 int error = 0;
4184 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4185 if (enable) {
4186 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4187 }
4188 return error;
4189}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004190
wu@webrtc.org94454b72014-06-05 20:34:08 +00004191int32_t Channel::GetPlayoutFrequency() {
4192 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4193 CodecInst current_recive_codec;
4194 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4195 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4196 // Even though the actual sampling rate for G.722 audio is
4197 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4198 // 8,000 Hz because that value was erroneously assigned in
4199 // RFC 1890 and must remain unchanged for backward compatibility.
4200 playout_frequency = 8000;
4201 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4202 // We are resampling Opus internally to 32,000 Hz until all our
4203 // DSP routines can operate at 48,000 Hz, but the RTP clock
4204 // rate for the Opus payload format is standardized to 48,000 Hz,
4205 // because that is the maximum supported decoding sampling rate.
4206 playout_frequency = 48000;
4207 }
4208 }
4209 return playout_frequency;
4210}
4211
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004212int64_t Channel::GetRTT() const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004213 RTCPMethod method = _rtpRtcpModule->RTCP();
4214 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004215 return 0;
4216 }
4217 std::vector<RTCPReportBlock> report_blocks;
4218 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4219 if (report_blocks.empty()) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004220 return 0;
4221 }
4222
4223 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4224 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4225 for (; it != report_blocks.end(); ++it) {
4226 if (it->remoteSSRC == remoteSSRC)
4227 break;
4228 }
4229 if (it == report_blocks.end()) {
4230 // We have not received packets with SSRC matching the report blocks.
4231 // To calculate RTT we try with the SSRC of the first report block.
4232 // This is very important for send-only channels where we don't know
4233 // the SSRC of the other end.
4234 remoteSSRC = report_blocks[0].remoteSSRC;
4235 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004236 int64_t rtt = 0;
4237 int64_t avg_rtt = 0;
4238 int64_t max_rtt= 0;
4239 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004240 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4241 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004242 return 0;
4243 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004244 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004245}
4246
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004247} // namespace voe
4248} // namespace webrtc