blob: af2c58e4e4ebe5fe811363dfbe3799b5352e1b90 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Henrik Lundin64dad832015-05-11 12:44:23 +020013#include <algorithm>
14
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000015#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000016#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000017#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020018#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000019#include "webrtc/modules/audio_device/include/audio_device.h"
20#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000021#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000022#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
23#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
24#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
25#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000026#include "webrtc/modules/utility/interface/audio_frame_operations.h"
27#include "webrtc/modules/utility/interface/process_thread.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000028#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
29#include "webrtc/system_wrappers/interface/logging.h"
30#include "webrtc/system_wrappers/interface/trace.h"
31#include "webrtc/voice_engine/include/voe_base.h"
32#include "webrtc/voice_engine/include/voe_external_media.h"
33#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
34#include "webrtc/voice_engine/output_mixer.h"
35#include "webrtc/voice_engine/statistics.h"
36#include "webrtc/voice_engine/transmit_mixer.h"
37#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000038
39#if defined(_WIN32)
40#include <Qos.h>
41#endif
42
andrew@webrtc.org50419b02012-11-14 19:07:54 +000043namespace webrtc {
44namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000045
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000046// Extend the default RTCP statistics struct with max_jitter, defined as the
47// maximum jitter value seen in an RTCP report block.
48struct ChannelStatistics : public RtcpStatistics {
49 ChannelStatistics() : rtcp(), max_jitter(0) {}
50
51 RtcpStatistics rtcp;
52 uint32_t max_jitter;
53};
54
55// Statistics callback, called at each generation of a new RTCP report block.
56class StatisticsProxy : public RtcpStatisticsCallback {
57 public:
58 StatisticsProxy(uint32_t ssrc)
59 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
60 ssrc_(ssrc) {}
61 virtual ~StatisticsProxy() {}
62
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000063 void StatisticsUpdated(const RtcpStatistics& statistics,
64 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000065 if (ssrc != ssrc_)
66 return;
67
68 CriticalSectionScoped cs(stats_lock_.get());
69 stats_.rtcp = statistics;
70 if (statistics.jitter > stats_.max_jitter) {
71 stats_.max_jitter = statistics.jitter;
72 }
73 }
74
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000075 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +000076
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000077 void ResetStatistics() {
78 CriticalSectionScoped cs(stats_lock_.get());
79 stats_ = ChannelStatistics();
80 }
81
82 ChannelStatistics GetStats() {
83 CriticalSectionScoped cs(stats_lock_.get());
84 return stats_;
85 }
86
87 private:
88 // StatisticsUpdated calls are triggered from threads in the RTP module,
89 // while GetStats calls can be triggered from the public voice engine API,
90 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000091 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000092 const uint32_t ssrc_;
93 ChannelStatistics stats_;
94};
95
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000096class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000097 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000098 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
99 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000100
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000101 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
102 // Not used for Voice Engine.
103 }
104
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000105 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
106 int64_t rtt,
107 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000108 // 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
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000199Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000200{
201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000202 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000203
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000204 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000205 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 return 0;
207}
208
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000209int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000210Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000211{
212 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
213 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
214
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000215 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216 if (_rxVadObserverPtr)
217 {
218 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
219 }
220
221 return 0;
222}
223
224int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000225Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000226{
227 channel = VoEChannelId(channel);
228 assert(channel == _channelId);
229
230 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000231 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
232 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000233
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000234 CriticalSectionScoped cs(&_callbackCritSect);
235
niklase@google.com470e71d2011-07-07 08:21:25 +0000236 if (_transportPtr == NULL)
237 {
238 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
239 "Channel::SendPacket() failed to send RTP packet due to"
240 " invalid transport object");
241 return -1;
242 }
243
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000244 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000245 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000247 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
248 bufferLength);
249 if (n < 0) {
250 std::string transport_name =
251 _externalTransport ? "external transport" : "WebRtc sockets";
252 WEBRTC_TRACE(kTraceError, kTraceVoice,
253 VoEId(_instanceId,_channelId),
254 "Channel::SendPacket() RTP transmission using %s failed",
255 transport_name.c_str());
256 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000257 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000259}
260
261int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000262Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000263{
264 channel = VoEChannelId(channel);
265 assert(channel == _channelId);
266
267 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000268 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
269 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000270
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000271 CriticalSectionScoped cs(&_callbackCritSect);
272 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000273 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000274 WEBRTC_TRACE(kTraceError, kTraceVoice,
275 VoEId(_instanceId,_channelId),
276 "Channel::SendRTCPPacket() failed to send RTCP packet"
277 " due to invalid transport object");
278 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000279 }
280
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000281 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000282 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000284 int n = _transportPtr->SendRTCPPacket(channel,
285 bufferToSendPtr,
286 bufferLength);
287 if (n < 0) {
288 std::string transport_name =
289 _externalTransport ? "external transport" : "WebRtc sockets";
290 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
291 VoEId(_instanceId,_channelId),
292 "Channel::SendRTCPPacket() transmission using %s failed",
293 transport_name.c_str());
294 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000296 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000297}
298
299void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000300Channel::OnPlayTelephoneEvent(int32_t id,
301 uint8_t event,
302 uint16_t lengthMs,
303 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000304{
305 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
306 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000307 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000308
309 if (!_playOutbandDtmfEvent || (event > 15))
310 {
311 // Ignore callback since feedback is disabled or event is not a
312 // Dtmf tone event.
313 return;
314 }
315
316 assert(_outputMixerPtr != NULL);
317
318 // Start playing out the Dtmf tone (if playout is enabled).
319 // Reduce length of tone with 80ms to the reduce risk of echo.
320 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
321}
322
323void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000324Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000325{
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
327 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000328 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000329
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000330 // Update ssrc so that NTP for AV sync can be updated.
331 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000332}
333
pbos@webrtc.org92135212013-05-14 08:31:39 +0000334void Channel::OnIncomingCSRCChanged(int32_t id,
335 uint32_t CSRC,
336 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000337{
338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
339 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
340 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000341}
342
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000343void Channel::ResetStatistics(uint32_t ssrc) {
344 StreamStatistician* statistician =
345 rtp_receive_statistics_->GetStatistician(ssrc);
346 if (statistician) {
347 statistician->ResetStatistics();
348 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000349 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000350}
351
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000352int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000353Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000354 int32_t id,
355 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000356 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000357 int frequency,
358 uint8_t channels,
359 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000360{
361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
362 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
363 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
364 id, payloadType, payloadName, frequency, channels, rate);
365
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000366 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000368 CodecInst receiveCodec = {0};
369 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000370
371 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 receiveCodec.plfreq = frequency;
373 receiveCodec.channels = channels;
374 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000375 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000376
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000377 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000378 receiveCodec.pacsize = dummyCodec.pacsize;
379
380 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000381 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 {
383 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000384 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000385 "Channel::OnInitializeDecoder() invalid codec ("
386 "pt=%d, name=%s) received - 1", payloadType, payloadName);
387 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
388 return -1;
389 }
390
391 return 0;
392}
393
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000394int32_t
395Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000396 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 const WebRtcRTPHeader* rtpHeader)
398{
399 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000400 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000401 " payloadType=%u, audioChannel=%u)",
402 payloadSize,
403 rtpHeader->header.payloadType,
404 rtpHeader->type.Audio.channel);
405
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000406 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 {
408 // Avoid inserting into NetEQ when we are not playing. Count the
409 // packet as discarded.
410 WEBRTC_TRACE(kTraceStream, kTraceVoice,
411 VoEId(_instanceId, _channelId),
412 "received packet is discarded since playing is not"
413 " activated");
414 _numberOfDiscardedPackets++;
415 return 0;
416 }
417
418 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000419 if (audio_coding_->IncomingPacket(payloadData,
420 payloadSize,
421 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 {
423 _engineStatisticsPtr->SetLastError(
424 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
425 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
426 return -1;
427 }
428
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000429 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 UpdatePacketDelay(rtpHeader->header.timestamp,
431 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000432
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000433 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000434 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
435 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000436
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000437 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000438 round_trip_time);
439 if (!nack_list.empty()) {
440 // Can't use nack_list.data() since it's not supported by all
441 // compilers.
442 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000443 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 return 0;
445}
446
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000447bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000448 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000449 RTPHeader header;
450 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
451 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
452 "IncomingPacket invalid RTP header");
453 return false;
454 }
455 header.payload_type_frequency =
456 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
457 if (header.payload_type_frequency < 0)
458 return false;
459 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
460}
461
pbos@webrtc.org92135212013-05-14 08:31:39 +0000462int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000463{
464 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
465 "Channel::GetAudioFrame(id=%d)", id);
466
467 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000468 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
469 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 {
471 WEBRTC_TRACE(kTraceError, kTraceVoice,
472 VoEId(_instanceId,_channelId),
473 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000474 // In all likelihood, the audio in this frame is garbage. We return an
475 // error so that the audio mixer module doesn't add it to the mix. As
476 // a result, it won't be played out and the actions skipped here are
477 // irrelevant.
478 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 }
480
481 if (_RxVadDetection)
482 {
483 UpdateRxVadDetection(audioFrame);
484 }
485
486 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000487 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000488 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000489 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000490
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000491 ChannelState::State state = channel_state_.Get();
492
493 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000494 int err = rx_audioproc_->ProcessStream(&audioFrame);
495 if (err) {
496 LOG(LS_ERROR) << "ProcessStream() error: " << err;
497 assert(false);
498 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 }
500
wu@webrtc.org63420662013-10-17 18:28:55 +0000501 float output_gain = 1.0f;
502 float left_pan = 1.0f;
503 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000505 CriticalSectionScoped cs(&volume_settings_critsect_);
506 output_gain = _outputGain;
507 left_pan = _panLeft;
508 right_pan= _panRight;
509 }
510
511 // Output volume scaling
512 if (output_gain < 0.99f || output_gain > 1.01f)
513 {
514 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 }
516
517 // Scale left and/or right channel(s) if stereo and master balance is
518 // active
519
wu@webrtc.org63420662013-10-17 18:28:55 +0000520 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000522 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000523 {
524 // Emulate stereo mode since panning is active.
525 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000526 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 }
528 // For true stereo mode (when we are receiving a stereo signal), no
529 // action is needed.
530
531 // Do the panning operation (the audio frame contains stereo at this
532 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000533 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 }
535
536 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000537 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000539 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 }
541
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 // External media
543 if (_outputExternalMedia)
544 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000545 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000546 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 if (_outputExternalMediaCallbackPtr)
548 {
549 _outputExternalMediaCallbackPtr->Process(
550 _channelId,
551 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000552 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000553 audioFrame.samples_per_channel_,
554 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 isStereo);
556 }
557 }
558
559 // Record playout if enabled
560 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000561 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000562
563 if (_outputFileRecording && _outputFileRecorderPtr)
564 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000565 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 }
567 }
568
569 // Measure audio level (0-9)
570 _outputAudioLevel.ComputeLevel(audioFrame);
571
wu@webrtc.org94454b72014-06-05 20:34:08 +0000572 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
573 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000574 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000575 }
576
577 if (capture_start_rtp_time_stamp_ >= 0) {
578 // audioFrame.timestamp_ should be valid from now on.
579
580 // Compute elapsed time.
581 int64_t unwrap_timestamp =
582 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
583 audioFrame.elapsed_time_ms_ =
584 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
585 (GetPlayoutFrequency() / 1000);
586
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000587 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000588 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000589 // Compute ntp time.
590 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
591 audioFrame.timestamp_);
592 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
593 if (audioFrame.ntp_time_ms_ > 0) {
594 // Compute |capture_start_ntp_time_ms_| so that
595 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
596 capture_start_ntp_time_ms_ =
597 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
598 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000599 }
600 }
601
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 return 0;
603}
604
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000605int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000606Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000607{
608 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
609 "Channel::NeededFrequency(id=%d)", id);
610
611 int highestNeeded = 0;
612
613 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000614 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
616 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000617 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000619 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 }
621 else
622 {
623 highestNeeded = receiveFrequency;
624 }
625
626 // Special case, if we're playing a file on the playout side
627 // we take that frequency into consideration as well
628 // This is not needed on sending side, since the codec will
629 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000630 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000631 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000632 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000633 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 {
635 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
636 {
637 highestNeeded=_outputFilePlayerPtr->Frequency();
638 }
639 }
640 }
641
642 return(highestNeeded);
643}
644
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000645int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000646Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000647 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000648 uint32_t instanceId,
649 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000650{
651 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
652 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
653 channelId, instanceId);
654
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000655 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 if (channel == NULL)
657 {
658 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
659 VoEId(instanceId,channelId),
660 "Channel::CreateChannel() unable to allocate memory for"
661 " channel");
662 return -1;
663 }
664 return 0;
665}
666
667void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000668Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000669{
670 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
671 "Channel::PlayNotification(id=%d, durationMs=%d)",
672 id, durationMs);
673
674 // Not implement yet
675}
676
677void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000678Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000679{
680 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
681 "Channel::RecordNotification(id=%d, durationMs=%d)",
682 id, durationMs);
683
684 // Not implement yet
685}
686
687void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000688Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000689{
690 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
691 "Channel::PlayFileEnded(id=%d)", id);
692
693 if (id == _inputFilePlayerId)
694 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000695 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
697 VoEId(_instanceId,_channelId),
698 "Channel::PlayFileEnded() => input file player module is"
699 " shutdown");
700 }
701 else if (id == _outputFilePlayerId)
702 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000703 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
705 VoEId(_instanceId,_channelId),
706 "Channel::PlayFileEnded() => output file player module is"
707 " shutdown");
708 }
709}
710
711void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000712Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000713{
714 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
715 "Channel::RecordFileEnded(id=%d)", id);
716
717 assert(id == _outputFileRecorderId);
718
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000719 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000720
721 _outputFileRecording = false;
722 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
723 VoEId(_instanceId,_channelId),
724 "Channel::RecordFileEnded() => output file recorder module is"
725 " shutdown");
726}
727
pbos@webrtc.org92135212013-05-14 08:31:39 +0000728Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000729 uint32_t instanceId,
730 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
732 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000733 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000735 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000736 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000737 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000738 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000739 rtp_receive_statistics_(ReceiveStatistics::Create(
740 Clock::GetRealTimeClock())),
741 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
742 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
743 this, this, rtp_payload_registry_.get())),
744 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000746 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000747 _inputFilePlayerPtr(NULL),
748 _outputFilePlayerPtr(NULL),
749 _outputFileRecorderPtr(NULL),
750 // Avoid conflict with other channels by adding 1024 - 1026,
751 // won't use as much as 1024 channels.
752 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
753 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
754 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000755 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000756 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
757 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000758 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000759 _inputExternalMediaCallbackPtr(NULL),
760 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000761 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
762 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000763 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000764 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000765 playout_timestamp_rtp_(0),
766 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000767 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000768 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000769 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000770 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000771 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
772 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000773 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000774 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000775 _outputMixerPtr(NULL),
776 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _moduleProcessThreadPtr(NULL),
778 _audioDeviceModulePtr(NULL),
779 _voiceEngineObserverPtr(NULL),
780 _callbackCritSectPtr(NULL),
781 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000782 _rxVadObserverPtr(NULL),
783 _oldVadDecision(-1),
784 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000785 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000786 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 _mute(false),
788 _panLeft(1.0f),
789 _panRight(1.0f),
790 _outputGain(1.0f),
791 _playOutbandDtmfEvent(false),
792 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000793 _lastLocalTimeStamp(0),
794 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000795 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000797 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000798 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 _previousTimestamp(0),
800 _recPacketDelayMs(20),
801 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000803 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000804 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000805 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200806 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
807 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
808 associate_send_channel_(ChannelOwner(nullptr))
niklase@google.com470e71d2011-07-07 08:21:25 +0000809{
810 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
811 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200812 AudioCodingModule::Config acm_config;
813 acm_config.id = VoEModuleId(instanceId, channelId);
814 if (config.Get<NetEqCapacityConfig>().enabled) {
815 // Clamping the buffer capacity at 20 packets. While going lower will
816 // probably work, it makes little sense.
817 acm_config.neteq_config.max_packets_in_buffer =
818 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
819 }
820 audio_coding_.reset(AudioCodingModule::Create(acm_config));
821
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 _inbandDtmfQueue.ResetDtmf();
823 _inbandDtmfGenerator.Init();
824 _outputAudioLevel.Clear();
825
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000826 RtpRtcp::Configuration configuration;
827 configuration.id = VoEModuleId(instanceId, channelId);
828 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000829 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000830 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000831 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000832 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000833
834 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000835
836 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
837 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
838 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000839
840 Config audioproc_config;
841 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
842 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000843}
844
845Channel::~Channel()
846{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000847 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
849 "Channel::~Channel() - dtor");
850
851 if (_outputExternalMedia)
852 {
853 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
854 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000855 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000856 {
857 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
858 }
859 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000860 StopPlayout();
861
862 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000863 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 if (_inputFilePlayerPtr)
865 {
866 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
867 _inputFilePlayerPtr->StopPlayingFile();
868 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
869 _inputFilePlayerPtr = NULL;
870 }
871 if (_outputFilePlayerPtr)
872 {
873 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
874 _outputFilePlayerPtr->StopPlayingFile();
875 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
876 _outputFilePlayerPtr = NULL;
877 }
878 if (_outputFileRecorderPtr)
879 {
880 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
881 _outputFileRecorderPtr->StopRecording();
882 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
883 _outputFileRecorderPtr = NULL;
884 }
885 }
886
887 // The order to safely shutdown modules in a channel is:
888 // 1. De-register callbacks in modules
889 // 2. De-register modules in process thread
890 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000891 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 {
893 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
894 VoEId(_instanceId,_channelId),
895 "~Channel() failed to de-register transport callback"
896 " (Audio coding module)");
897 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000898 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 {
900 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
901 VoEId(_instanceId,_channelId),
902 "~Channel() failed to de-register VAD callback"
903 " (Audio coding module)");
904 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000906 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
907
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 // End of modules shutdown
909
910 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000913 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000914}
915
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000916int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000917Channel::Init()
918{
919 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
920 "Channel::Init()");
921
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000922 channel_state_.Reset();
923
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 // --- Initial sanity
925
926 if ((_engineStatisticsPtr == NULL) ||
927 (_moduleProcessThreadPtr == NULL))
928 {
929 WEBRTC_TRACE(kTraceError, kTraceVoice,
930 VoEId(_instanceId,_channelId),
931 "Channel::Init() must call SetEngineInformation() first");
932 return -1;
933 }
934
935 // --- Add modules to process thread (for periodic schedulation)
936
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000937 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
938
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000939 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000940
Henrik Lundin45c64492015-03-30 19:00:44 +0200941 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000942#ifdef WEBRTC_CODEC_AVT
943 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200944 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000945#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200946 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000947 {
948 _engineStatisticsPtr->SetLastError(
949 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
950 "Channel::Init() unable to initialize the ACM - 1");
951 return -1;
952 }
953
954 // --- RTP/RTCP module initialization
955
956 // Ensure that RTCP is enabled by default for the created channel.
957 // Note that, the module will keep generating RTCP until it is explicitly
958 // disabled by the user.
959 // After StopListen (when no sockets exists), RTCP packets will no longer
960 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000961 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
962 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000963 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
964 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000966 (audio_coding_->RegisterTransportCallback(this) == -1) ||
967 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000968
969 if (fail)
970 {
971 _engineStatisticsPtr->SetLastError(
972 VE_CANNOT_INIT_CHANNEL, kTraceError,
973 "Channel::Init() callbacks not registered");
974 return -1;
975 }
976
977 // --- Register all supported codecs to the receiving side of the
978 // RTP/RTCP module
979
980 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000981 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000982
983 for (int idx = 0; idx < nSupportedCodecs; idx++)
984 {
985 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000986 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000987 (rtp_receiver_->RegisterReceivePayload(
988 codec.plname,
989 codec.pltype,
990 codec.plfreq,
991 codec.channels,
992 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 {
994 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
995 VoEId(_instanceId,_channelId),
996 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
997 "to RTP/RTCP receiver",
998 codec.plname, codec.pltype, codec.plfreq,
999 codec.channels, codec.rate);
1000 }
1001 else
1002 {
1003 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1004 VoEId(_instanceId,_channelId),
1005 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1006 "the RTP/RTCP receiver",
1007 codec.plname, codec.pltype, codec.plfreq,
1008 codec.channels, codec.rate);
1009 }
1010
1011 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001012 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 {
1014 SetSendCodec(codec);
1015 }
1016
1017 // Register default PT for outband 'telephone-event'
1018 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1019 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001020 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001021 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
1023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "Channel::Init() failed to register outband "
1026 "'telephone-event' (%d/%d) correctly",
1027 codec.pltype, codec.plfreq);
1028 }
1029 }
1030
1031 if (!STR_CASE_CMP(codec.plname, "CN"))
1032 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001033 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1034 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001035 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 {
1037 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1038 VoEId(_instanceId,_channelId),
1039 "Channel::Init() failed to register CN (%d/%d) "
1040 "correctly - 1",
1041 codec.pltype, codec.plfreq);
1042 }
1043 }
1044#ifdef WEBRTC_CODEC_RED
1045 // Register RED to the receiving side of the ACM.
1046 // We will not receive an OnInitializeDecoder() callback for RED.
1047 if (!STR_CASE_CMP(codec.plname, "RED"))
1048 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001049 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 {
1051 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1052 VoEId(_instanceId,_channelId),
1053 "Channel::Init() failed to register RED (%d/%d) "
1054 "correctly",
1055 codec.pltype, codec.plfreq);
1056 }
1057 }
1058#endif
1059 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001060
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001061 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1062 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1063 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001065 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1066 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1067 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001068 }
1069
1070 return 0;
1071}
1072
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001073int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001074Channel::SetEngineInformation(Statistics& engineStatistics,
1075 OutputMixer& outputMixer,
1076 voe::TransmitMixer& transmitMixer,
1077 ProcessThread& moduleProcessThread,
1078 AudioDeviceModule& audioDeviceModule,
1079 VoiceEngineObserver* voiceEngineObserver,
1080 CriticalSectionWrapper* callbackCritSect)
1081{
1082 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1083 "Channel::SetEngineInformation()");
1084 _engineStatisticsPtr = &engineStatistics;
1085 _outputMixerPtr = &outputMixer;
1086 _transmitMixerPtr = &transmitMixer,
1087 _moduleProcessThreadPtr = &moduleProcessThread;
1088 _audioDeviceModulePtr = &audioDeviceModule;
1089 _voiceEngineObserverPtr = voiceEngineObserver;
1090 _callbackCritSectPtr = callbackCritSect;
1091 return 0;
1092}
1093
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001094int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001095Channel::UpdateLocalTimeStamp()
1096{
1097
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001098 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 return 0;
1100}
1101
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001102int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001103Channel::StartPlayout()
1104{
1105 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1106 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001107 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 {
1109 return 0;
1110 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001111
1112 if (!_externalMixing) {
1113 // Add participant as candidates for mixing.
1114 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1115 {
1116 _engineStatisticsPtr->SetLastError(
1117 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1118 "StartPlayout() failed to add participant to mixer");
1119 return -1;
1120 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 }
1122
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001123 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001124 if (RegisterFilePlayingToMixer() != 0)
1125 return -1;
1126
niklase@google.com470e71d2011-07-07 08:21:25 +00001127 return 0;
1128}
1129
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001130int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001131Channel::StopPlayout()
1132{
1133 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1134 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001135 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 {
1137 return 0;
1138 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001139
1140 if (!_externalMixing) {
1141 // Remove participant as candidates for mixing
1142 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1143 {
1144 _engineStatisticsPtr->SetLastError(
1145 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1146 "StopPlayout() failed to remove participant from mixer");
1147 return -1;
1148 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 }
1150
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001151 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001152 _outputAudioLevel.Clear();
1153
1154 return 0;
1155}
1156
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001157int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001158Channel::StartSend()
1159{
1160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1161 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001162 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001163 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001164 if (send_sequence_number_)
1165 SetInitSequenceNumber(send_sequence_number_);
1166
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001167 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001168 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001169 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001171 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001172
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001173 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 {
1175 _engineStatisticsPtr->SetLastError(
1176 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1177 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001178 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001179 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001180 return -1;
1181 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001182
niklase@google.com470e71d2011-07-07 08:21:25 +00001183 return 0;
1184}
1185
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001186int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001187Channel::StopSend()
1188{
1189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1190 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001191 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001192 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001193 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001195 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001196
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001197 // Store the sequence number to be able to pick up the same sequence for
1198 // the next StartSend(). This is needed for restarting device, otherwise
1199 // it might cause libSRTP to complain about packets being replayed.
1200 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1201 // CL is landed. See issue
1202 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1203 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1204
niklase@google.com470e71d2011-07-07 08:21:25 +00001205 // Reset sending SSRC and sequence number and triggers direct transmission
1206 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001207 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1208 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 {
1210 _engineStatisticsPtr->SetLastError(
1211 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1212 "StartSend() RTP/RTCP failed to stop sending");
1213 }
1214
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 return 0;
1216}
1217
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001218int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001219Channel::StartReceiving()
1220{
1221 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1222 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001223 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 {
1225 return 0;
1226 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001227 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001228 _numberOfDiscardedPackets = 0;
1229 return 0;
1230}
1231
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001232int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001233Channel::StopReceiving()
1234{
1235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1236 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001237 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001238 {
1239 return 0;
1240 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001241
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 return 0;
1244}
1245
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001246int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001247Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1248{
1249 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1250 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001251 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001252
1253 if (_voiceEngineObserverPtr)
1254 {
1255 _engineStatisticsPtr->SetLastError(
1256 VE_INVALID_OPERATION, kTraceError,
1257 "RegisterVoiceEngineObserver() observer already enabled");
1258 return -1;
1259 }
1260 _voiceEngineObserverPtr = &observer;
1261 return 0;
1262}
1263
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001264int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001265Channel::DeRegisterVoiceEngineObserver()
1266{
1267 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1268 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001269 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001270
1271 if (!_voiceEngineObserverPtr)
1272 {
1273 _engineStatisticsPtr->SetLastError(
1274 VE_INVALID_OPERATION, kTraceWarning,
1275 "DeRegisterVoiceEngineObserver() observer already disabled");
1276 return 0;
1277 }
1278 _voiceEngineObserverPtr = NULL;
1279 return 0;
1280}
1281
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001282int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001283Channel::GetSendCodec(CodecInst& codec)
1284{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001285 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001286}
1287
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001288int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001289Channel::GetRecCodec(CodecInst& codec)
1290{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001291 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001292}
1293
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001294int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001295Channel::SetSendCodec(const CodecInst& codec)
1296{
1297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1298 "Channel::SetSendCodec()");
1299
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001300 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 {
1302 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1303 "SetSendCodec() failed to register codec to ACM");
1304 return -1;
1305 }
1306
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001307 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001309 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1310 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001311 {
1312 WEBRTC_TRACE(
1313 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1314 "SetSendCodec() failed to register codec to"
1315 " RTP/RTCP module");
1316 return -1;
1317 }
1318 }
1319
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001320 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001321 {
1322 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1323 "SetSendCodec() failed to set audio packet size");
1324 return -1;
1325 }
1326
1327 return 0;
1328}
1329
Ivo Creusenadf89b72015-04-29 16:03:33 +02001330void Channel::SetBitRate(int bitrate_bps) {
1331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1332 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1333 audio_coding_->SetBitRate(bitrate_bps);
1334}
1335
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001336void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001337 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001338 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1339
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001340 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001341 if (audio_coding_->SetPacketLossRate(
1342 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001343 assert(false); // This should not happen.
1344 }
1345}
1346
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001347int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001348Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1349{
1350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1351 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001352 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 // To disable VAD, DTX must be disabled too
1354 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001355 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001356 {
1357 _engineStatisticsPtr->SetLastError(
1358 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1359 "SetVADStatus() failed to set VAD");
1360 return -1;
1361 }
1362 return 0;
1363}
1364
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001365int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001366Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1367{
1368 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1369 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001370 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001371 {
1372 _engineStatisticsPtr->SetLastError(
1373 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1374 "GetVADStatus() failed to get VAD status");
1375 return -1;
1376 }
1377 disabledDTX = !disabledDTX;
1378 return 0;
1379}
1380
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001381int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001382Channel::SetRecPayloadType(const CodecInst& codec)
1383{
1384 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1385 "Channel::SetRecPayloadType()");
1386
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001387 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 {
1389 _engineStatisticsPtr->SetLastError(
1390 VE_ALREADY_PLAYING, kTraceError,
1391 "SetRecPayloadType() unable to set PT while playing");
1392 return -1;
1393 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001394 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 {
1396 _engineStatisticsPtr->SetLastError(
1397 VE_ALREADY_LISTENING, kTraceError,
1398 "SetRecPayloadType() unable to set PT while listening");
1399 return -1;
1400 }
1401
1402 if (codec.pltype == -1)
1403 {
1404 // De-register the selected codec (RTP/RTCP module and ACM)
1405
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001406 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 CodecInst rxCodec = codec;
1408
1409 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001410 rtp_payload_registry_->ReceivePayloadType(
1411 rxCodec.plname,
1412 rxCodec.plfreq,
1413 rxCodec.channels,
1414 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1415 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 rxCodec.pltype = pltype;
1417
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001418 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 {
1420 _engineStatisticsPtr->SetLastError(
1421 VE_RTP_RTCP_MODULE_ERROR,
1422 kTraceError,
1423 "SetRecPayloadType() RTP/RTCP-module deregistration "
1424 "failed");
1425 return -1;
1426 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001427 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001428 {
1429 _engineStatisticsPtr->SetLastError(
1430 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1431 "SetRecPayloadType() ACM deregistration failed - 1");
1432 return -1;
1433 }
1434 return 0;
1435 }
1436
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001437 if (rtp_receiver_->RegisterReceivePayload(
1438 codec.plname,
1439 codec.pltype,
1440 codec.plfreq,
1441 codec.channels,
1442 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001443 {
1444 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001445 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1446 if (rtp_receiver_->RegisterReceivePayload(
1447 codec.plname,
1448 codec.pltype,
1449 codec.plfreq,
1450 codec.channels,
1451 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
1453 _engineStatisticsPtr->SetLastError(
1454 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1455 "SetRecPayloadType() RTP/RTCP-module registration failed");
1456 return -1;
1457 }
1458 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001459 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001460 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001461 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1462 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001463 {
1464 _engineStatisticsPtr->SetLastError(
1465 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1466 "SetRecPayloadType() ACM registration failed - 1");
1467 return -1;
1468 }
1469 }
1470 return 0;
1471}
1472
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001473int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001474Channel::GetRecPayloadType(CodecInst& codec)
1475{
1476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1477 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001478 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001479 if (rtp_payload_registry_->ReceivePayloadType(
1480 codec.plname,
1481 codec.plfreq,
1482 codec.channels,
1483 (codec.rate < 0) ? 0 : codec.rate,
1484 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001485 {
1486 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001487 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001488 "GetRecPayloadType() failed to retrieve RX payload type");
1489 return -1;
1490 }
1491 codec.pltype = payloadType;
1492 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001493 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001494 return 0;
1495}
1496
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001497int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001498Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1499{
1500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1501 "Channel::SetSendCNPayloadType()");
1502
1503 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001504 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001505 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 if (frequency == kFreq32000Hz)
1507 samplingFreqHz = 32000;
1508 else if (frequency == kFreq16000Hz)
1509 samplingFreqHz = 16000;
1510
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001511 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001512 {
1513 _engineStatisticsPtr->SetLastError(
1514 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1515 "SetSendCNPayloadType() failed to retrieve default CN codec "
1516 "settings");
1517 return -1;
1518 }
1519
1520 // Modify the payload type (must be set to dynamic range)
1521 codec.pltype = type;
1522
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001523 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
1525 _engineStatisticsPtr->SetLastError(
1526 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1527 "SetSendCNPayloadType() failed to register CN to ACM");
1528 return -1;
1529 }
1530
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001531 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001532 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001533 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1534 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
1536 _engineStatisticsPtr->SetLastError(
1537 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1538 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1539 "module");
1540 return -1;
1541 }
1542 }
1543 return 0;
1544}
1545
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001546int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001548 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001549
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001550 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001551 _engineStatisticsPtr->SetLastError(
1552 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001553 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001554 return -1;
1555 }
1556 return 0;
1557}
1558
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001559int Channel::SetOpusDtx(bool enable_dtx) {
1560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1561 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001562 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001563 : audio_coding_->DisableOpusDtx();
1564 if (ret != 0) {
1565 _engineStatisticsPtr->SetLastError(
1566 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1567 return -1;
1568 }
1569 return 0;
1570}
1571
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001572int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001573{
1574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1575 "Channel::RegisterExternalTransport()");
1576
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001577 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001578
niklase@google.com470e71d2011-07-07 08:21:25 +00001579 if (_externalTransport)
1580 {
1581 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1582 kTraceError,
1583 "RegisterExternalTransport() external transport already enabled");
1584 return -1;
1585 }
1586 _externalTransport = true;
1587 _transportPtr = &transport;
1588 return 0;
1589}
1590
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001591int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001592Channel::DeRegisterExternalTransport()
1593{
1594 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1595 "Channel::DeRegisterExternalTransport()");
1596
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001597 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001598
niklase@google.com470e71d2011-07-07 08:21:25 +00001599 if (!_transportPtr)
1600 {
1601 _engineStatisticsPtr->SetLastError(
1602 VE_INVALID_OPERATION, kTraceWarning,
1603 "DeRegisterExternalTransport() external transport already "
1604 "disabled");
1605 return 0;
1606 }
1607 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001608 _transportPtr = NULL;
1609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1610 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001611 return 0;
1612}
1613
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001614int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001615 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001616 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1617 "Channel::ReceivedRTPPacket()");
1618
1619 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001620 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001621
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001622 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001623 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001624 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1625 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1626 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001627 return -1;
1628 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001629 header.payload_type_frequency =
1630 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001631 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001632 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001633 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001634 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001635 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001636 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001637
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001638 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001639}
1640
1641bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001642 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001643 const RTPHeader& header,
1644 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001645 if (rtp_payload_registry_->IsRtx(header)) {
1646 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001647 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001648 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001649 assert(packet_length >= header.headerLength);
1650 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001651 PayloadUnion payload_specific;
1652 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001653 &payload_specific)) {
1654 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001655 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001656 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1657 payload_specific, in_order);
1658}
1659
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001660bool Channel::HandleRtxPacket(const uint8_t* packet,
1661 size_t packet_length,
1662 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001663 if (!rtp_payload_registry_->IsRtx(header))
1664 return false;
1665
1666 // Remove the RTX header and parse the original RTP header.
1667 if (packet_length < header.headerLength)
1668 return false;
1669 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1670 return false;
1671 if (restored_packet_in_use_) {
1672 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1673 "Multiple RTX headers detected, dropping packet");
1674 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001675 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001676 uint8_t* restored_packet_ptr = restored_packet_;
1677 if (!rtp_payload_registry_->RestoreOriginalPacket(
1678 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1679 header)) {
1680 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1681 "Incoming RTX packet: invalid RTP header");
1682 return false;
1683 }
1684 restored_packet_in_use_ = true;
1685 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1686 restored_packet_in_use_ = false;
1687 return ret;
1688}
1689
1690bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1691 StreamStatistician* statistician =
1692 rtp_receive_statistics_->GetStatistician(header.ssrc);
1693 if (!statistician)
1694 return false;
1695 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001696}
1697
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001698bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1699 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001700 // Retransmissions are handled separately if RTX is enabled.
1701 if (rtp_payload_registry_->RtxEnabled())
1702 return false;
1703 StreamStatistician* statistician =
1704 rtp_receive_statistics_->GetStatistician(header.ssrc);
1705 if (!statistician)
1706 return false;
1707 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001708 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001709 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001710 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001711 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001712}
1713
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001714int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001715 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1716 "Channel::ReceivedRTCPPacket()");
1717 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001718 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001719
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001720 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001721 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001722 _engineStatisticsPtr->SetLastError(
1723 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1724 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1725 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001726
Minyue2013aec2015-05-13 14:14:42 +02001727 int64_t rtt = GetRTT(true);
1728 if (rtt == 0) {
1729 // Waiting for valid RTT.
1730 return 0;
1731 }
1732 uint32_t ntp_secs = 0;
1733 uint32_t ntp_frac = 0;
1734 uint32_t rtp_timestamp = 0;
1735 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1736 &rtp_timestamp)) {
1737 // Waiting for RTCP.
1738 return 0;
1739 }
1740
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001741 {
1742 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001743 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001744 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001745 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001746}
1747
niklase@google.com470e71d2011-07-07 08:21:25 +00001748int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001749 bool loop,
1750 FileFormats format,
1751 int startPosition,
1752 float volumeScaling,
1753 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001754 const CodecInst* codecInst)
1755{
1756 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1757 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1758 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1759 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1760 startPosition, stopPosition);
1761
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001762 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 {
1764 _engineStatisticsPtr->SetLastError(
1765 VE_ALREADY_PLAYING, kTraceError,
1766 "StartPlayingFileLocally() is already playing");
1767 return -1;
1768 }
1769
niklase@google.com470e71d2011-07-07 08:21:25 +00001770 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001771 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001772
1773 if (_outputFilePlayerPtr)
1774 {
1775 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1776 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1777 _outputFilePlayerPtr = NULL;
1778 }
1779
1780 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1781 _outputFilePlayerId, (const FileFormats)format);
1782
1783 if (_outputFilePlayerPtr == NULL)
1784 {
1785 _engineStatisticsPtr->SetLastError(
1786 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001787 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001788 return -1;
1789 }
1790
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001791 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001792
1793 if (_outputFilePlayerPtr->StartPlayingFile(
1794 fileName,
1795 loop,
1796 startPosition,
1797 volumeScaling,
1798 notificationTime,
1799 stopPosition,
1800 (const CodecInst*)codecInst) != 0)
1801 {
1802 _engineStatisticsPtr->SetLastError(
1803 VE_BAD_FILE, kTraceError,
1804 "StartPlayingFile() failed to start file playout");
1805 _outputFilePlayerPtr->StopPlayingFile();
1806 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1807 _outputFilePlayerPtr = NULL;
1808 return -1;
1809 }
1810 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001811 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001812 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001813
1814 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001815 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001816
1817 return 0;
1818}
1819
1820int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001821 FileFormats format,
1822 int startPosition,
1823 float volumeScaling,
1824 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001825 const CodecInst* codecInst)
1826{
1827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1828 "Channel::StartPlayingFileLocally(format=%d,"
1829 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1830 format, volumeScaling, startPosition, stopPosition);
1831
1832 if(stream == NULL)
1833 {
1834 _engineStatisticsPtr->SetLastError(
1835 VE_BAD_FILE, kTraceError,
1836 "StartPlayingFileLocally() NULL as input stream");
1837 return -1;
1838 }
1839
1840
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001841 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001842 {
1843 _engineStatisticsPtr->SetLastError(
1844 VE_ALREADY_PLAYING, kTraceError,
1845 "StartPlayingFileLocally() is already playing");
1846 return -1;
1847 }
1848
niklase@google.com470e71d2011-07-07 08:21:25 +00001849 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001850 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001851
1852 // Destroy the old instance
1853 if (_outputFilePlayerPtr)
1854 {
1855 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1856 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1857 _outputFilePlayerPtr = NULL;
1858 }
1859
1860 // Create the instance
1861 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1862 _outputFilePlayerId,
1863 (const FileFormats)format);
1864
1865 if (_outputFilePlayerPtr == NULL)
1866 {
1867 _engineStatisticsPtr->SetLastError(
1868 VE_INVALID_ARGUMENT, kTraceError,
1869 "StartPlayingFileLocally() filePlayer format isnot correct");
1870 return -1;
1871 }
1872
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001873 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001874
1875 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1876 volumeScaling,
1877 notificationTime,
1878 stopPosition, codecInst) != 0)
1879 {
1880 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1881 "StartPlayingFile() failed to "
1882 "start file playout");
1883 _outputFilePlayerPtr->StopPlayingFile();
1884 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1885 _outputFilePlayerPtr = NULL;
1886 return -1;
1887 }
1888 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001889 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001890 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001891
1892 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001893 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001894
niklase@google.com470e71d2011-07-07 08:21:25 +00001895 return 0;
1896}
1897
1898int Channel::StopPlayingFileLocally()
1899{
1900 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1901 "Channel::StopPlayingFileLocally()");
1902
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001903 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001904 {
1905 _engineStatisticsPtr->SetLastError(
1906 VE_INVALID_OPERATION, kTraceWarning,
1907 "StopPlayingFileLocally() isnot playing");
1908 return 0;
1909 }
1910
niklase@google.com470e71d2011-07-07 08:21:25 +00001911 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001912 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001913
1914 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1915 {
1916 _engineStatisticsPtr->SetLastError(
1917 VE_STOP_RECORDING_FAILED, kTraceError,
1918 "StopPlayingFile() could not stop playing");
1919 return -1;
1920 }
1921 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1922 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1923 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001924 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001925 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001926 // _fileCritSect cannot be taken while calling
1927 // SetAnonymousMixibilityStatus. Refer to comments in
1928 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001929 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1930 {
1931 _engineStatisticsPtr->SetLastError(
1932 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001933 "StopPlayingFile() failed to stop participant from playing as"
1934 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001935 return -1;
1936 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001937
1938 return 0;
1939}
1940
1941int Channel::IsPlayingFileLocally() const
1942{
1943 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1944 "Channel::IsPlayingFileLocally()");
1945
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001946 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001947}
1948
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001949int Channel::RegisterFilePlayingToMixer()
1950{
1951 // Return success for not registering for file playing to mixer if:
1952 // 1. playing file before playout is started on that channel.
1953 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001954 if (!channel_state_.Get().playing ||
1955 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001956 {
1957 return 0;
1958 }
1959
1960 // |_fileCritSect| cannot be taken while calling
1961 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1962 // frames can be pulled by the mixer. Since the frames are generated from
1963 // the file, _fileCritSect will be taken. This would result in a deadlock.
1964 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1965 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001966 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001967 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001968 _engineStatisticsPtr->SetLastError(
1969 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1970 "StartPlayingFile() failed to add participant as file to mixer");
1971 _outputFilePlayerPtr->StopPlayingFile();
1972 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1973 _outputFilePlayerPtr = NULL;
1974 return -1;
1975 }
1976
1977 return 0;
1978}
1979
niklase@google.com470e71d2011-07-07 08:21:25 +00001980int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001981 bool loop,
1982 FileFormats format,
1983 int startPosition,
1984 float volumeScaling,
1985 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001986 const CodecInst* codecInst)
1987{
1988 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1989 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1990 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1991 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1992 startPosition, stopPosition);
1993
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001994 CriticalSectionScoped cs(&_fileCritSect);
1995
1996 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001997 {
1998 _engineStatisticsPtr->SetLastError(
1999 VE_ALREADY_PLAYING, kTraceWarning,
2000 "StartPlayingFileAsMicrophone() filePlayer is playing");
2001 return 0;
2002 }
2003
niklase@google.com470e71d2011-07-07 08:21:25 +00002004 // Destroy the old instance
2005 if (_inputFilePlayerPtr)
2006 {
2007 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2008 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2009 _inputFilePlayerPtr = NULL;
2010 }
2011
2012 // Create the instance
2013 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2014 _inputFilePlayerId, (const FileFormats)format);
2015
2016 if (_inputFilePlayerPtr == NULL)
2017 {
2018 _engineStatisticsPtr->SetLastError(
2019 VE_INVALID_ARGUMENT, kTraceError,
2020 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2021 return -1;
2022 }
2023
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002024 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002025
2026 if (_inputFilePlayerPtr->StartPlayingFile(
2027 fileName,
2028 loop,
2029 startPosition,
2030 volumeScaling,
2031 notificationTime,
2032 stopPosition,
2033 (const CodecInst*)codecInst) != 0)
2034 {
2035 _engineStatisticsPtr->SetLastError(
2036 VE_BAD_FILE, kTraceError,
2037 "StartPlayingFile() failed to start file playout");
2038 _inputFilePlayerPtr->StopPlayingFile();
2039 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2040 _inputFilePlayerPtr = NULL;
2041 return -1;
2042 }
2043 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002044 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002045
2046 return 0;
2047}
2048
2049int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002050 FileFormats format,
2051 int startPosition,
2052 float volumeScaling,
2053 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002054 const CodecInst* codecInst)
2055{
2056 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2057 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2058 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2059 format, volumeScaling, startPosition, stopPosition);
2060
2061 if(stream == NULL)
2062 {
2063 _engineStatisticsPtr->SetLastError(
2064 VE_BAD_FILE, kTraceError,
2065 "StartPlayingFileAsMicrophone NULL as input stream");
2066 return -1;
2067 }
2068
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002069 CriticalSectionScoped cs(&_fileCritSect);
2070
2071 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002072 {
2073 _engineStatisticsPtr->SetLastError(
2074 VE_ALREADY_PLAYING, kTraceWarning,
2075 "StartPlayingFileAsMicrophone() is playing");
2076 return 0;
2077 }
2078
niklase@google.com470e71d2011-07-07 08:21:25 +00002079 // Destroy the old instance
2080 if (_inputFilePlayerPtr)
2081 {
2082 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2083 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2084 _inputFilePlayerPtr = NULL;
2085 }
2086
2087 // Create the instance
2088 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2089 _inputFilePlayerId, (const FileFormats)format);
2090
2091 if (_inputFilePlayerPtr == NULL)
2092 {
2093 _engineStatisticsPtr->SetLastError(
2094 VE_INVALID_ARGUMENT, kTraceError,
2095 "StartPlayingInputFile() filePlayer format isnot correct");
2096 return -1;
2097 }
2098
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002099 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002100
2101 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2102 volumeScaling, notificationTime,
2103 stopPosition, codecInst) != 0)
2104 {
2105 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2106 "StartPlayingFile() failed to start "
2107 "file playout");
2108 _inputFilePlayerPtr->StopPlayingFile();
2109 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2110 _inputFilePlayerPtr = NULL;
2111 return -1;
2112 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002113
niklase@google.com470e71d2011-07-07 08:21:25 +00002114 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002115 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002116
2117 return 0;
2118}
2119
2120int Channel::StopPlayingFileAsMicrophone()
2121{
2122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2123 "Channel::StopPlayingFileAsMicrophone()");
2124
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002125 CriticalSectionScoped cs(&_fileCritSect);
2126
2127 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002128 {
2129 _engineStatisticsPtr->SetLastError(
2130 VE_INVALID_OPERATION, kTraceWarning,
2131 "StopPlayingFileAsMicrophone() isnot playing");
2132 return 0;
2133 }
2134
niklase@google.com470e71d2011-07-07 08:21:25 +00002135 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2136 {
2137 _engineStatisticsPtr->SetLastError(
2138 VE_STOP_RECORDING_FAILED, kTraceError,
2139 "StopPlayingFile() could not stop playing");
2140 return -1;
2141 }
2142 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2143 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2144 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002145 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002146
2147 return 0;
2148}
2149
2150int Channel::IsPlayingFileAsMicrophone() const
2151{
2152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2153 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002154 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002155}
2156
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002157int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002158 const CodecInst* codecInst)
2159{
2160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2161 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2162
2163 if (_outputFileRecording)
2164 {
2165 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2166 "StartRecordingPlayout() is already recording");
2167 return 0;
2168 }
2169
2170 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002171 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002172 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2173
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002174 if ((codecInst != NULL) &&
2175 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002176 {
2177 _engineStatisticsPtr->SetLastError(
2178 VE_BAD_ARGUMENT, kTraceError,
2179 "StartRecordingPlayout() invalid compression");
2180 return(-1);
2181 }
2182 if(codecInst == NULL)
2183 {
2184 format = kFileFormatPcm16kHzFile;
2185 codecInst=&dummyCodec;
2186 }
2187 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2188 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2189 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2190 {
2191 format = kFileFormatWavFile;
2192 }
2193 else
2194 {
2195 format = kFileFormatCompressedFile;
2196 }
2197
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002198 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002199
2200 // Destroy the old instance
2201 if (_outputFileRecorderPtr)
2202 {
2203 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2204 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2205 _outputFileRecorderPtr = NULL;
2206 }
2207
2208 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2209 _outputFileRecorderId, (const FileFormats)format);
2210 if (_outputFileRecorderPtr == NULL)
2211 {
2212 _engineStatisticsPtr->SetLastError(
2213 VE_INVALID_ARGUMENT, kTraceError,
2214 "StartRecordingPlayout() fileRecorder format isnot correct");
2215 return -1;
2216 }
2217
2218 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2219 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2220 {
2221 _engineStatisticsPtr->SetLastError(
2222 VE_BAD_FILE, kTraceError,
2223 "StartRecordingAudioFile() failed to start file recording");
2224 _outputFileRecorderPtr->StopRecording();
2225 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2226 _outputFileRecorderPtr = NULL;
2227 return -1;
2228 }
2229 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2230 _outputFileRecording = true;
2231
2232 return 0;
2233}
2234
2235int Channel::StartRecordingPlayout(OutStream* stream,
2236 const CodecInst* codecInst)
2237{
2238 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2239 "Channel::StartRecordingPlayout()");
2240
2241 if (_outputFileRecording)
2242 {
2243 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2244 "StartRecordingPlayout() is already recording");
2245 return 0;
2246 }
2247
2248 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002249 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002250 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2251
2252 if (codecInst != NULL && codecInst->channels != 1)
2253 {
2254 _engineStatisticsPtr->SetLastError(
2255 VE_BAD_ARGUMENT, kTraceError,
2256 "StartRecordingPlayout() invalid compression");
2257 return(-1);
2258 }
2259 if(codecInst == NULL)
2260 {
2261 format = kFileFormatPcm16kHzFile;
2262 codecInst=&dummyCodec;
2263 }
2264 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2265 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2266 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2267 {
2268 format = kFileFormatWavFile;
2269 }
2270 else
2271 {
2272 format = kFileFormatCompressedFile;
2273 }
2274
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002275 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002276
2277 // Destroy the old instance
2278 if (_outputFileRecorderPtr)
2279 {
2280 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2281 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2282 _outputFileRecorderPtr = NULL;
2283 }
2284
2285 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2286 _outputFileRecorderId, (const FileFormats)format);
2287 if (_outputFileRecorderPtr == NULL)
2288 {
2289 _engineStatisticsPtr->SetLastError(
2290 VE_INVALID_ARGUMENT, kTraceError,
2291 "StartRecordingPlayout() fileRecorder format isnot correct");
2292 return -1;
2293 }
2294
2295 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2296 notificationTime) != 0)
2297 {
2298 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2299 "StartRecordingPlayout() failed to "
2300 "start file recording");
2301 _outputFileRecorderPtr->StopRecording();
2302 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2303 _outputFileRecorderPtr = NULL;
2304 return -1;
2305 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002306
niklase@google.com470e71d2011-07-07 08:21:25 +00002307 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2308 _outputFileRecording = true;
2309
2310 return 0;
2311}
2312
2313int Channel::StopRecordingPlayout()
2314{
2315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2316 "Channel::StopRecordingPlayout()");
2317
2318 if (!_outputFileRecording)
2319 {
2320 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2321 "StopRecordingPlayout() isnot recording");
2322 return -1;
2323 }
2324
2325
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002326 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002327
2328 if (_outputFileRecorderPtr->StopRecording() != 0)
2329 {
2330 _engineStatisticsPtr->SetLastError(
2331 VE_STOP_RECORDING_FAILED, kTraceError,
2332 "StopRecording() could not stop recording");
2333 return(-1);
2334 }
2335 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2336 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2337 _outputFileRecorderPtr = NULL;
2338 _outputFileRecording = false;
2339
2340 return 0;
2341}
2342
2343void
2344Channel::SetMixWithMicStatus(bool mix)
2345{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002346 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002347 _mixFileWithMicrophone=mix;
2348}
2349
2350int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002351Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002352{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002353 int8_t currentLevel = _outputAudioLevel.Level();
2354 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002355 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2356 VoEId(_instanceId,_channelId),
2357 "GetSpeechOutputLevel() => level=%u", level);
2358 return 0;
2359}
2360
2361int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002362Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002363{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002364 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2365 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002366 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2367 VoEId(_instanceId,_channelId),
2368 "GetSpeechOutputLevelFullRange() => level=%u", level);
2369 return 0;
2370}
2371
2372int
2373Channel::SetMute(bool enable)
2374{
wu@webrtc.org63420662013-10-17 18:28:55 +00002375 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2377 "Channel::SetMute(enable=%d)", enable);
2378 _mute = enable;
2379 return 0;
2380}
2381
2382bool
2383Channel::Mute() const
2384{
wu@webrtc.org63420662013-10-17 18:28:55 +00002385 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002386 return _mute;
2387}
2388
2389int
2390Channel::SetOutputVolumePan(float left, float right)
2391{
wu@webrtc.org63420662013-10-17 18:28:55 +00002392 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002393 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2394 "Channel::SetOutputVolumePan()");
2395 _panLeft = left;
2396 _panRight = right;
2397 return 0;
2398}
2399
2400int
2401Channel::GetOutputVolumePan(float& left, float& right) const
2402{
wu@webrtc.org63420662013-10-17 18:28:55 +00002403 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002404 left = _panLeft;
2405 right = _panRight;
2406 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2407 VoEId(_instanceId,_channelId),
2408 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2409 return 0;
2410}
2411
2412int
2413Channel::SetChannelOutputVolumeScaling(float scaling)
2414{
wu@webrtc.org63420662013-10-17 18:28:55 +00002415 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2417 "Channel::SetChannelOutputVolumeScaling()");
2418 _outputGain = scaling;
2419 return 0;
2420}
2421
2422int
2423Channel::GetChannelOutputVolumeScaling(float& scaling) const
2424{
wu@webrtc.org63420662013-10-17 18:28:55 +00002425 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002426 scaling = _outputGain;
2427 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2428 VoEId(_instanceId,_channelId),
2429 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2430 return 0;
2431}
2432
niklase@google.com470e71d2011-07-07 08:21:25 +00002433int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002434 int lengthMs, int attenuationDb,
2435 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002436{
2437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2438 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2439 playDtmfEvent);
2440
2441 _playOutbandDtmfEvent = playDtmfEvent;
2442
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002443 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002444 attenuationDb) != 0)
2445 {
2446 _engineStatisticsPtr->SetLastError(
2447 VE_SEND_DTMF_FAILED,
2448 kTraceWarning,
2449 "SendTelephoneEventOutband() failed to send event");
2450 return -1;
2451 }
2452 return 0;
2453}
2454
2455int Channel::SendTelephoneEventInband(unsigned char eventCode,
2456 int lengthMs,
2457 int attenuationDb,
2458 bool playDtmfEvent)
2459{
2460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2461 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2462 playDtmfEvent);
2463
2464 _playInbandDtmfEvent = playDtmfEvent;
2465 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2466
2467 return 0;
2468}
2469
2470int
niklase@google.com470e71d2011-07-07 08:21:25 +00002471Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2472{
2473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2474 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002475 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 {
2477 _engineStatisticsPtr->SetLastError(
2478 VE_INVALID_ARGUMENT, kTraceError,
2479 "SetSendTelephoneEventPayloadType() invalid type");
2480 return -1;
2481 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002482 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002483 codec.plfreq = 8000;
2484 codec.pltype = type;
2485 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002486 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002487 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002488 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2489 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2490 _engineStatisticsPtr->SetLastError(
2491 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2492 "SetSendTelephoneEventPayloadType() failed to register send"
2493 "payload type");
2494 return -1;
2495 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002496 }
2497 _sendTelephoneEventPayloadType = type;
2498 return 0;
2499}
2500
2501int
2502Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2503{
2504 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2505 "Channel::GetSendTelephoneEventPayloadType()");
2506 type = _sendTelephoneEventPayloadType;
2507 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2508 VoEId(_instanceId,_channelId),
2509 "GetSendTelephoneEventPayloadType() => type=%u", type);
2510 return 0;
2511}
2512
niklase@google.com470e71d2011-07-07 08:21:25 +00002513int
2514Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2515{
2516 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2517 "Channel::UpdateRxVadDetection()");
2518
2519 int vadDecision = 1;
2520
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002521 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002522
2523 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2524 {
2525 OnRxVadDetected(vadDecision);
2526 _oldVadDecision = vadDecision;
2527 }
2528
2529 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2530 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2531 vadDecision);
2532 return 0;
2533}
2534
2535int
2536Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2537{
2538 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2539 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002540 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002541
2542 if (_rxVadObserverPtr)
2543 {
2544 _engineStatisticsPtr->SetLastError(
2545 VE_INVALID_OPERATION, kTraceError,
2546 "RegisterRxVadObserver() observer already enabled");
2547 return -1;
2548 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002549 _rxVadObserverPtr = &observer;
2550 _RxVadDetection = true;
2551 return 0;
2552}
2553
2554int
2555Channel::DeRegisterRxVadObserver()
2556{
2557 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2558 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002559 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002560
2561 if (!_rxVadObserverPtr)
2562 {
2563 _engineStatisticsPtr->SetLastError(
2564 VE_INVALID_OPERATION, kTraceWarning,
2565 "DeRegisterRxVadObserver() observer already disabled");
2566 return 0;
2567 }
2568 _rxVadObserverPtr = NULL;
2569 _RxVadDetection = false;
2570 return 0;
2571}
2572
2573int
2574Channel::VoiceActivityIndicator(int &activity)
2575{
2576 activity = _sendFrameType;
2577
2578 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002579 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002580 return 0;
2581}
2582
2583#ifdef WEBRTC_VOICE_ENGINE_AGC
2584
2585int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002586Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002587{
2588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2589 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2590 (int)enable, (int)mode);
2591
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002592 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002593 switch (mode)
2594 {
2595 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002596 break;
2597 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002598 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002599 break;
2600 case kAgcFixedDigital:
2601 agcMode = GainControl::kFixedDigital;
2602 break;
2603 case kAgcAdaptiveDigital:
2604 agcMode =GainControl::kAdaptiveDigital;
2605 break;
2606 default:
2607 _engineStatisticsPtr->SetLastError(
2608 VE_INVALID_ARGUMENT, kTraceError,
2609 "SetRxAgcStatus() invalid Agc mode");
2610 return -1;
2611 }
2612
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002613 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002614 {
2615 _engineStatisticsPtr->SetLastError(
2616 VE_APM_ERROR, kTraceError,
2617 "SetRxAgcStatus() failed to set Agc mode");
2618 return -1;
2619 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002620 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002621 {
2622 _engineStatisticsPtr->SetLastError(
2623 VE_APM_ERROR, kTraceError,
2624 "SetRxAgcStatus() failed to set Agc state");
2625 return -1;
2626 }
2627
2628 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002629 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002630
2631 return 0;
2632}
2633
2634int
2635Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2636{
2637 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2638 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2639
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002640 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002641 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002642 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002643
2644 enabled = enable;
2645
2646 switch (agcMode)
2647 {
2648 case GainControl::kFixedDigital:
2649 mode = kAgcFixedDigital;
2650 break;
2651 case GainControl::kAdaptiveDigital:
2652 mode = kAgcAdaptiveDigital;
2653 break;
2654 default:
2655 _engineStatisticsPtr->SetLastError(
2656 VE_APM_ERROR, kTraceError,
2657 "GetRxAgcStatus() invalid Agc mode");
2658 return -1;
2659 }
2660
2661 return 0;
2662}
2663
2664int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002665Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002666{
2667 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2668 "Channel::SetRxAgcConfig()");
2669
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002670 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002671 config.targetLeveldBOv) != 0)
2672 {
2673 _engineStatisticsPtr->SetLastError(
2674 VE_APM_ERROR, kTraceError,
2675 "SetRxAgcConfig() failed to set target peak |level|"
2676 "(or envelope) of the Agc");
2677 return -1;
2678 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002679 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 config.digitalCompressionGaindB) != 0)
2681 {
2682 _engineStatisticsPtr->SetLastError(
2683 VE_APM_ERROR, kTraceError,
2684 "SetRxAgcConfig() failed to set the range in |gain| the"
2685 " digital compression stage may apply");
2686 return -1;
2687 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002688 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002689 config.limiterEnable) != 0)
2690 {
2691 _engineStatisticsPtr->SetLastError(
2692 VE_APM_ERROR, kTraceError,
2693 "SetRxAgcConfig() failed to set hard limiter to the signal");
2694 return -1;
2695 }
2696
2697 return 0;
2698}
2699
2700int
2701Channel::GetRxAgcConfig(AgcConfig& config)
2702{
2703 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2704 "Channel::GetRxAgcConfig(config=%?)");
2705
2706 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002707 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002708 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002709 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002710 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002711 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002712
2713 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2714 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2715 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2716 " limiterEnable=%d",
2717 config.targetLeveldBOv,
2718 config.digitalCompressionGaindB,
2719 config.limiterEnable);
2720
2721 return 0;
2722}
2723
2724#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2725
2726#ifdef WEBRTC_VOICE_ENGINE_NR
2727
2728int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002729Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002730{
2731 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2732 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2733 (int)enable, (int)mode);
2734
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002735 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002736 switch (mode)
2737 {
2738
2739 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002740 break;
2741 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002742 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002743 break;
2744 case kNsConference:
2745 nsLevel = NoiseSuppression::kHigh;
2746 break;
2747 case kNsLowSuppression:
2748 nsLevel = NoiseSuppression::kLow;
2749 break;
2750 case kNsModerateSuppression:
2751 nsLevel = NoiseSuppression::kModerate;
2752 break;
2753 case kNsHighSuppression:
2754 nsLevel = NoiseSuppression::kHigh;
2755 break;
2756 case kNsVeryHighSuppression:
2757 nsLevel = NoiseSuppression::kVeryHigh;
2758 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002759 }
2760
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002761 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 != 0)
2763 {
2764 _engineStatisticsPtr->SetLastError(
2765 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002766 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002767 return -1;
2768 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002769 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002770 {
2771 _engineStatisticsPtr->SetLastError(
2772 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002773 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002774 return -1;
2775 }
2776
2777 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002778 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002779
2780 return 0;
2781}
2782
2783int
2784Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2785{
2786 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2787 "Channel::GetRxNsStatus(enable=?, mode=?)");
2788
2789 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002790 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002791 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002792 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002793
2794 enabled = enable;
2795
2796 switch (ncLevel)
2797 {
2798 case NoiseSuppression::kLow:
2799 mode = kNsLowSuppression;
2800 break;
2801 case NoiseSuppression::kModerate:
2802 mode = kNsModerateSuppression;
2803 break;
2804 case NoiseSuppression::kHigh:
2805 mode = kNsHighSuppression;
2806 break;
2807 case NoiseSuppression::kVeryHigh:
2808 mode = kNsVeryHighSuppression;
2809 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002810 }
2811
2812 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2813 VoEId(_instanceId,_channelId),
2814 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2815 return 0;
2816}
2817
2818#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2819
2820int
niklase@google.com470e71d2011-07-07 08:21:25 +00002821Channel::SetLocalSSRC(unsigned int ssrc)
2822{
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2824 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002825 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002826 {
2827 _engineStatisticsPtr->SetLastError(
2828 VE_ALREADY_SENDING, kTraceError,
2829 "SetLocalSSRC() already sending");
2830 return -1;
2831 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002832 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002833 return 0;
2834}
2835
2836int
2837Channel::GetLocalSSRC(unsigned int& ssrc)
2838{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002839 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002840 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2841 VoEId(_instanceId,_channelId),
2842 "GetLocalSSRC() => ssrc=%lu", ssrc);
2843 return 0;
2844}
2845
2846int
2847Channel::GetRemoteSSRC(unsigned int& ssrc)
2848{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002849 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002850 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2851 VoEId(_instanceId,_channelId),
2852 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2853 return 0;
2854}
2855
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002856int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002857 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002858 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002859}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002860
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002861int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2862 unsigned char id) {
2863 rtp_header_parser_->DeregisterRtpHeaderExtension(
2864 kRtpExtensionAudioLevel);
2865 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2866 kRtpExtensionAudioLevel, id)) {
2867 return -1;
2868 }
2869 return 0;
2870}
2871
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002872int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2873 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2874}
2875
2876int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2877 rtp_header_parser_->DeregisterRtpHeaderExtension(
2878 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002879 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2880 kRtpExtensionAbsoluteSendTime, id)) {
2881 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002882 }
2883 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002884}
2885
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002886void Channel::SetRTCPStatus(bool enable) {
2887 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2888 "Channel::SetRTCPStatus()");
2889 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002890}
2891
2892int
2893Channel::GetRTCPStatus(bool& enabled)
2894{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002895 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002896 enabled = (method != kRtcpOff);
2897 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2898 VoEId(_instanceId,_channelId),
2899 "GetRTCPStatus() => enabled=%d", enabled);
2900 return 0;
2901}
2902
2903int
2904Channel::SetRTCP_CNAME(const char cName[256])
2905{
2906 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2907 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002908 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002909 {
2910 _engineStatisticsPtr->SetLastError(
2911 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2912 "SetRTCP_CNAME() failed to set RTCP CNAME");
2913 return -1;
2914 }
2915 return 0;
2916}
2917
2918int
niklase@google.com470e71d2011-07-07 08:21:25 +00002919Channel::GetRemoteRTCP_CNAME(char cName[256])
2920{
2921 if (cName == NULL)
2922 {
2923 _engineStatisticsPtr->SetLastError(
2924 VE_INVALID_ARGUMENT, kTraceError,
2925 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2926 return -1;
2927 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002928 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002929 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002930 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002931 {
2932 _engineStatisticsPtr->SetLastError(
2933 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2934 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2935 return -1;
2936 }
2937 strcpy(cName, cname);
2938 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2939 VoEId(_instanceId, _channelId),
2940 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2941 return 0;
2942}
2943
2944int
2945Channel::GetRemoteRTCPData(
2946 unsigned int& NTPHigh,
2947 unsigned int& NTPLow,
2948 unsigned int& timestamp,
2949 unsigned int& playoutTimestamp,
2950 unsigned int* jitter,
2951 unsigned short* fractionLost)
2952{
2953 // --- Information from sender info in received Sender Reports
2954
2955 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002956 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002957 {
2958 _engineStatisticsPtr->SetLastError(
2959 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002960 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002961 "side");
2962 return -1;
2963 }
2964
2965 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2966 // and octet count)
2967 NTPHigh = senderInfo.NTPseconds;
2968 NTPLow = senderInfo.NTPfraction;
2969 timestamp = senderInfo.RTPtimeStamp;
2970
2971 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2972 VoEId(_instanceId, _channelId),
2973 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2974 "timestamp=%lu",
2975 NTPHigh, NTPLow, timestamp);
2976
2977 // --- Locally derived information
2978
2979 // This value is updated on each incoming RTCP packet (0 when no packet
2980 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002981 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002982
2983 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2984 VoEId(_instanceId, _channelId),
2985 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002986 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002987
2988 if (NULL != jitter || NULL != fractionLost)
2989 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002990 // Get all RTCP receiver report blocks that have been received on this
2991 // channel. If we receive RTP packets from a remote source we know the
2992 // remote SSRC and use the report block from him.
2993 // Otherwise use the first report block.
2994 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002995 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002996 remote_stats.empty()) {
2997 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2998 VoEId(_instanceId, _channelId),
2999 "GetRemoteRTCPData() failed to measure statistics due"
3000 " to lack of received RTP and/or RTCP packets");
3001 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003002 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003003
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003004 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003005 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3006 for (; it != remote_stats.end(); ++it) {
3007 if (it->remoteSSRC == remoteSSRC)
3008 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003009 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003010
3011 if (it == remote_stats.end()) {
3012 // If we have not received any RTCP packets from this SSRC it probably
3013 // means that we have not received any RTP packets.
3014 // Use the first received report block instead.
3015 it = remote_stats.begin();
3016 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003017 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003018
xians@webrtc.org79af7342012-01-31 12:22:14 +00003019 if (jitter) {
3020 *jitter = it->jitter;
3021 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3022 VoEId(_instanceId, _channelId),
3023 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3024 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003025
xians@webrtc.org79af7342012-01-31 12:22:14 +00003026 if (fractionLost) {
3027 *fractionLost = it->fractionLost;
3028 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3029 VoEId(_instanceId, _channelId),
3030 "GetRemoteRTCPData() => fractionLost = %lu",
3031 *fractionLost);
3032 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003033 }
3034 return 0;
3035}
3036
3037int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003038Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003039 unsigned int name,
3040 const char* data,
3041 unsigned short dataLengthInBytes)
3042{
3043 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3044 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003045 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003046 {
3047 _engineStatisticsPtr->SetLastError(
3048 VE_NOT_SENDING, kTraceError,
3049 "SendApplicationDefinedRTCPPacket() not sending");
3050 return -1;
3051 }
3052 if (NULL == data)
3053 {
3054 _engineStatisticsPtr->SetLastError(
3055 VE_INVALID_ARGUMENT, kTraceError,
3056 "SendApplicationDefinedRTCPPacket() invalid data value");
3057 return -1;
3058 }
3059 if (dataLengthInBytes % 4 != 0)
3060 {
3061 _engineStatisticsPtr->SetLastError(
3062 VE_INVALID_ARGUMENT, kTraceError,
3063 "SendApplicationDefinedRTCPPacket() invalid length value");
3064 return -1;
3065 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003066 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003067 if (status == kRtcpOff)
3068 {
3069 _engineStatisticsPtr->SetLastError(
3070 VE_RTCP_ERROR, kTraceError,
3071 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3072 return -1;
3073 }
3074
3075 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003076 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003077 subType,
3078 name,
3079 (const unsigned char*) data,
3080 dataLengthInBytes) != 0)
3081 {
3082 _engineStatisticsPtr->SetLastError(
3083 VE_SEND_ERROR, kTraceError,
3084 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3085 return -1;
3086 }
3087 return 0;
3088}
3089
3090int
3091Channel::GetRTPStatistics(
3092 unsigned int& averageJitterMs,
3093 unsigned int& maxJitterMs,
3094 unsigned int& discardedPackets)
3095{
niklase@google.com470e71d2011-07-07 08:21:25 +00003096 // The jitter statistics is updated for each received RTP packet and is
3097 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003098 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3099 // If RTCP is off, there is no timed thread in the RTCP module regularly
3100 // generating new stats, trigger the update manually here instead.
3101 StreamStatistician* statistician =
3102 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3103 if (statistician) {
3104 // Don't use returned statistics, use data from proxy instead so that
3105 // max jitter can be fetched atomically.
3106 RtcpStatistics s;
3107 statistician->GetStatistics(&s, true);
3108 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003109 }
3110
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003111 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003112 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003113 if (playoutFrequency > 0) {
3114 // Scale RTP statistics given the current playout frequency
3115 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3116 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003117 }
3118
3119 discardedPackets = _numberOfDiscardedPackets;
3120
3121 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3122 VoEId(_instanceId, _channelId),
3123 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003124 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 averageJitterMs, maxJitterMs, discardedPackets);
3126 return 0;
3127}
3128
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003129int Channel::GetRemoteRTCPReportBlocks(
3130 std::vector<ReportBlock>* report_blocks) {
3131 if (report_blocks == NULL) {
3132 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3133 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3134 return -1;
3135 }
3136
3137 // Get the report blocks from the latest received RTCP Sender or Receiver
3138 // Report. Each element in the vector contains the sender's SSRC and a
3139 // report block according to RFC 3550.
3140 std::vector<RTCPReportBlock> rtcp_report_blocks;
3141 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3142 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3143 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3144 return -1;
3145 }
3146
3147 if (rtcp_report_blocks.empty())
3148 return 0;
3149
3150 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3151 for (; it != rtcp_report_blocks.end(); ++it) {
3152 ReportBlock report_block;
3153 report_block.sender_SSRC = it->remoteSSRC;
3154 report_block.source_SSRC = it->sourceSSRC;
3155 report_block.fraction_lost = it->fractionLost;
3156 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3157 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3158 report_block.interarrival_jitter = it->jitter;
3159 report_block.last_SR_timestamp = it->lastSR;
3160 report_block.delay_since_last_SR = it->delaySinceLastSR;
3161 report_blocks->push_back(report_block);
3162 }
3163 return 0;
3164}
3165
niklase@google.com470e71d2011-07-07 08:21:25 +00003166int
3167Channel::GetRTPStatistics(CallStatistics& stats)
3168{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003169 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003170
3171 // The jitter statistics is updated for each received RTP packet and is
3172 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003173 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003174 StreamStatistician* statistician =
3175 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3176 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003177 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3178 _engineStatisticsPtr->SetLastError(
3179 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3180 "GetRTPStatistics() failed to read RTP statistics from the "
3181 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003182 }
3183
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003184 stats.fractionLost = statistics.fraction_lost;
3185 stats.cumulativeLost = statistics.cumulative_lost;
3186 stats.extendedMax = statistics.extended_max_sequence_number;
3187 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003188
3189 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3190 VoEId(_instanceId, _channelId),
3191 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003192 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003193 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3194 stats.jitterSamples);
3195
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003196 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003197 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003198 if (stats.rttMs == 0) {
3199 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3200 "GetRTPStatistics() failed to get RTT");
3201 } else {
3202 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003203 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003204 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003205
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003206 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003207
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003208 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003209 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003210 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003211 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003212
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003213 if (statistician) {
3214 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3215 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003216
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003217 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003218 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003219 {
3220 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3221 VoEId(_instanceId, _channelId),
3222 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003223 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003224 }
3225
3226 stats.bytesSent = bytesSent;
3227 stats.packetsSent = packetsSent;
3228 stats.bytesReceived = bytesReceived;
3229 stats.packetsReceived = packetsReceived;
3230
3231 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3232 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003233 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3234 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003235 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3236 stats.packetsReceived);
3237
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003238 // --- Timestamps
3239 {
3240 CriticalSectionScoped lock(ts_stats_lock_.get());
3241 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3242 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003243 return 0;
3244}
3245
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003246int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003247 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003248 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003249
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003250 if (enable) {
3251 if (redPayloadtype < 0 || redPayloadtype > 127) {
3252 _engineStatisticsPtr->SetLastError(
3253 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003254 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003255 return -1;
3256 }
3257
3258 if (SetRedPayloadType(redPayloadtype) < 0) {
3259 _engineStatisticsPtr->SetLastError(
3260 VE_CODEC_ERROR, kTraceError,
3261 "SetSecondarySendCodec() Failed to register RED ACM");
3262 return -1;
3263 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003264 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003265
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003266 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003267 _engineStatisticsPtr->SetLastError(
3268 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003269 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003270 return -1;
3271 }
3272 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003273}
3274
3275int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003276Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003277{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003278 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003279 if (enabled)
3280 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003281 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003282 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003283 {
3284 _engineStatisticsPtr->SetLastError(
3285 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003286 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003287 "module");
3288 return -1;
3289 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003290 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003291 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3292 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003293 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003294 enabled, redPayloadtype);
3295 return 0;
3296 }
3297 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3298 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003299 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003300 return 0;
3301}
3302
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003303int Channel::SetCodecFECStatus(bool enable) {
3304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3305 "Channel::SetCodecFECStatus()");
3306
3307 if (audio_coding_->SetCodecFEC(enable) != 0) {
3308 _engineStatisticsPtr->SetLastError(
3309 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3310 "SetCodecFECStatus() failed to set FEC state");
3311 return -1;
3312 }
3313 return 0;
3314}
3315
3316bool Channel::GetCodecFECStatus() {
3317 bool enabled = audio_coding_->CodecFEC();
3318 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3319 VoEId(_instanceId, _channelId),
3320 "GetCodecFECStatus() => enabled=%d", enabled);
3321 return enabled;
3322}
3323
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003324void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3325 // None of these functions can fail.
3326 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003327 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3328 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003329 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003330 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003331 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003332 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003333}
3334
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003335// Called when we are missing one or more packets.
3336int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003337 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3338}
3339
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003340uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003341Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003342{
3343 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003344 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003345 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003346 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003347 return 0;
3348}
3349
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003350void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003351 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003352 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003353 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003354 CodecInst codec;
3355 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003356
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003357 if (!mono_recording_audio_.get()) {
3358 // Temporary space for DownConvertToCodecFormat.
3359 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003360 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003361 DownConvertToCodecFormat(audio_data,
3362 number_of_frames,
3363 number_of_channels,
3364 sample_rate,
3365 codec.channels,
3366 codec.plfreq,
3367 mono_recording_audio_.get(),
3368 &input_resampler_,
3369 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003370}
3371
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003372uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003373Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003374{
3375 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3376 "Channel::PrepareEncodeAndSend()");
3377
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003378 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003379 {
3380 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3381 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003382 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003383 }
3384
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003385 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003386 {
3387 MixOrReplaceAudioWithFile(mixingFrequency);
3388 }
3389
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003390 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3391 if (is_muted) {
3392 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003393 }
3394
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003395 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003396 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003397 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003398 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003399 if (_inputExternalMediaCallbackPtr)
3400 {
3401 _inputExternalMediaCallbackPtr->Process(
3402 _channelId,
3403 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003404 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003405 _audioFrame.samples_per_channel_,
3406 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003407 isStereo);
3408 }
3409 }
3410
3411 InsertInbandDtmfTone();
3412
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003413 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003414 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003415 if (is_muted) {
3416 rms_level_.ProcessMuted(length);
3417 } else {
3418 rms_level_.Process(_audioFrame.data_, length);
3419 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003420 }
3421
niklase@google.com470e71d2011-07-07 08:21:25 +00003422 return 0;
3423}
3424
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003425uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003426Channel::EncodeAndSend()
3427{
3428 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3429 "Channel::EncodeAndSend()");
3430
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003431 assert(_audioFrame.num_channels_ <= 2);
3432 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003433 {
3434 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3435 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003436 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003437 }
3438
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003439 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003440
3441 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3442
3443 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003444 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003445 // This call will trigger AudioPacketizationCallback::SendData if encoding
3446 // is done and payload is ready for packetization and transmission.
3447 // Otherwise, it will return without invoking the callback.
3448 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003449 {
3450 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3451 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003452 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003453 }
3454
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003455 _timeStamp += _audioFrame.samples_per_channel_;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003456 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003457}
3458
Minyue2013aec2015-05-13 14:14:42 +02003459void Channel::DisassociateSendChannel(int channel_id) {
3460 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3461 Channel* channel = associate_send_channel_.channel();
3462 if (channel && channel->ChannelId() == channel_id) {
3463 // If this channel is associated with a send channel of the specified
3464 // Channel ID, disassociate with it.
3465 ChannelOwner ref(NULL);
3466 associate_send_channel_ = ref;
3467 }
3468}
3469
niklase@google.com470e71d2011-07-07 08:21:25 +00003470int Channel::RegisterExternalMediaProcessing(
3471 ProcessingTypes type,
3472 VoEMediaProcess& processObject)
3473{
3474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3475 "Channel::RegisterExternalMediaProcessing()");
3476
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003477 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003478
3479 if (kPlaybackPerChannel == type)
3480 {
3481 if (_outputExternalMediaCallbackPtr)
3482 {
3483 _engineStatisticsPtr->SetLastError(
3484 VE_INVALID_OPERATION, kTraceError,
3485 "Channel::RegisterExternalMediaProcessing() "
3486 "output external media already enabled");
3487 return -1;
3488 }
3489 _outputExternalMediaCallbackPtr = &processObject;
3490 _outputExternalMedia = true;
3491 }
3492 else if (kRecordingPerChannel == type)
3493 {
3494 if (_inputExternalMediaCallbackPtr)
3495 {
3496 _engineStatisticsPtr->SetLastError(
3497 VE_INVALID_OPERATION, kTraceError,
3498 "Channel::RegisterExternalMediaProcessing() "
3499 "output external media already enabled");
3500 return -1;
3501 }
3502 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003503 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 }
3505 return 0;
3506}
3507
3508int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3509{
3510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3511 "Channel::DeRegisterExternalMediaProcessing()");
3512
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003513 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003514
3515 if (kPlaybackPerChannel == type)
3516 {
3517 if (!_outputExternalMediaCallbackPtr)
3518 {
3519 _engineStatisticsPtr->SetLastError(
3520 VE_INVALID_OPERATION, kTraceWarning,
3521 "Channel::DeRegisterExternalMediaProcessing() "
3522 "output external media already disabled");
3523 return 0;
3524 }
3525 _outputExternalMedia = false;
3526 _outputExternalMediaCallbackPtr = NULL;
3527 }
3528 else if (kRecordingPerChannel == type)
3529 {
3530 if (!_inputExternalMediaCallbackPtr)
3531 {
3532 _engineStatisticsPtr->SetLastError(
3533 VE_INVALID_OPERATION, kTraceWarning,
3534 "Channel::DeRegisterExternalMediaProcessing() "
3535 "input external media already disabled");
3536 return 0;
3537 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003538 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003539 _inputExternalMediaCallbackPtr = NULL;
3540 }
3541
3542 return 0;
3543}
3544
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003545int Channel::SetExternalMixing(bool enabled) {
3546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3547 "Channel::SetExternalMixing(enabled=%d)", enabled);
3548
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003549 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003550 {
3551 _engineStatisticsPtr->SetLastError(
3552 VE_INVALID_OPERATION, kTraceError,
3553 "Channel::SetExternalMixing() "
3554 "external mixing cannot be changed while playing.");
3555 return -1;
3556 }
3557
3558 _externalMixing = enabled;
3559
3560 return 0;
3561}
3562
niklase@google.com470e71d2011-07-07 08:21:25 +00003563int
niklase@google.com470e71d2011-07-07 08:21:25 +00003564Channel::GetNetworkStatistics(NetworkStatistics& stats)
3565{
3566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3567 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003568 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003569}
3570
wu@webrtc.org24301a62013-12-13 19:17:43 +00003571void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3572 audio_coding_->GetDecodingCallStatistics(stats);
3573}
3574
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003575bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3576 int* playout_buffer_delay_ms) const {
3577 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003578 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003579 "Channel::GetDelayEstimate() no valid estimate.");
3580 return false;
3581 }
3582 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3583 _recPacketDelayMs;
3584 *playout_buffer_delay_ms = playout_delay_ms_;
3585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3586 "Channel::GetDelayEstimate()");
3587 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003588}
3589
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003590int Channel::SetInitialPlayoutDelay(int delay_ms)
3591{
3592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3593 "Channel::SetInitialPlayoutDelay()");
3594 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3595 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3596 {
3597 _engineStatisticsPtr->SetLastError(
3598 VE_INVALID_ARGUMENT, kTraceError,
3599 "SetInitialPlayoutDelay() invalid min delay");
3600 return -1;
3601 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003602 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3606 "SetInitialPlayoutDelay() failed to set min playout delay");
3607 return -1;
3608 }
3609 return 0;
3610}
3611
3612
niklase@google.com470e71d2011-07-07 08:21:25 +00003613int
3614Channel::SetMinimumPlayoutDelay(int delayMs)
3615{
3616 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3617 "Channel::SetMinimumPlayoutDelay()");
3618 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3619 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3620 {
3621 _engineStatisticsPtr->SetLastError(
3622 VE_INVALID_ARGUMENT, kTraceError,
3623 "SetMinimumPlayoutDelay() invalid min delay");
3624 return -1;
3625 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003626 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003627 {
3628 _engineStatisticsPtr->SetLastError(
3629 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3630 "SetMinimumPlayoutDelay() failed to set min playout delay");
3631 return -1;
3632 }
3633 return 0;
3634}
3635
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003636void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3637 uint32_t playout_timestamp = 0;
3638
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003639 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003640 // This can happen if this channel has not been received any RTP packet. In
3641 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003642 return;
3643 }
3644
3645 uint16_t delay_ms = 0;
3646 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3647 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3648 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3649 " delay from the ADM");
3650 _engineStatisticsPtr->SetLastError(
3651 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3652 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3653 return;
3654 }
3655
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003656 jitter_buffer_playout_timestamp_ = playout_timestamp;
3657
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003658 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003659 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003660
3661 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3662 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3663 playout_timestamp);
3664
3665 if (rtcp) {
3666 playout_timestamp_rtcp_ = playout_timestamp;
3667 } else {
3668 playout_timestamp_rtp_ = playout_timestamp;
3669 }
3670 playout_delay_ms_ = delay_ms;
3671}
3672
3673int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3675 "Channel::GetPlayoutTimestamp()");
3676 if (playout_timestamp_rtp_ == 0) {
3677 _engineStatisticsPtr->SetLastError(
3678 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3679 "GetPlayoutTimestamp() failed to retrieve timestamp");
3680 return -1;
3681 }
3682 timestamp = playout_timestamp_rtp_;
3683 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3684 VoEId(_instanceId,_channelId),
3685 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3686 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003687}
3688
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003689int Channel::SetInitTimestamp(unsigned int timestamp) {
3690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003691 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003692 if (channel_state_.Get().sending) {
3693 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3694 "SetInitTimestamp() already sending");
3695 return -1;
3696 }
3697 _rtpRtcpModule->SetStartTimestamp(timestamp);
3698 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003699}
3700
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003701int Channel::SetInitSequenceNumber(short sequenceNumber) {
3702 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3703 "Channel::SetInitSequenceNumber()");
3704 if (channel_state_.Get().sending) {
3705 _engineStatisticsPtr->SetLastError(
3706 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3707 return -1;
3708 }
3709 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3710 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003711}
3712
3713int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003714Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003715{
3716 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3717 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003718 *rtpRtcpModule = _rtpRtcpModule.get();
3719 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003720 return 0;
3721}
3722
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003723// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3724// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003725int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003726Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003727{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003728 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003729 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003730
3731 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003732 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003733
3734 if (_inputFilePlayerPtr == NULL)
3735 {
3736 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3737 VoEId(_instanceId, _channelId),
3738 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3739 " doesnt exist");
3740 return -1;
3741 }
3742
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003743 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003744 fileSamples,
3745 mixingFrequency) == -1)
3746 {
3747 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3748 VoEId(_instanceId, _channelId),
3749 "Channel::MixOrReplaceAudioWithFile() file mixing "
3750 "failed");
3751 return -1;
3752 }
3753 if (fileSamples == 0)
3754 {
3755 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3756 VoEId(_instanceId, _channelId),
3757 "Channel::MixOrReplaceAudioWithFile() file is ended");
3758 return 0;
3759 }
3760 }
3761
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003762 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003763
3764 if (_mixFileWithMicrophone)
3765 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003766 // Currently file stream is always mono.
3767 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003768 MixWithSat(_audioFrame.data_,
3769 _audioFrame.num_channels_,
3770 fileBuffer.get(),
3771 1,
3772 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003773 }
3774 else
3775 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003776 // Replace ACM audio with file.
3777 // Currently file stream is always mono.
3778 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003779 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003780 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003781 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003782 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003783 mixingFrequency,
3784 AudioFrame::kNormalSpeech,
3785 AudioFrame::kVadUnknown,
3786 1);
3787
3788 }
3789 return 0;
3790}
3791
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003792int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003793Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003794 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003795{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003796 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003797
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003798 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003799 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003800
3801 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003802 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003803
3804 if (_outputFilePlayerPtr == NULL)
3805 {
3806 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3807 VoEId(_instanceId, _channelId),
3808 "Channel::MixAudioWithFile() file mixing failed");
3809 return -1;
3810 }
3811
3812 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003813 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003814 fileSamples,
3815 mixingFrequency) == -1)
3816 {
3817 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3818 VoEId(_instanceId, _channelId),
3819 "Channel::MixAudioWithFile() file mixing failed");
3820 return -1;
3821 }
3822 }
3823
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003824 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003825 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003826 // Currently file stream is always mono.
3827 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003828 MixWithSat(audioFrame.data_,
3829 audioFrame.num_channels_,
3830 fileBuffer.get(),
3831 1,
3832 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003833 }
3834 else
3835 {
3836 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003837 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00003838 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003839 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003840 return -1;
3841 }
3842
3843 return 0;
3844}
3845
3846int
3847Channel::InsertInbandDtmfTone()
3848{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003849 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003850 if (_inbandDtmfQueue.PendingDtmf() &&
3851 !_inbandDtmfGenerator.IsAddingTone() &&
3852 _inbandDtmfGenerator.DelaySinceLastTone() >
3853 kMinTelephoneEventSeparationMs)
3854 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003855 int8_t eventCode(0);
3856 uint16_t lengthMs(0);
3857 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003858
3859 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3860 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3861 if (_playInbandDtmfEvent)
3862 {
3863 // Add tone to output mixer using a reduced length to minimize
3864 // risk of echo.
3865 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3866 attenuationDb);
3867 }
3868 }
3869
3870 if (_inbandDtmfGenerator.IsAddingTone())
3871 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003872 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003873 _inbandDtmfGenerator.GetSampleRate(frequency);
3874
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003875 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003876 {
3877 // Update sample rate of Dtmf tone since the mixing frequency
3878 // has changed.
3879 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003880 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003881 // Reset the tone to be added taking the new sample rate into
3882 // account.
3883 _inbandDtmfGenerator.ResetTone();
3884 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003885
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003886 int16_t toneBuffer[320];
3887 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003888 // Get 10ms tone segment and set time since last tone to zero
3889 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3890 {
3891 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3892 VoEId(_instanceId, _channelId),
3893 "Channel::EncodeAndSend() inserting Dtmf failed");
3894 return -1;
3895 }
3896
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003897 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003898 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003899 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003900 sample++)
3901 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003902 for (int channel = 0;
3903 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003904 channel++)
3905 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003906 const int index = sample * _audioFrame.num_channels_ + channel;
3907 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003908 }
3909 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003910
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003911 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003912 } else
3913 {
3914 // Add 10ms to "delay-since-last-tone" counter
3915 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3916 }
3917 return 0;
3918}
3919
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003920int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003921Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003922{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003923 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003924 if (_transportPtr == NULL)
3925 {
3926 return -1;
3927 }
3928 if (!RTCP)
3929 {
3930 return _transportPtr->SendPacket(_channelId, data, len);
3931 }
3932 else
3933 {
3934 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3935 }
3936}
3937
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003938// Called for incoming RTP packets after successful RTP header parsing.
3939void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3940 uint16_t sequence_number) {
3941 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3942 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3943 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003944
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003945 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003946 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003947
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00003948 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003949 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00003950
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003951 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3952 // every incoming packet.
3953 uint32_t timestamp_diff_ms = (rtp_timestamp -
3954 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003955 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3956 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3957 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3958 // timestamp, the resulting difference is negative, but is set to zero.
3959 // This can happen when a network glitch causes a packet to arrive late,
3960 // and during long comfort noise periods with clock drift.
3961 timestamp_diff_ms = 0;
3962 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003963
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003964 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3965 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003966
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003967 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003968
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003969 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003970
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003971 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3972 _recPacketDelayMs = packet_delay_ms;
3973 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003974
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003975 if (_average_jitter_buffer_delay_us == 0) {
3976 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3977 return;
3978 }
3979
3980 // Filter average delay value using exponential filter (alpha is
3981 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3982 // risk of rounding error) and compensate for it in GetDelayEstimate()
3983 // later.
3984 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3985 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00003986}
3987
3988void
3989Channel::RegisterReceiveCodecsToRTPModule()
3990{
3991 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3992 "Channel::RegisterReceiveCodecsToRTPModule()");
3993
3994
3995 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003996 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003997
3998 for (int idx = 0; idx < nSupportedCodecs; idx++)
3999 {
4000 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004001 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004002 (rtp_receiver_->RegisterReceivePayload(
4003 codec.plname,
4004 codec.pltype,
4005 codec.plfreq,
4006 codec.channels,
4007 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004008 {
4009 WEBRTC_TRACE(
4010 kTraceWarning,
4011 kTraceVoice,
4012 VoEId(_instanceId, _channelId),
4013 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4014 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4015 codec.plname, codec.pltype, codec.plfreq,
4016 codec.channels, codec.rate);
4017 }
4018 else
4019 {
4020 WEBRTC_TRACE(
4021 kTraceInfo,
4022 kTraceVoice,
4023 VoEId(_instanceId, _channelId),
4024 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004025 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004026 "receiver",
4027 codec.plname, codec.pltype, codec.plfreq,
4028 codec.channels, codec.rate);
4029 }
4030 }
4031}
4032
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004033// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004034int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004035 CodecInst codec;
4036 bool found_red = false;
4037
4038 // Get default RED settings from the ACM database
4039 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4040 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004041 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004042 if (!STR_CASE_CMP(codec.plname, "RED")) {
4043 found_red = true;
4044 break;
4045 }
4046 }
4047
4048 if (!found_red) {
4049 _engineStatisticsPtr->SetLastError(
4050 VE_CODEC_ERROR, kTraceError,
4051 "SetRedPayloadType() RED is not supported");
4052 return -1;
4053 }
4054
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004055 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004056 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004057 _engineStatisticsPtr->SetLastError(
4058 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4059 "SetRedPayloadType() RED registration in ACM module failed");
4060 return -1;
4061 }
4062
4063 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4064 _engineStatisticsPtr->SetLastError(
4065 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4066 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4067 return -1;
4068 }
4069 return 0;
4070}
4071
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004072int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4073 unsigned char id) {
4074 int error = 0;
4075 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4076 if (enable) {
4077 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4078 }
4079 return error;
4080}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004081
wu@webrtc.org94454b72014-06-05 20:34:08 +00004082int32_t Channel::GetPlayoutFrequency() {
4083 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4084 CodecInst current_recive_codec;
4085 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4086 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4087 // Even though the actual sampling rate for G.722 audio is
4088 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4089 // 8,000 Hz because that value was erroneously assigned in
4090 // RFC 1890 and must remain unchanged for backward compatibility.
4091 playout_frequency = 8000;
4092 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4093 // We are resampling Opus internally to 32,000 Hz until all our
4094 // DSP routines can operate at 48,000 Hz, but the RTP clock
4095 // rate for the Opus payload format is standardized to 48,000 Hz,
4096 // because that is the maximum supported decoding sampling rate.
4097 playout_frequency = 48000;
4098 }
4099 }
4100 return playout_frequency;
4101}
4102
Minyue2013aec2015-05-13 14:14:42 +02004103int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004104 RTCPMethod method = _rtpRtcpModule->RTCP();
4105 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004106 return 0;
4107 }
4108 std::vector<RTCPReportBlock> report_blocks;
4109 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004110
4111 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004112 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004113 if (allow_associate_channel) {
4114 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4115 Channel* channel = associate_send_channel_.channel();
4116 // Tries to get RTT from an associated channel. This is important for
4117 // receive-only channels.
4118 if (channel) {
4119 // To prevent infinite recursion and deadlock, calling GetRTT of
4120 // associate channel should always use "false" for argument:
4121 // |allow_associate_channel|.
4122 rtt = channel->GetRTT(false);
4123 }
4124 }
4125 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004126 }
4127
4128 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4129 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4130 for (; it != report_blocks.end(); ++it) {
4131 if (it->remoteSSRC == remoteSSRC)
4132 break;
4133 }
4134 if (it == report_blocks.end()) {
4135 // We have not received packets with SSRC matching the report blocks.
4136 // To calculate RTT we try with the SSRC of the first report block.
4137 // This is very important for send-only channels where we don't know
4138 // the SSRC of the other end.
4139 remoteSSRC = report_blocks[0].remoteSSRC;
4140 }
Minyue2013aec2015-05-13 14:14:42 +02004141
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004142 int64_t avg_rtt = 0;
4143 int64_t max_rtt= 0;
4144 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004145 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4146 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004147 return 0;
4148 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004149 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004150}
4151
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004152} // namespace voe
4153} // namespace webrtc