blob: 06812dd3278bc49c072d190990a89cd68ab5212b [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 ChannelStatistics GetStats() {
78 CriticalSectionScoped cs(stats_lock_.get());
79 return stats_;
80 }
81
82 private:
83 // StatisticsUpdated calls are triggered from threads in the RTP module,
84 // while GetStats calls can be triggered from the public voice engine API,
85 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000086 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000087 const uint32_t ssrc_;
88 ChannelStatistics stats_;
89};
90
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000091class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000092 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000093 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
94 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000095
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000096 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
97 // Not used for Voice Engine.
98 }
99
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000100 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
101 int64_t rtt,
102 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000103 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
104 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
105 // report for VoiceEngine?
106 if (report_blocks.empty())
107 return;
108
109 int fraction_lost_aggregate = 0;
110 int total_number_of_packets = 0;
111
112 // If receiving multiple report blocks, calculate the weighted average based
113 // on the number of packets a report refers to.
114 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
115 block_it != report_blocks.end(); ++block_it) {
116 // Find the previous extended high sequence number for this remote SSRC,
117 // to calculate the number of RTP packets this report refers to. Ignore if
118 // we haven't seen this SSRC before.
119 std::map<uint32_t, uint32_t>::iterator seq_num_it =
120 extended_max_sequence_number_.find(block_it->sourceSSRC);
121 int number_of_packets = 0;
122 if (seq_num_it != extended_max_sequence_number_.end()) {
123 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
124 }
125 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
126 total_number_of_packets += number_of_packets;
127
128 extended_max_sequence_number_[block_it->sourceSSRC] =
129 block_it->extendedHighSeqNum;
130 }
131 int weighted_fraction_lost = 0;
132 if (total_number_of_packets > 0) {
133 weighted_fraction_lost = (fraction_lost_aggregate +
134 total_number_of_packets / 2) / total_number_of_packets;
135 }
136 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000137 }
138
139 private:
140 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000141 // Maps remote side ssrc to extended highest sequence number received.
142 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000143};
144
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000145int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000146Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000147 uint8_t payloadType,
148 uint32_t timeStamp,
149 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000150 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 const RTPFragmentationHeader* fragmentation)
152{
153 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
154 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000155 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
156 frameType, payloadType, timeStamp,
157 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158
159 if (_includeAudioLevelIndication)
160 {
161 // Store current audio level in the RTP/RTCP module.
162 // The level will be used in combination with voice-activity state
163 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000164 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 }
166
167 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
168 // packetization.
169 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000170 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 payloadType,
172 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000173 // Leaving the time when this frame was
174 // received from the capture device as
175 // undefined for voice for now.
176 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 payloadData,
178 payloadSize,
179 fragmentation) == -1)
180 {
181 _engineStatisticsPtr->SetLastError(
182 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
183 "Channel::SendData() failed to send data to RTP/RTCP module");
184 return -1;
185 }
186
187 _lastLocalTimeStamp = timeStamp;
188 _lastPayloadType = payloadType;
189
190 return 0;
191}
192
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000193int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000194Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000195{
196 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000197 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000198
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000199 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000200 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 return 0;
202}
203
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000204int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000205Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000206{
207 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
208 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
209
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000210 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 if (_rxVadObserverPtr)
212 {
213 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
214 }
215
216 return 0;
217}
218
219int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000220Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000221{
222 channel = VoEChannelId(channel);
223 assert(channel == _channelId);
224
225 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000226 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
227 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000229 CriticalSectionScoped cs(&_callbackCritSect);
230
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 if (_transportPtr == NULL)
232 {
233 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
234 "Channel::SendPacket() failed to send RTP packet due to"
235 " invalid transport object");
236 return -1;
237 }
238
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000239 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000240 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000242 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
243 bufferLength);
244 if (n < 0) {
245 std::string transport_name =
246 _externalTransport ? "external transport" : "WebRtc sockets";
247 WEBRTC_TRACE(kTraceError, kTraceVoice,
248 VoEId(_instanceId,_channelId),
249 "Channel::SendPacket() RTP transmission using %s failed",
250 transport_name.c_str());
251 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000253 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000254}
255
256int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000257Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000258{
259 channel = VoEChannelId(channel);
260 assert(channel == _channelId);
261
262 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000263 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
264 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000265
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000266 CriticalSectionScoped cs(&_callbackCritSect);
267 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000269 WEBRTC_TRACE(kTraceError, kTraceVoice,
270 VoEId(_instanceId,_channelId),
271 "Channel::SendRTCPPacket() failed to send RTCP packet"
272 " due to invalid transport object");
273 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000276 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000277 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000279 int n = _transportPtr->SendRTCPPacket(channel,
280 bufferToSendPtr,
281 bufferLength);
282 if (n < 0) {
283 std::string transport_name =
284 _externalTransport ? "external transport" : "WebRtc sockets";
285 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
286 VoEId(_instanceId,_channelId),
287 "Channel::SendRTCPPacket() transmission using %s failed",
288 transport_name.c_str());
289 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000291 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000292}
293
294void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000295Channel::OnPlayTelephoneEvent(int32_t id,
296 uint8_t event,
297 uint16_t lengthMs,
298 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000299{
300 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
301 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000302 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000303
304 if (!_playOutbandDtmfEvent || (event > 15))
305 {
306 // Ignore callback since feedback is disabled or event is not a
307 // Dtmf tone event.
308 return;
309 }
310
311 assert(_outputMixerPtr != NULL);
312
313 // Start playing out the Dtmf tone (if playout is enabled).
314 // Reduce length of tone with 80ms to the reduce risk of echo.
315 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
316}
317
318void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000319Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000320{
321 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
322 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000323 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000324
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000325 // Update ssrc so that NTP for AV sync can be updated.
326 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000327}
328
pbos@webrtc.org92135212013-05-14 08:31:39 +0000329void Channel::OnIncomingCSRCChanged(int32_t id,
330 uint32_t CSRC,
331 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000332{
333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
334 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
335 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000336}
337
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000338int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000339Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000340 int32_t id,
341 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000342 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000343 int frequency,
344 uint8_t channels,
345 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000346{
347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
348 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
349 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
350 id, payloadType, payloadName, frequency, channels, rate);
351
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000352 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000353
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000354 CodecInst receiveCodec = {0};
355 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000356
357 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 receiveCodec.plfreq = frequency;
359 receiveCodec.channels = channels;
360 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000361 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000362
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000363 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 receiveCodec.pacsize = dummyCodec.pacsize;
365
366 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000367 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 {
369 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000370 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000371 "Channel::OnInitializeDecoder() invalid codec ("
372 "pt=%d, name=%s) received - 1", payloadType, payloadName);
373 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
374 return -1;
375 }
376
377 return 0;
378}
379
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000380int32_t
381Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000382 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 const WebRtcRTPHeader* rtpHeader)
384{
385 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000386 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 " payloadType=%u, audioChannel=%u)",
388 payloadSize,
389 rtpHeader->header.payloadType,
390 rtpHeader->type.Audio.channel);
391
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000392 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 {
394 // Avoid inserting into NetEQ when we are not playing. Count the
395 // packet as discarded.
396 WEBRTC_TRACE(kTraceStream, kTraceVoice,
397 VoEId(_instanceId, _channelId),
398 "received packet is discarded since playing is not"
399 " activated");
400 _numberOfDiscardedPackets++;
401 return 0;
402 }
403
404 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000405 if (audio_coding_->IncomingPacket(payloadData,
406 payloadSize,
407 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
409 _engineStatisticsPtr->SetLastError(
410 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
411 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
412 return -1;
413 }
414
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000415 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 UpdatePacketDelay(rtpHeader->header.timestamp,
417 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000418
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000419 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000420 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
421 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000422
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000423 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000424 round_trip_time);
425 if (!nack_list.empty()) {
426 // Can't use nack_list.data() since it's not supported by all
427 // compilers.
428 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000429 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 return 0;
431}
432
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000433bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000434 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000435 RTPHeader header;
436 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
437 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
438 "IncomingPacket invalid RTP header");
439 return false;
440 }
441 header.payload_type_frequency =
442 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
443 if (header.payload_type_frequency < 0)
444 return false;
445 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
446}
447
minyuel0f4b3732015-08-31 16:04:32 +0200448int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000449{
450 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
451 "Channel::GetAudioFrame(id=%d)", id);
452
453 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200454 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
455 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 {
457 WEBRTC_TRACE(kTraceError, kTraceVoice,
458 VoEId(_instanceId,_channelId),
459 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000460 // In all likelihood, the audio in this frame is garbage. We return an
461 // error so that the audio mixer module doesn't add it to the mix. As
462 // a result, it won't be played out and the actions skipped here are
463 // irrelevant.
464 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 }
466
467 if (_RxVadDetection)
468 {
minyuel0f4b3732015-08-31 16:04:32 +0200469 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 }
471
472 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200473 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000474 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200475 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000476
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000477 ChannelState::State state = channel_state_.Get();
478
479 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200480 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000481 if (err) {
482 LOG(LS_ERROR) << "ProcessStream() error: " << err;
483 assert(false);
484 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 }
486
wu@webrtc.org63420662013-10-17 18:28:55 +0000487 float output_gain = 1.0f;
488 float left_pan = 1.0f;
489 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000491 CriticalSectionScoped cs(&volume_settings_critsect_);
492 output_gain = _outputGain;
493 left_pan = _panLeft;
494 right_pan= _panRight;
495 }
496
497 // Output volume scaling
498 if (output_gain < 0.99f || output_gain > 1.01f)
499 {
minyuel0f4b3732015-08-31 16:04:32 +0200500 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 }
502
503 // Scale left and/or right channel(s) if stereo and master balance is
504 // active
505
wu@webrtc.org63420662013-10-17 18:28:55 +0000506 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 {
minyuel0f4b3732015-08-31 16:04:32 +0200508 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 {
510 // Emulate stereo mode since panning is active.
511 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200512 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 }
514 // For true stereo mode (when we are receiving a stereo signal), no
515 // action is needed.
516
517 // Do the panning operation (the audio frame contains stereo at this
518 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200519 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000520 }
521
522 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000523 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 {
minyuel0f4b3732015-08-31 16:04:32 +0200525 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000526 }
527
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 // External media
529 if (_outputExternalMedia)
530 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000531 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200532 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 if (_outputExternalMediaCallbackPtr)
534 {
535 _outputExternalMediaCallbackPtr->Process(
536 _channelId,
537 kPlaybackPerChannel,
minyuel0f4b3732015-08-31 16:04:32 +0200538 (int16_t*)audioFrame->data_,
539 audioFrame->samples_per_channel_,
540 audioFrame->sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000541 isStereo);
542 }
543 }
544
545 // Record playout if enabled
546 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000547 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000548
549 if (_outputFileRecording && _outputFileRecorderPtr)
550 {
minyuel0f4b3732015-08-31 16:04:32 +0200551 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 }
553 }
554
555 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200556 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000557
minyuel0f4b3732015-08-31 16:04:32 +0200558 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000559 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200560 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000561 }
562
563 if (capture_start_rtp_time_stamp_ >= 0) {
564 // audioFrame.timestamp_ should be valid from now on.
565
566 // Compute elapsed time.
567 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200568 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
569 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000570 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
571 (GetPlayoutFrequency() / 1000);
572
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000573 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000574 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000575 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200576 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
577 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000578 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200579 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000580 // Compute |capture_start_ntp_time_ms_| so that
581 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
582 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200583 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000584 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000585 }
586 }
587
niklase@google.com470e71d2011-07-07 08:21:25 +0000588 return 0;
589}
590
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000591int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200592Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000593{
594 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
595 "Channel::NeededFrequency(id=%d)", id);
596
597 int highestNeeded = 0;
598
599 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000600 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000601
602 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000603 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000604 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000605 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 }
607 else
608 {
609 highestNeeded = receiveFrequency;
610 }
611
612 // Special case, if we're playing a file on the playout side
613 // we take that frequency into consideration as well
614 // This is not needed on sending side, since the codec will
615 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000616 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000618 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000619 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 {
621 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
622 {
623 highestNeeded=_outputFilePlayerPtr->Frequency();
624 }
625 }
626 }
627
628 return(highestNeeded);
629}
630
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000631int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000632Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000633 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000634 uint32_t instanceId,
635 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000636{
637 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
638 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
639 channelId, instanceId);
640
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000641 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 if (channel == NULL)
643 {
644 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
645 VoEId(instanceId,channelId),
646 "Channel::CreateChannel() unable to allocate memory for"
647 " channel");
648 return -1;
649 }
650 return 0;
651}
652
653void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000654Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000655{
656 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
657 "Channel::PlayNotification(id=%d, durationMs=%d)",
658 id, durationMs);
659
660 // Not implement yet
661}
662
663void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000664Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000665{
666 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
667 "Channel::RecordNotification(id=%d, durationMs=%d)",
668 id, durationMs);
669
670 // Not implement yet
671}
672
673void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000674Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000675{
676 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
677 "Channel::PlayFileEnded(id=%d)", id);
678
679 if (id == _inputFilePlayerId)
680 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000681 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
683 VoEId(_instanceId,_channelId),
684 "Channel::PlayFileEnded() => input file player module is"
685 " shutdown");
686 }
687 else if (id == _outputFilePlayerId)
688 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000689 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000690 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
691 VoEId(_instanceId,_channelId),
692 "Channel::PlayFileEnded() => output file player module is"
693 " shutdown");
694 }
695}
696
697void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000698Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000699{
700 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
701 "Channel::RecordFileEnded(id=%d)", id);
702
703 assert(id == _outputFileRecorderId);
704
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000705 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000706
707 _outputFileRecording = false;
708 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
709 VoEId(_instanceId,_channelId),
710 "Channel::RecordFileEnded() => output file recorder module is"
711 " shutdown");
712}
713
pbos@webrtc.org92135212013-05-14 08:31:39 +0000714Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000715 uint32_t instanceId,
716 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
718 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000719 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000721 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000722 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000723 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000724 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000725 rtp_receive_statistics_(ReceiveStatistics::Create(
726 Clock::GetRealTimeClock())),
727 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
728 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
729 this, this, rtp_payload_registry_.get())),
730 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 _inputFilePlayerPtr(NULL),
734 _outputFilePlayerPtr(NULL),
735 _outputFileRecorderPtr(NULL),
736 // Avoid conflict with other channels by adding 1024 - 1026,
737 // won't use as much as 1024 channels.
738 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
739 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
740 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000742 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
743 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000744 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 _inputExternalMediaCallbackPtr(NULL),
746 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000747 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
748 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000749 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000750 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000751 playout_timestamp_rtp_(0),
752 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000753 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000754 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000755 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000756 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000757 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
758 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000759 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000760 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000761 _outputMixerPtr(NULL),
762 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000763 _moduleProcessThreadPtr(NULL),
764 _audioDeviceModulePtr(NULL),
765 _voiceEngineObserverPtr(NULL),
766 _callbackCritSectPtr(NULL),
767 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000768 _rxVadObserverPtr(NULL),
769 _oldVadDecision(-1),
770 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000771 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000772 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000773 _mute(false),
774 _panLeft(1.0f),
775 _panRight(1.0f),
776 _outputGain(1.0f),
777 _playOutbandDtmfEvent(false),
778 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000779 _lastLocalTimeStamp(0),
780 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000781 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 _outputSpeechType(AudioFrame::kNormalSpeech),
deadbeef74375882015-08-13 12:09:10 -0700783 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000784 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 _previousTimestamp(0),
786 _recPacketDelayMs(20),
787 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000788 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000789 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000790 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000791 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200792 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
793 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
794 associate_send_channel_(ChannelOwner(nullptr))
niklase@google.com470e71d2011-07-07 08:21:25 +0000795{
796 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
797 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200798 AudioCodingModule::Config acm_config;
799 acm_config.id = VoEModuleId(instanceId, channelId);
800 if (config.Get<NetEqCapacityConfig>().enabled) {
801 // Clamping the buffer capacity at 20 packets. While going lower will
802 // probably work, it makes little sense.
803 acm_config.neteq_config.max_packets_in_buffer =
804 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
805 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200806 acm_config.neteq_config.enable_fast_accelerate =
807 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200808 audio_coding_.reset(AudioCodingModule::Create(acm_config));
809
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 _inbandDtmfQueue.ResetDtmf();
811 _inbandDtmfGenerator.Init();
812 _outputAudioLevel.Clear();
813
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000814 RtpRtcp::Configuration configuration;
815 configuration.id = VoEModuleId(instanceId, channelId);
816 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000817 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000818 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000819 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000820 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000821
822 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000823
824 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
825 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
826 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000827
828 Config audioproc_config;
829 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
830 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000831}
832
833Channel::~Channel()
834{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000835 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
837 "Channel::~Channel() - dtor");
838
839 if (_outputExternalMedia)
840 {
841 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
842 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000843 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 {
845 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
846 }
847 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 StopPlayout();
849
850 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000851 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 if (_inputFilePlayerPtr)
853 {
854 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
855 _inputFilePlayerPtr->StopPlayingFile();
856 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
857 _inputFilePlayerPtr = NULL;
858 }
859 if (_outputFilePlayerPtr)
860 {
861 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
862 _outputFilePlayerPtr->StopPlayingFile();
863 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
864 _outputFilePlayerPtr = NULL;
865 }
866 if (_outputFileRecorderPtr)
867 {
868 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
869 _outputFileRecorderPtr->StopRecording();
870 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
871 _outputFileRecorderPtr = NULL;
872 }
873 }
874
875 // The order to safely shutdown modules in a channel is:
876 // 1. De-register callbacks in modules
877 // 2. De-register modules in process thread
878 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000879 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000880 {
881 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
882 VoEId(_instanceId,_channelId),
883 "~Channel() failed to de-register transport callback"
884 " (Audio coding module)");
885 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000886 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000887 {
888 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
889 VoEId(_instanceId,_channelId),
890 "~Channel() failed to de-register VAD callback"
891 " (Audio coding module)");
892 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000894 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
895
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 // End of modules shutdown
897
898 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000901 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000902}
903
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000904int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000905Channel::Init()
906{
907 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
908 "Channel::Init()");
909
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000910 channel_state_.Reset();
911
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 // --- Initial sanity
913
914 if ((_engineStatisticsPtr == NULL) ||
915 (_moduleProcessThreadPtr == NULL))
916 {
917 WEBRTC_TRACE(kTraceError, kTraceVoice,
918 VoEId(_instanceId,_channelId),
919 "Channel::Init() must call SetEngineInformation() first");
920 return -1;
921 }
922
923 // --- Add modules to process thread (for periodic schedulation)
924
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000925 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
926
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000927 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000928
Henrik Lundin45c64492015-03-30 19:00:44 +0200929 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000930#ifdef WEBRTC_CODEC_AVT
931 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200932 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000933#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200934 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 {
936 _engineStatisticsPtr->SetLastError(
937 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
938 "Channel::Init() unable to initialize the ACM - 1");
939 return -1;
940 }
941
942 // --- RTP/RTCP module initialization
943
944 // Ensure that RTCP is enabled by default for the created channel.
945 // Note that, the module will keep generating RTCP until it is explicitly
946 // disabled by the user.
947 // After StopListen (when no sockets exists), RTCP packets will no longer
948 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000949 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
950 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000951 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
952 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000954 (audio_coding_->RegisterTransportCallback(this) == -1) ||
955 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000956
957 if (fail)
958 {
959 _engineStatisticsPtr->SetLastError(
960 VE_CANNOT_INIT_CHANNEL, kTraceError,
961 "Channel::Init() callbacks not registered");
962 return -1;
963 }
964
965 // --- Register all supported codecs to the receiving side of the
966 // RTP/RTCP module
967
968 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000969 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000970
971 for (int idx = 0; idx < nSupportedCodecs; idx++)
972 {
973 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000974 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000975 (rtp_receiver_->RegisterReceivePayload(
976 codec.plname,
977 codec.pltype,
978 codec.plfreq,
979 codec.channels,
980 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000981 {
982 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
983 VoEId(_instanceId,_channelId),
984 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
985 "to RTP/RTCP receiver",
986 codec.plname, codec.pltype, codec.plfreq,
987 codec.channels, codec.rate);
988 }
989 else
990 {
991 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
992 VoEId(_instanceId,_channelId),
993 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
994 "the RTP/RTCP receiver",
995 codec.plname, codec.pltype, codec.plfreq,
996 codec.channels, codec.rate);
997 }
998
999 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001000 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001001 {
1002 SetSendCodec(codec);
1003 }
1004
1005 // Register default PT for outband 'telephone-event'
1006 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1007 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001008 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001009 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 {
1011 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1012 VoEId(_instanceId,_channelId),
1013 "Channel::Init() failed to register outband "
1014 "'telephone-event' (%d/%d) correctly",
1015 codec.pltype, codec.plfreq);
1016 }
1017 }
1018
1019 if (!STR_CASE_CMP(codec.plname, "CN"))
1020 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001021 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1022 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001023 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001024 {
1025 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1026 VoEId(_instanceId,_channelId),
1027 "Channel::Init() failed to register CN (%d/%d) "
1028 "correctly - 1",
1029 codec.pltype, codec.plfreq);
1030 }
1031 }
1032#ifdef WEBRTC_CODEC_RED
1033 // Register RED to the receiving side of the ACM.
1034 // We will not receive an OnInitializeDecoder() callback for RED.
1035 if (!STR_CASE_CMP(codec.plname, "RED"))
1036 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001037 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 {
1039 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1040 VoEId(_instanceId,_channelId),
1041 "Channel::Init() failed to register RED (%d/%d) "
1042 "correctly",
1043 codec.pltype, codec.plfreq);
1044 }
1045 }
1046#endif
1047 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001048
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001049 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1050 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1051 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001053 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1054 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1055 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 }
1057
1058 return 0;
1059}
1060
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001061int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001062Channel::SetEngineInformation(Statistics& engineStatistics,
1063 OutputMixer& outputMixer,
1064 voe::TransmitMixer& transmitMixer,
1065 ProcessThread& moduleProcessThread,
1066 AudioDeviceModule& audioDeviceModule,
1067 VoiceEngineObserver* voiceEngineObserver,
1068 CriticalSectionWrapper* callbackCritSect)
1069{
1070 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1071 "Channel::SetEngineInformation()");
1072 _engineStatisticsPtr = &engineStatistics;
1073 _outputMixerPtr = &outputMixer;
1074 _transmitMixerPtr = &transmitMixer,
1075 _moduleProcessThreadPtr = &moduleProcessThread;
1076 _audioDeviceModulePtr = &audioDeviceModule;
1077 _voiceEngineObserverPtr = voiceEngineObserver;
1078 _callbackCritSectPtr = callbackCritSect;
1079 return 0;
1080}
1081
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001082int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001083Channel::UpdateLocalTimeStamp()
1084{
1085
Peter Kastingb7e50542015-06-11 12:55:50 -07001086 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001087 return 0;
1088}
1089
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001090int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001091Channel::StartPlayout()
1092{
1093 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1094 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001095 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001096 {
1097 return 0;
1098 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001099
1100 if (!_externalMixing) {
1101 // Add participant as candidates for mixing.
1102 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1103 {
1104 _engineStatisticsPtr->SetLastError(
1105 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1106 "StartPlayout() failed to add participant to mixer");
1107 return -1;
1108 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 }
1110
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001111 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001112 if (RegisterFilePlayingToMixer() != 0)
1113 return -1;
1114
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 return 0;
1116}
1117
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001118int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001119Channel::StopPlayout()
1120{
1121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1122 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001123 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 {
1125 return 0;
1126 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001127
1128 if (!_externalMixing) {
1129 // Remove participant as candidates for mixing
1130 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1131 {
1132 _engineStatisticsPtr->SetLastError(
1133 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1134 "StopPlayout() failed to remove participant from mixer");
1135 return -1;
1136 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001137 }
1138
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001139 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 _outputAudioLevel.Clear();
1141
1142 return 0;
1143}
1144
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001145int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001146Channel::StartSend()
1147{
1148 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1149 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001150 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001151 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001152 if (send_sequence_number_)
1153 SetInitSequenceNumber(send_sequence_number_);
1154
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001155 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001156 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001157 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001159 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001160
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001161 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
1163 _engineStatisticsPtr->SetLastError(
1164 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1165 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001166 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001167 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001168 return -1;
1169 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001170
niklase@google.com470e71d2011-07-07 08:21:25 +00001171 return 0;
1172}
1173
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001174int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001175Channel::StopSend()
1176{
1177 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1178 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001179 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001180 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001181 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001183 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001184
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001185 // Store the sequence number to be able to pick up the same sequence for
1186 // the next StartSend(). This is needed for restarting device, otherwise
1187 // it might cause libSRTP to complain about packets being replayed.
1188 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1189 // CL is landed. See issue
1190 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1191 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1192
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 // Reset sending SSRC and sequence number and triggers direct transmission
1194 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001195 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001196 {
1197 _engineStatisticsPtr->SetLastError(
1198 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1199 "StartSend() RTP/RTCP failed to stop sending");
1200 }
1201
niklase@google.com470e71d2011-07-07 08:21:25 +00001202 return 0;
1203}
1204
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001205int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001206Channel::StartReceiving()
1207{
1208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1209 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001210 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001211 {
1212 return 0;
1213 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001214 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 _numberOfDiscardedPackets = 0;
1216 return 0;
1217}
1218
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001219int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001220Channel::StopReceiving()
1221{
1222 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1223 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001224 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 {
1226 return 0;
1227 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001228
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001229 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 return 0;
1231}
1232
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001233int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001234Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1235{
1236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1237 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001238 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001239
1240 if (_voiceEngineObserverPtr)
1241 {
1242 _engineStatisticsPtr->SetLastError(
1243 VE_INVALID_OPERATION, kTraceError,
1244 "RegisterVoiceEngineObserver() observer already enabled");
1245 return -1;
1246 }
1247 _voiceEngineObserverPtr = &observer;
1248 return 0;
1249}
1250
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001251int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001252Channel::DeRegisterVoiceEngineObserver()
1253{
1254 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1255 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001256 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001257
1258 if (!_voiceEngineObserverPtr)
1259 {
1260 _engineStatisticsPtr->SetLastError(
1261 VE_INVALID_OPERATION, kTraceWarning,
1262 "DeRegisterVoiceEngineObserver() observer already disabled");
1263 return 0;
1264 }
1265 _voiceEngineObserverPtr = NULL;
1266 return 0;
1267}
1268
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001269int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001270Channel::GetSendCodec(CodecInst& codec)
1271{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001272 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001273}
1274
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001275int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001276Channel::GetRecCodec(CodecInst& codec)
1277{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001278 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001279}
1280
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001281int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001282Channel::SetSendCodec(const CodecInst& codec)
1283{
1284 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1285 "Channel::SetSendCodec()");
1286
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001287 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001288 {
1289 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1290 "SetSendCodec() failed to register codec to ACM");
1291 return -1;
1292 }
1293
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001294 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001296 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1297 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001298 {
1299 WEBRTC_TRACE(
1300 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1301 "SetSendCodec() failed to register codec to"
1302 " RTP/RTCP module");
1303 return -1;
1304 }
1305 }
1306
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001307 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 {
1309 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1310 "SetSendCodec() failed to set audio packet size");
1311 return -1;
1312 }
1313
1314 return 0;
1315}
1316
Ivo Creusenadf89b72015-04-29 16:03:33 +02001317void Channel::SetBitRate(int bitrate_bps) {
1318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1319 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1320 audio_coding_->SetBitRate(bitrate_bps);
1321}
1322
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001323void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001324 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001325 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1326
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001327 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001328 if (audio_coding_->SetPacketLossRate(
1329 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001330 assert(false); // This should not happen.
1331 }
1332}
1333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001334int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001335Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001339 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 // To disable VAD, DTX must be disabled too
1341 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001342 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001343 {
1344 _engineStatisticsPtr->SetLastError(
1345 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1346 "SetVADStatus() failed to set VAD");
1347 return -1;
1348 }
1349 return 0;
1350}
1351
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001352int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001353Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1354{
1355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1356 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001357 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001358 {
1359 _engineStatisticsPtr->SetLastError(
1360 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1361 "GetVADStatus() failed to get VAD status");
1362 return -1;
1363 }
1364 disabledDTX = !disabledDTX;
1365 return 0;
1366}
1367
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001368int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001369Channel::SetRecPayloadType(const CodecInst& codec)
1370{
1371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1372 "Channel::SetRecPayloadType()");
1373
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001374 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001375 {
1376 _engineStatisticsPtr->SetLastError(
1377 VE_ALREADY_PLAYING, kTraceError,
1378 "SetRecPayloadType() unable to set PT while playing");
1379 return -1;
1380 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001381 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001382 {
1383 _engineStatisticsPtr->SetLastError(
1384 VE_ALREADY_LISTENING, kTraceError,
1385 "SetRecPayloadType() unable to set PT while listening");
1386 return -1;
1387 }
1388
1389 if (codec.pltype == -1)
1390 {
1391 // De-register the selected codec (RTP/RTCP module and ACM)
1392
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001393 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001394 CodecInst rxCodec = codec;
1395
1396 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001397 rtp_payload_registry_->ReceivePayloadType(
1398 rxCodec.plname,
1399 rxCodec.plfreq,
1400 rxCodec.channels,
1401 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1402 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 rxCodec.pltype = pltype;
1404
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001405 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 {
1407 _engineStatisticsPtr->SetLastError(
1408 VE_RTP_RTCP_MODULE_ERROR,
1409 kTraceError,
1410 "SetRecPayloadType() RTP/RTCP-module deregistration "
1411 "failed");
1412 return -1;
1413 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001414 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001415 {
1416 _engineStatisticsPtr->SetLastError(
1417 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1418 "SetRecPayloadType() ACM deregistration failed - 1");
1419 return -1;
1420 }
1421 return 0;
1422 }
1423
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001424 if (rtp_receiver_->RegisterReceivePayload(
1425 codec.plname,
1426 codec.pltype,
1427 codec.plfreq,
1428 codec.channels,
1429 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 {
1431 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001432 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1433 if (rtp_receiver_->RegisterReceivePayload(
1434 codec.plname,
1435 codec.pltype,
1436 codec.plfreq,
1437 codec.channels,
1438 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 {
1440 _engineStatisticsPtr->SetLastError(
1441 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1442 "SetRecPayloadType() RTP/RTCP-module registration failed");
1443 return -1;
1444 }
1445 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001446 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001447 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001448 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1449 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001450 {
1451 _engineStatisticsPtr->SetLastError(
1452 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1453 "SetRecPayloadType() ACM registration failed - 1");
1454 return -1;
1455 }
1456 }
1457 return 0;
1458}
1459
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001460int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001461Channel::GetRecPayloadType(CodecInst& codec)
1462{
1463 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1464 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001465 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001466 if (rtp_payload_registry_->ReceivePayloadType(
1467 codec.plname,
1468 codec.plfreq,
1469 codec.channels,
1470 (codec.rate < 0) ? 0 : codec.rate,
1471 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001472 {
1473 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001474 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 "GetRecPayloadType() failed to retrieve RX payload type");
1476 return -1;
1477 }
1478 codec.pltype = payloadType;
1479 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001480 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 return 0;
1482}
1483
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001484int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001485Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1486{
1487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "Channel::SetSendCNPayloadType()");
1489
1490 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001491 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001492 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001493 if (frequency == kFreq32000Hz)
1494 samplingFreqHz = 32000;
1495 else if (frequency == kFreq16000Hz)
1496 samplingFreqHz = 16000;
1497
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001498 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001499 {
1500 _engineStatisticsPtr->SetLastError(
1501 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1502 "SetSendCNPayloadType() failed to retrieve default CN codec "
1503 "settings");
1504 return -1;
1505 }
1506
1507 // Modify the payload type (must be set to dynamic range)
1508 codec.pltype = type;
1509
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001510 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 {
1512 _engineStatisticsPtr->SetLastError(
1513 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1514 "SetSendCNPayloadType() failed to register CN to ACM");
1515 return -1;
1516 }
1517
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001518 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001519 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001520 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1521 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001522 {
1523 _engineStatisticsPtr->SetLastError(
1524 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1525 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1526 "module");
1527 return -1;
1528 }
1529 }
1530 return 0;
1531}
1532
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001533int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001534 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001535 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001536
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001537 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001538 _engineStatisticsPtr->SetLastError(
1539 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001540 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001541 return -1;
1542 }
1543 return 0;
1544}
1545
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001546int Channel::SetOpusDtx(bool enable_dtx) {
1547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1548 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001549 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001550 : audio_coding_->DisableOpusDtx();
1551 if (ret != 0) {
1552 _engineStatisticsPtr->SetLastError(
1553 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1554 return -1;
1555 }
1556 return 0;
1557}
1558
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001559int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001560{
1561 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1562 "Channel::RegisterExternalTransport()");
1563
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001564 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001565
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 if (_externalTransport)
1567 {
1568 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1569 kTraceError,
1570 "RegisterExternalTransport() external transport already enabled");
1571 return -1;
1572 }
1573 _externalTransport = true;
1574 _transportPtr = &transport;
1575 return 0;
1576}
1577
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001578int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001579Channel::DeRegisterExternalTransport()
1580{
1581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1582 "Channel::DeRegisterExternalTransport()");
1583
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001584 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001585
niklase@google.com470e71d2011-07-07 08:21:25 +00001586 if (!_transportPtr)
1587 {
1588 _engineStatisticsPtr->SetLastError(
1589 VE_INVALID_OPERATION, kTraceWarning,
1590 "DeRegisterExternalTransport() external transport already "
1591 "disabled");
1592 return 0;
1593 }
1594 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001595 _transportPtr = NULL;
1596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1597 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001598 return 0;
1599}
1600
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001601int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001602 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001603 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1604 "Channel::ReceivedRTPPacket()");
1605
1606 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001607 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001608
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001609 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001610 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001611 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1612 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1613 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001614 return -1;
1615 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001616 header.payload_type_frequency =
1617 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001618 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001619 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001620 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001621 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001622 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001623 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001624
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001625 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001626}
1627
1628bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001629 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001630 const RTPHeader& header,
1631 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001632 if (rtp_payload_registry_->IsRtx(header)) {
1633 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001634 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001635 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001636 assert(packet_length >= header.headerLength);
1637 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001638 PayloadUnion payload_specific;
1639 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001640 &payload_specific)) {
1641 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001642 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001643 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1644 payload_specific, in_order);
1645}
1646
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001647bool Channel::HandleRtxPacket(const uint8_t* packet,
1648 size_t packet_length,
1649 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001650 if (!rtp_payload_registry_->IsRtx(header))
1651 return false;
1652
1653 // Remove the RTX header and parse the original RTP header.
1654 if (packet_length < header.headerLength)
1655 return false;
1656 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1657 return false;
1658 if (restored_packet_in_use_) {
1659 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1660 "Multiple RTX headers detected, dropping packet");
1661 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001662 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001663 uint8_t* restored_packet_ptr = restored_packet_;
1664 if (!rtp_payload_registry_->RestoreOriginalPacket(
1665 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1666 header)) {
1667 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1668 "Incoming RTX packet: invalid RTP header");
1669 return false;
1670 }
1671 restored_packet_in_use_ = true;
1672 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1673 restored_packet_in_use_ = false;
1674 return ret;
1675}
1676
1677bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1678 StreamStatistician* statistician =
1679 rtp_receive_statistics_->GetStatistician(header.ssrc);
1680 if (!statistician)
1681 return false;
1682 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001683}
1684
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001685bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1686 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001687 // Retransmissions are handled separately if RTX is enabled.
1688 if (rtp_payload_registry_->RtxEnabled())
1689 return false;
1690 StreamStatistician* statistician =
1691 rtp_receive_statistics_->GetStatistician(header.ssrc);
1692 if (!statistician)
1693 return false;
1694 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001695 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001696 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001697 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001698 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001699}
1700
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001701int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001702 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1703 "Channel::ReceivedRTCPPacket()");
1704 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001705 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001706
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001707 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001708 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001709 _engineStatisticsPtr->SetLastError(
1710 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1711 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1712 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001713
Minyue2013aec2015-05-13 14:14:42 +02001714 int64_t rtt = GetRTT(true);
1715 if (rtt == 0) {
1716 // Waiting for valid RTT.
1717 return 0;
1718 }
1719 uint32_t ntp_secs = 0;
1720 uint32_t ntp_frac = 0;
1721 uint32_t rtp_timestamp = 0;
1722 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1723 &rtp_timestamp)) {
1724 // Waiting for RTCP.
1725 return 0;
1726 }
1727
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001728 {
1729 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001730 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001731 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001732 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001733}
1734
niklase@google.com470e71d2011-07-07 08:21:25 +00001735int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001736 bool loop,
1737 FileFormats format,
1738 int startPosition,
1739 float volumeScaling,
1740 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001741 const CodecInst* codecInst)
1742{
1743 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1744 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1745 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1746 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1747 startPosition, stopPosition);
1748
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001749 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001750 {
1751 _engineStatisticsPtr->SetLastError(
1752 VE_ALREADY_PLAYING, kTraceError,
1753 "StartPlayingFileLocally() is already playing");
1754 return -1;
1755 }
1756
niklase@google.com470e71d2011-07-07 08:21:25 +00001757 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001758 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001759
1760 if (_outputFilePlayerPtr)
1761 {
1762 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1763 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1764 _outputFilePlayerPtr = NULL;
1765 }
1766
1767 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1768 _outputFilePlayerId, (const FileFormats)format);
1769
1770 if (_outputFilePlayerPtr == NULL)
1771 {
1772 _engineStatisticsPtr->SetLastError(
1773 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001774 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001775 return -1;
1776 }
1777
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001778 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001779
1780 if (_outputFilePlayerPtr->StartPlayingFile(
1781 fileName,
1782 loop,
1783 startPosition,
1784 volumeScaling,
1785 notificationTime,
1786 stopPosition,
1787 (const CodecInst*)codecInst) != 0)
1788 {
1789 _engineStatisticsPtr->SetLastError(
1790 VE_BAD_FILE, kTraceError,
1791 "StartPlayingFile() failed to start file playout");
1792 _outputFilePlayerPtr->StopPlayingFile();
1793 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1794 _outputFilePlayerPtr = NULL;
1795 return -1;
1796 }
1797 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001798 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001799 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001800
1801 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001802 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001803
1804 return 0;
1805}
1806
1807int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001808 FileFormats format,
1809 int startPosition,
1810 float volumeScaling,
1811 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001812 const CodecInst* codecInst)
1813{
1814 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1815 "Channel::StartPlayingFileLocally(format=%d,"
1816 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1817 format, volumeScaling, startPosition, stopPosition);
1818
1819 if(stream == NULL)
1820 {
1821 _engineStatisticsPtr->SetLastError(
1822 VE_BAD_FILE, kTraceError,
1823 "StartPlayingFileLocally() NULL as input stream");
1824 return -1;
1825 }
1826
1827
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001828 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001829 {
1830 _engineStatisticsPtr->SetLastError(
1831 VE_ALREADY_PLAYING, kTraceError,
1832 "StartPlayingFileLocally() is already playing");
1833 return -1;
1834 }
1835
niklase@google.com470e71d2011-07-07 08:21:25 +00001836 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001837 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001838
1839 // Destroy the old instance
1840 if (_outputFilePlayerPtr)
1841 {
1842 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1843 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1844 _outputFilePlayerPtr = NULL;
1845 }
1846
1847 // Create the instance
1848 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1849 _outputFilePlayerId,
1850 (const FileFormats)format);
1851
1852 if (_outputFilePlayerPtr == NULL)
1853 {
1854 _engineStatisticsPtr->SetLastError(
1855 VE_INVALID_ARGUMENT, kTraceError,
1856 "StartPlayingFileLocally() filePlayer format isnot correct");
1857 return -1;
1858 }
1859
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001860 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001861
1862 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1863 volumeScaling,
1864 notificationTime,
1865 stopPosition, codecInst) != 0)
1866 {
1867 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1868 "StartPlayingFile() failed to "
1869 "start file playout");
1870 _outputFilePlayerPtr->StopPlayingFile();
1871 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1872 _outputFilePlayerPtr = NULL;
1873 return -1;
1874 }
1875 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001876 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001877 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001878
1879 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001880 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001881
niklase@google.com470e71d2011-07-07 08:21:25 +00001882 return 0;
1883}
1884
1885int Channel::StopPlayingFileLocally()
1886{
1887 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1888 "Channel::StopPlayingFileLocally()");
1889
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001890 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001891 {
1892 _engineStatisticsPtr->SetLastError(
1893 VE_INVALID_OPERATION, kTraceWarning,
1894 "StopPlayingFileLocally() isnot playing");
1895 return 0;
1896 }
1897
niklase@google.com470e71d2011-07-07 08:21:25 +00001898 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001899 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001900
1901 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1902 {
1903 _engineStatisticsPtr->SetLastError(
1904 VE_STOP_RECORDING_FAILED, kTraceError,
1905 "StopPlayingFile() could not stop playing");
1906 return -1;
1907 }
1908 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1909 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1910 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001911 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001912 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001913 // _fileCritSect cannot be taken while calling
1914 // SetAnonymousMixibilityStatus. Refer to comments in
1915 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001916 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001920 "StopPlayingFile() failed to stop participant from playing as"
1921 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001922 return -1;
1923 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001924
1925 return 0;
1926}
1927
1928int Channel::IsPlayingFileLocally() const
1929{
1930 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1931 "Channel::IsPlayingFileLocally()");
1932
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001933 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001934}
1935
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001936int Channel::RegisterFilePlayingToMixer()
1937{
1938 // Return success for not registering for file playing to mixer if:
1939 // 1. playing file before playout is started on that channel.
1940 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001941 if (!channel_state_.Get().playing ||
1942 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001943 {
1944 return 0;
1945 }
1946
1947 // |_fileCritSect| cannot be taken while calling
1948 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1949 // frames can be pulled by the mixer. Since the frames are generated from
1950 // the file, _fileCritSect will be taken. This would result in a deadlock.
1951 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1952 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001953 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001954 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001955 _engineStatisticsPtr->SetLastError(
1956 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1957 "StartPlayingFile() failed to add participant as file to mixer");
1958 _outputFilePlayerPtr->StopPlayingFile();
1959 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1960 _outputFilePlayerPtr = NULL;
1961 return -1;
1962 }
1963
1964 return 0;
1965}
1966
niklase@google.com470e71d2011-07-07 08:21:25 +00001967int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001968 bool loop,
1969 FileFormats format,
1970 int startPosition,
1971 float volumeScaling,
1972 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 const CodecInst* codecInst)
1974{
1975 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1976 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1977 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1978 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1979 startPosition, stopPosition);
1980
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001981 CriticalSectionScoped cs(&_fileCritSect);
1982
1983 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001984 {
1985 _engineStatisticsPtr->SetLastError(
1986 VE_ALREADY_PLAYING, kTraceWarning,
1987 "StartPlayingFileAsMicrophone() filePlayer is playing");
1988 return 0;
1989 }
1990
niklase@google.com470e71d2011-07-07 08:21:25 +00001991 // Destroy the old instance
1992 if (_inputFilePlayerPtr)
1993 {
1994 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1995 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1996 _inputFilePlayerPtr = NULL;
1997 }
1998
1999 // Create the instance
2000 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2001 _inputFilePlayerId, (const FileFormats)format);
2002
2003 if (_inputFilePlayerPtr == NULL)
2004 {
2005 _engineStatisticsPtr->SetLastError(
2006 VE_INVALID_ARGUMENT, kTraceError,
2007 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2008 return -1;
2009 }
2010
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002011 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002012
2013 if (_inputFilePlayerPtr->StartPlayingFile(
2014 fileName,
2015 loop,
2016 startPosition,
2017 volumeScaling,
2018 notificationTime,
2019 stopPosition,
2020 (const CodecInst*)codecInst) != 0)
2021 {
2022 _engineStatisticsPtr->SetLastError(
2023 VE_BAD_FILE, kTraceError,
2024 "StartPlayingFile() failed to start file playout");
2025 _inputFilePlayerPtr->StopPlayingFile();
2026 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2027 _inputFilePlayerPtr = NULL;
2028 return -1;
2029 }
2030 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002031 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002032
2033 return 0;
2034}
2035
2036int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002037 FileFormats format,
2038 int startPosition,
2039 float volumeScaling,
2040 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002041 const CodecInst* codecInst)
2042{
2043 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2044 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2045 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2046 format, volumeScaling, startPosition, stopPosition);
2047
2048 if(stream == NULL)
2049 {
2050 _engineStatisticsPtr->SetLastError(
2051 VE_BAD_FILE, kTraceError,
2052 "StartPlayingFileAsMicrophone NULL as input stream");
2053 return -1;
2054 }
2055
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002056 CriticalSectionScoped cs(&_fileCritSect);
2057
2058 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002059 {
2060 _engineStatisticsPtr->SetLastError(
2061 VE_ALREADY_PLAYING, kTraceWarning,
2062 "StartPlayingFileAsMicrophone() is playing");
2063 return 0;
2064 }
2065
niklase@google.com470e71d2011-07-07 08:21:25 +00002066 // Destroy the old instance
2067 if (_inputFilePlayerPtr)
2068 {
2069 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2070 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2071 _inputFilePlayerPtr = NULL;
2072 }
2073
2074 // Create the instance
2075 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2076 _inputFilePlayerId, (const FileFormats)format);
2077
2078 if (_inputFilePlayerPtr == NULL)
2079 {
2080 _engineStatisticsPtr->SetLastError(
2081 VE_INVALID_ARGUMENT, kTraceError,
2082 "StartPlayingInputFile() filePlayer format isnot correct");
2083 return -1;
2084 }
2085
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002086 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002087
2088 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2089 volumeScaling, notificationTime,
2090 stopPosition, codecInst) != 0)
2091 {
2092 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2093 "StartPlayingFile() failed to start "
2094 "file playout");
2095 _inputFilePlayerPtr->StopPlayingFile();
2096 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2097 _inputFilePlayerPtr = NULL;
2098 return -1;
2099 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002100
niklase@google.com470e71d2011-07-07 08:21:25 +00002101 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002102 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002103
2104 return 0;
2105}
2106
2107int Channel::StopPlayingFileAsMicrophone()
2108{
2109 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2110 "Channel::StopPlayingFileAsMicrophone()");
2111
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002112 CriticalSectionScoped cs(&_fileCritSect);
2113
2114 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002115 {
2116 _engineStatisticsPtr->SetLastError(
2117 VE_INVALID_OPERATION, kTraceWarning,
2118 "StopPlayingFileAsMicrophone() isnot playing");
2119 return 0;
2120 }
2121
niklase@google.com470e71d2011-07-07 08:21:25 +00002122 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2123 {
2124 _engineStatisticsPtr->SetLastError(
2125 VE_STOP_RECORDING_FAILED, kTraceError,
2126 "StopPlayingFile() could not stop playing");
2127 return -1;
2128 }
2129 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2130 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2131 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002132 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002133
2134 return 0;
2135}
2136
2137int Channel::IsPlayingFileAsMicrophone() const
2138{
2139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2140 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002141 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002142}
2143
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002144int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002145 const CodecInst* codecInst)
2146{
2147 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2148 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2149
2150 if (_outputFileRecording)
2151 {
2152 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2153 "StartRecordingPlayout() is already recording");
2154 return 0;
2155 }
2156
2157 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002158 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002159 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2160
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002161 if ((codecInst != NULL) &&
2162 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002163 {
2164 _engineStatisticsPtr->SetLastError(
2165 VE_BAD_ARGUMENT, kTraceError,
2166 "StartRecordingPlayout() invalid compression");
2167 return(-1);
2168 }
2169 if(codecInst == NULL)
2170 {
2171 format = kFileFormatPcm16kHzFile;
2172 codecInst=&dummyCodec;
2173 }
2174 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2175 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2176 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2177 {
2178 format = kFileFormatWavFile;
2179 }
2180 else
2181 {
2182 format = kFileFormatCompressedFile;
2183 }
2184
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002185 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002186
2187 // Destroy the old instance
2188 if (_outputFileRecorderPtr)
2189 {
2190 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2191 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2192 _outputFileRecorderPtr = NULL;
2193 }
2194
2195 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2196 _outputFileRecorderId, (const FileFormats)format);
2197 if (_outputFileRecorderPtr == NULL)
2198 {
2199 _engineStatisticsPtr->SetLastError(
2200 VE_INVALID_ARGUMENT, kTraceError,
2201 "StartRecordingPlayout() fileRecorder format isnot correct");
2202 return -1;
2203 }
2204
2205 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2206 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2207 {
2208 _engineStatisticsPtr->SetLastError(
2209 VE_BAD_FILE, kTraceError,
2210 "StartRecordingAudioFile() failed to start file recording");
2211 _outputFileRecorderPtr->StopRecording();
2212 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2213 _outputFileRecorderPtr = NULL;
2214 return -1;
2215 }
2216 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2217 _outputFileRecording = true;
2218
2219 return 0;
2220}
2221
2222int Channel::StartRecordingPlayout(OutStream* stream,
2223 const CodecInst* codecInst)
2224{
2225 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2226 "Channel::StartRecordingPlayout()");
2227
2228 if (_outputFileRecording)
2229 {
2230 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2231 "StartRecordingPlayout() is already recording");
2232 return 0;
2233 }
2234
2235 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002236 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002237 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2238
2239 if (codecInst != NULL && codecInst->channels != 1)
2240 {
2241 _engineStatisticsPtr->SetLastError(
2242 VE_BAD_ARGUMENT, kTraceError,
2243 "StartRecordingPlayout() invalid compression");
2244 return(-1);
2245 }
2246 if(codecInst == NULL)
2247 {
2248 format = kFileFormatPcm16kHzFile;
2249 codecInst=&dummyCodec;
2250 }
2251 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2252 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2253 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2254 {
2255 format = kFileFormatWavFile;
2256 }
2257 else
2258 {
2259 format = kFileFormatCompressedFile;
2260 }
2261
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002262 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002263
2264 // Destroy the old instance
2265 if (_outputFileRecorderPtr)
2266 {
2267 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2268 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2269 _outputFileRecorderPtr = NULL;
2270 }
2271
2272 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2273 _outputFileRecorderId, (const FileFormats)format);
2274 if (_outputFileRecorderPtr == NULL)
2275 {
2276 _engineStatisticsPtr->SetLastError(
2277 VE_INVALID_ARGUMENT, kTraceError,
2278 "StartRecordingPlayout() fileRecorder format isnot correct");
2279 return -1;
2280 }
2281
2282 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2283 notificationTime) != 0)
2284 {
2285 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2286 "StartRecordingPlayout() failed to "
2287 "start file recording");
2288 _outputFileRecorderPtr->StopRecording();
2289 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2290 _outputFileRecorderPtr = NULL;
2291 return -1;
2292 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002293
niklase@google.com470e71d2011-07-07 08:21:25 +00002294 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2295 _outputFileRecording = true;
2296
2297 return 0;
2298}
2299
2300int Channel::StopRecordingPlayout()
2301{
2302 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2303 "Channel::StopRecordingPlayout()");
2304
2305 if (!_outputFileRecording)
2306 {
2307 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2308 "StopRecordingPlayout() isnot recording");
2309 return -1;
2310 }
2311
2312
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002313 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002314
2315 if (_outputFileRecorderPtr->StopRecording() != 0)
2316 {
2317 _engineStatisticsPtr->SetLastError(
2318 VE_STOP_RECORDING_FAILED, kTraceError,
2319 "StopRecording() could not stop recording");
2320 return(-1);
2321 }
2322 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2323 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2324 _outputFileRecorderPtr = NULL;
2325 _outputFileRecording = false;
2326
2327 return 0;
2328}
2329
2330void
2331Channel::SetMixWithMicStatus(bool mix)
2332{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002333 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002334 _mixFileWithMicrophone=mix;
2335}
2336
2337int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002338Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002339{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002340 int8_t currentLevel = _outputAudioLevel.Level();
2341 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2343 VoEId(_instanceId,_channelId),
2344 "GetSpeechOutputLevel() => level=%u", level);
2345 return 0;
2346}
2347
2348int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002349Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002350{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002351 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2352 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002353 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2354 VoEId(_instanceId,_channelId),
2355 "GetSpeechOutputLevelFullRange() => level=%u", level);
2356 return 0;
2357}
2358
2359int
2360Channel::SetMute(bool enable)
2361{
wu@webrtc.org63420662013-10-17 18:28:55 +00002362 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002363 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2364 "Channel::SetMute(enable=%d)", enable);
2365 _mute = enable;
2366 return 0;
2367}
2368
2369bool
2370Channel::Mute() const
2371{
wu@webrtc.org63420662013-10-17 18:28:55 +00002372 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002373 return _mute;
2374}
2375
2376int
2377Channel::SetOutputVolumePan(float left, float right)
2378{
wu@webrtc.org63420662013-10-17 18:28:55 +00002379 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2381 "Channel::SetOutputVolumePan()");
2382 _panLeft = left;
2383 _panRight = right;
2384 return 0;
2385}
2386
2387int
2388Channel::GetOutputVolumePan(float& left, float& right) const
2389{
wu@webrtc.org63420662013-10-17 18:28:55 +00002390 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002391 left = _panLeft;
2392 right = _panRight;
2393 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2394 VoEId(_instanceId,_channelId),
2395 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2396 return 0;
2397}
2398
2399int
2400Channel::SetChannelOutputVolumeScaling(float scaling)
2401{
wu@webrtc.org63420662013-10-17 18:28:55 +00002402 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2404 "Channel::SetChannelOutputVolumeScaling()");
2405 _outputGain = scaling;
2406 return 0;
2407}
2408
2409int
2410Channel::GetChannelOutputVolumeScaling(float& scaling) const
2411{
wu@webrtc.org63420662013-10-17 18:28:55 +00002412 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002413 scaling = _outputGain;
2414 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2415 VoEId(_instanceId,_channelId),
2416 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2417 return 0;
2418}
2419
niklase@google.com470e71d2011-07-07 08:21:25 +00002420int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002421 int lengthMs, int attenuationDb,
2422 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002423{
2424 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2425 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2426 playDtmfEvent);
2427
2428 _playOutbandDtmfEvent = playDtmfEvent;
2429
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002430 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002431 attenuationDb) != 0)
2432 {
2433 _engineStatisticsPtr->SetLastError(
2434 VE_SEND_DTMF_FAILED,
2435 kTraceWarning,
2436 "SendTelephoneEventOutband() failed to send event");
2437 return -1;
2438 }
2439 return 0;
2440}
2441
2442int Channel::SendTelephoneEventInband(unsigned char eventCode,
2443 int lengthMs,
2444 int attenuationDb,
2445 bool playDtmfEvent)
2446{
2447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2448 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2449 playDtmfEvent);
2450
2451 _playInbandDtmfEvent = playDtmfEvent;
2452 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2453
2454 return 0;
2455}
2456
2457int
niklase@google.com470e71d2011-07-07 08:21:25 +00002458Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2459{
2460 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2461 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002462 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002463 {
2464 _engineStatisticsPtr->SetLastError(
2465 VE_INVALID_ARGUMENT, kTraceError,
2466 "SetSendTelephoneEventPayloadType() invalid type");
2467 return -1;
2468 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002469 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002470 codec.plfreq = 8000;
2471 codec.pltype = type;
2472 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002473 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002474 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002475 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2476 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2477 _engineStatisticsPtr->SetLastError(
2478 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2479 "SetSendTelephoneEventPayloadType() failed to register send"
2480 "payload type");
2481 return -1;
2482 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002483 }
2484 _sendTelephoneEventPayloadType = type;
2485 return 0;
2486}
2487
2488int
2489Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2490{
2491 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2492 "Channel::GetSendTelephoneEventPayloadType()");
2493 type = _sendTelephoneEventPayloadType;
2494 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2495 VoEId(_instanceId,_channelId),
2496 "GetSendTelephoneEventPayloadType() => type=%u", type);
2497 return 0;
2498}
2499
niklase@google.com470e71d2011-07-07 08:21:25 +00002500int
2501Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2502{
2503 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2504 "Channel::UpdateRxVadDetection()");
2505
2506 int vadDecision = 1;
2507
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002508 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002509
2510 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2511 {
2512 OnRxVadDetected(vadDecision);
2513 _oldVadDecision = vadDecision;
2514 }
2515
2516 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2517 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2518 vadDecision);
2519 return 0;
2520}
2521
2522int
2523Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2524{
2525 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2526 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002527 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002528
2529 if (_rxVadObserverPtr)
2530 {
2531 _engineStatisticsPtr->SetLastError(
2532 VE_INVALID_OPERATION, kTraceError,
2533 "RegisterRxVadObserver() observer already enabled");
2534 return -1;
2535 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002536 _rxVadObserverPtr = &observer;
2537 _RxVadDetection = true;
2538 return 0;
2539}
2540
2541int
2542Channel::DeRegisterRxVadObserver()
2543{
2544 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2545 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002546 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002547
2548 if (!_rxVadObserverPtr)
2549 {
2550 _engineStatisticsPtr->SetLastError(
2551 VE_INVALID_OPERATION, kTraceWarning,
2552 "DeRegisterRxVadObserver() observer already disabled");
2553 return 0;
2554 }
2555 _rxVadObserverPtr = NULL;
2556 _RxVadDetection = false;
2557 return 0;
2558}
2559
2560int
2561Channel::VoiceActivityIndicator(int &activity)
2562{
2563 activity = _sendFrameType;
2564
2565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002566 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002567 return 0;
2568}
2569
2570#ifdef WEBRTC_VOICE_ENGINE_AGC
2571
2572int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002573Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002574{
2575 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2576 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2577 (int)enable, (int)mode);
2578
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002579 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002580 switch (mode)
2581 {
2582 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002583 break;
2584 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002585 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002586 break;
2587 case kAgcFixedDigital:
2588 agcMode = GainControl::kFixedDigital;
2589 break;
2590 case kAgcAdaptiveDigital:
2591 agcMode =GainControl::kAdaptiveDigital;
2592 break;
2593 default:
2594 _engineStatisticsPtr->SetLastError(
2595 VE_INVALID_ARGUMENT, kTraceError,
2596 "SetRxAgcStatus() invalid Agc mode");
2597 return -1;
2598 }
2599
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002600 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002601 {
2602 _engineStatisticsPtr->SetLastError(
2603 VE_APM_ERROR, kTraceError,
2604 "SetRxAgcStatus() failed to set Agc mode");
2605 return -1;
2606 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002607 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002608 {
2609 _engineStatisticsPtr->SetLastError(
2610 VE_APM_ERROR, kTraceError,
2611 "SetRxAgcStatus() failed to set Agc state");
2612 return -1;
2613 }
2614
2615 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002616 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002617
2618 return 0;
2619}
2620
2621int
2622Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2623{
2624 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2625 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2626
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002627 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002628 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002629 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002630
2631 enabled = enable;
2632
2633 switch (agcMode)
2634 {
2635 case GainControl::kFixedDigital:
2636 mode = kAgcFixedDigital;
2637 break;
2638 case GainControl::kAdaptiveDigital:
2639 mode = kAgcAdaptiveDigital;
2640 break;
2641 default:
2642 _engineStatisticsPtr->SetLastError(
2643 VE_APM_ERROR, kTraceError,
2644 "GetRxAgcStatus() invalid Agc mode");
2645 return -1;
2646 }
2647
2648 return 0;
2649}
2650
2651int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002652Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002653{
2654 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2655 "Channel::SetRxAgcConfig()");
2656
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002657 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002658 config.targetLeveldBOv) != 0)
2659 {
2660 _engineStatisticsPtr->SetLastError(
2661 VE_APM_ERROR, kTraceError,
2662 "SetRxAgcConfig() failed to set target peak |level|"
2663 "(or envelope) of the Agc");
2664 return -1;
2665 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002666 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002667 config.digitalCompressionGaindB) != 0)
2668 {
2669 _engineStatisticsPtr->SetLastError(
2670 VE_APM_ERROR, kTraceError,
2671 "SetRxAgcConfig() failed to set the range in |gain| the"
2672 " digital compression stage may apply");
2673 return -1;
2674 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002675 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002676 config.limiterEnable) != 0)
2677 {
2678 _engineStatisticsPtr->SetLastError(
2679 VE_APM_ERROR, kTraceError,
2680 "SetRxAgcConfig() failed to set hard limiter to the signal");
2681 return -1;
2682 }
2683
2684 return 0;
2685}
2686
2687int
2688Channel::GetRxAgcConfig(AgcConfig& config)
2689{
2690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2691 "Channel::GetRxAgcConfig(config=%?)");
2692
2693 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002694 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002695 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002696 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002697 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002698 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002699
2700 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2701 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2702 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2703 " limiterEnable=%d",
2704 config.targetLeveldBOv,
2705 config.digitalCompressionGaindB,
2706 config.limiterEnable);
2707
2708 return 0;
2709}
2710
2711#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2712
2713#ifdef WEBRTC_VOICE_ENGINE_NR
2714
2715int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002716Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002717{
2718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2719 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2720 (int)enable, (int)mode);
2721
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002722 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002723 switch (mode)
2724 {
2725
2726 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002727 break;
2728 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002729 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002730 break;
2731 case kNsConference:
2732 nsLevel = NoiseSuppression::kHigh;
2733 break;
2734 case kNsLowSuppression:
2735 nsLevel = NoiseSuppression::kLow;
2736 break;
2737 case kNsModerateSuppression:
2738 nsLevel = NoiseSuppression::kModerate;
2739 break;
2740 case kNsHighSuppression:
2741 nsLevel = NoiseSuppression::kHigh;
2742 break;
2743 case kNsVeryHighSuppression:
2744 nsLevel = NoiseSuppression::kVeryHigh;
2745 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002746 }
2747
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002748 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002749 != 0)
2750 {
2751 _engineStatisticsPtr->SetLastError(
2752 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002753 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002754 return -1;
2755 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002756 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002757 {
2758 _engineStatisticsPtr->SetLastError(
2759 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002760 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 return -1;
2762 }
2763
2764 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002765 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002766
2767 return 0;
2768}
2769
2770int
2771Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2772{
2773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2774 "Channel::GetRxNsStatus(enable=?, mode=?)");
2775
2776 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002777 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002778 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002779 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002780
2781 enabled = enable;
2782
2783 switch (ncLevel)
2784 {
2785 case NoiseSuppression::kLow:
2786 mode = kNsLowSuppression;
2787 break;
2788 case NoiseSuppression::kModerate:
2789 mode = kNsModerateSuppression;
2790 break;
2791 case NoiseSuppression::kHigh:
2792 mode = kNsHighSuppression;
2793 break;
2794 case NoiseSuppression::kVeryHigh:
2795 mode = kNsVeryHighSuppression;
2796 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 }
2798
2799 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2800 VoEId(_instanceId,_channelId),
2801 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2802 return 0;
2803}
2804
2805#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2806
2807int
niklase@google.com470e71d2011-07-07 08:21:25 +00002808Channel::SetLocalSSRC(unsigned int ssrc)
2809{
2810 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2811 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002812 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002813 {
2814 _engineStatisticsPtr->SetLastError(
2815 VE_ALREADY_SENDING, kTraceError,
2816 "SetLocalSSRC() already sending");
2817 return -1;
2818 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002819 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002820 return 0;
2821}
2822
2823int
2824Channel::GetLocalSSRC(unsigned int& ssrc)
2825{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002826 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002827 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2828 VoEId(_instanceId,_channelId),
2829 "GetLocalSSRC() => ssrc=%lu", ssrc);
2830 return 0;
2831}
2832
2833int
2834Channel::GetRemoteSSRC(unsigned int& ssrc)
2835{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002836 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002837 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2838 VoEId(_instanceId,_channelId),
2839 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2840 return 0;
2841}
2842
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002843int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002844 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002845 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002846}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002847
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002848int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2849 unsigned char id) {
2850 rtp_header_parser_->DeregisterRtpHeaderExtension(
2851 kRtpExtensionAudioLevel);
2852 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2853 kRtpExtensionAudioLevel, id)) {
2854 return -1;
2855 }
2856 return 0;
2857}
2858
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002859int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2860 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2861}
2862
2863int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2864 rtp_header_parser_->DeregisterRtpHeaderExtension(
2865 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002866 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2867 kRtpExtensionAbsoluteSendTime, id)) {
2868 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002869 }
2870 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002871}
2872
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002873void Channel::SetRTCPStatus(bool enable) {
2874 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2875 "Channel::SetRTCPStatus()");
2876 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002877}
2878
2879int
2880Channel::GetRTCPStatus(bool& enabled)
2881{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002882 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002883 enabled = (method != kRtcpOff);
2884 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2885 VoEId(_instanceId,_channelId),
2886 "GetRTCPStatus() => enabled=%d", enabled);
2887 return 0;
2888}
2889
2890int
2891Channel::SetRTCP_CNAME(const char cName[256])
2892{
2893 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2894 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002895 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002896 {
2897 _engineStatisticsPtr->SetLastError(
2898 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2899 "SetRTCP_CNAME() failed to set RTCP CNAME");
2900 return -1;
2901 }
2902 return 0;
2903}
2904
2905int
niklase@google.com470e71d2011-07-07 08:21:25 +00002906Channel::GetRemoteRTCP_CNAME(char cName[256])
2907{
2908 if (cName == NULL)
2909 {
2910 _engineStatisticsPtr->SetLastError(
2911 VE_INVALID_ARGUMENT, kTraceError,
2912 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2913 return -1;
2914 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002915 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002916 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002917 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002918 {
2919 _engineStatisticsPtr->SetLastError(
2920 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2921 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2922 return -1;
2923 }
2924 strcpy(cName, cname);
2925 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2926 VoEId(_instanceId, _channelId),
2927 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2928 return 0;
2929}
2930
2931int
2932Channel::GetRemoteRTCPData(
2933 unsigned int& NTPHigh,
2934 unsigned int& NTPLow,
2935 unsigned int& timestamp,
2936 unsigned int& playoutTimestamp,
2937 unsigned int* jitter,
2938 unsigned short* fractionLost)
2939{
2940 // --- Information from sender info in received Sender Reports
2941
2942 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002943 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002944 {
2945 _engineStatisticsPtr->SetLastError(
2946 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002947 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002948 "side");
2949 return -1;
2950 }
2951
2952 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2953 // and octet count)
2954 NTPHigh = senderInfo.NTPseconds;
2955 NTPLow = senderInfo.NTPfraction;
2956 timestamp = senderInfo.RTPtimeStamp;
2957
2958 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2959 VoEId(_instanceId, _channelId),
2960 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2961 "timestamp=%lu",
2962 NTPHigh, NTPLow, timestamp);
2963
2964 // --- Locally derived information
2965
2966 // This value is updated on each incoming RTCP packet (0 when no packet
2967 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002968 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002969
2970 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2971 VoEId(_instanceId, _channelId),
2972 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002973 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002974
2975 if (NULL != jitter || NULL != fractionLost)
2976 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002977 // Get all RTCP receiver report blocks that have been received on this
2978 // channel. If we receive RTP packets from a remote source we know the
2979 // remote SSRC and use the report block from him.
2980 // Otherwise use the first report block.
2981 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002982 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002983 remote_stats.empty()) {
2984 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2985 VoEId(_instanceId, _channelId),
2986 "GetRemoteRTCPData() failed to measure statistics due"
2987 " to lack of received RTP and/or RTCP packets");
2988 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002989 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002990
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002991 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002992 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2993 for (; it != remote_stats.end(); ++it) {
2994 if (it->remoteSSRC == remoteSSRC)
2995 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002996 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002997
2998 if (it == remote_stats.end()) {
2999 // If we have not received any RTCP packets from this SSRC it probably
3000 // means that we have not received any RTP packets.
3001 // Use the first received report block instead.
3002 it = remote_stats.begin();
3003 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003004 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003005
xians@webrtc.org79af7342012-01-31 12:22:14 +00003006 if (jitter) {
3007 *jitter = it->jitter;
3008 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3009 VoEId(_instanceId, _channelId),
3010 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3011 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003012
xians@webrtc.org79af7342012-01-31 12:22:14 +00003013 if (fractionLost) {
3014 *fractionLost = it->fractionLost;
3015 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3016 VoEId(_instanceId, _channelId),
3017 "GetRemoteRTCPData() => fractionLost = %lu",
3018 *fractionLost);
3019 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003020 }
3021 return 0;
3022}
3023
3024int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003025Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003026 unsigned int name,
3027 const char* data,
3028 unsigned short dataLengthInBytes)
3029{
3030 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3031 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003032 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003033 {
3034 _engineStatisticsPtr->SetLastError(
3035 VE_NOT_SENDING, kTraceError,
3036 "SendApplicationDefinedRTCPPacket() not sending");
3037 return -1;
3038 }
3039 if (NULL == data)
3040 {
3041 _engineStatisticsPtr->SetLastError(
3042 VE_INVALID_ARGUMENT, kTraceError,
3043 "SendApplicationDefinedRTCPPacket() invalid data value");
3044 return -1;
3045 }
3046 if (dataLengthInBytes % 4 != 0)
3047 {
3048 _engineStatisticsPtr->SetLastError(
3049 VE_INVALID_ARGUMENT, kTraceError,
3050 "SendApplicationDefinedRTCPPacket() invalid length value");
3051 return -1;
3052 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003053 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003054 if (status == kRtcpOff)
3055 {
3056 _engineStatisticsPtr->SetLastError(
3057 VE_RTCP_ERROR, kTraceError,
3058 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3059 return -1;
3060 }
3061
3062 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003063 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003064 subType,
3065 name,
3066 (const unsigned char*) data,
3067 dataLengthInBytes) != 0)
3068 {
3069 _engineStatisticsPtr->SetLastError(
3070 VE_SEND_ERROR, kTraceError,
3071 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3072 return -1;
3073 }
3074 return 0;
3075}
3076
3077int
3078Channel::GetRTPStatistics(
3079 unsigned int& averageJitterMs,
3080 unsigned int& maxJitterMs,
3081 unsigned int& discardedPackets)
3082{
niklase@google.com470e71d2011-07-07 08:21:25 +00003083 // The jitter statistics is updated for each received RTP packet and is
3084 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003085 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3086 // If RTCP is off, there is no timed thread in the RTCP module regularly
3087 // generating new stats, trigger the update manually here instead.
3088 StreamStatistician* statistician =
3089 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3090 if (statistician) {
3091 // Don't use returned statistics, use data from proxy instead so that
3092 // max jitter can be fetched atomically.
3093 RtcpStatistics s;
3094 statistician->GetStatistics(&s, true);
3095 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003096 }
3097
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003098 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003099 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003100 if (playoutFrequency > 0) {
3101 // Scale RTP statistics given the current playout frequency
3102 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3103 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003104 }
3105
3106 discardedPackets = _numberOfDiscardedPackets;
3107
3108 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3109 VoEId(_instanceId, _channelId),
3110 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003111 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003112 averageJitterMs, maxJitterMs, discardedPackets);
3113 return 0;
3114}
3115
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003116int Channel::GetRemoteRTCPReportBlocks(
3117 std::vector<ReportBlock>* report_blocks) {
3118 if (report_blocks == NULL) {
3119 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3120 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3121 return -1;
3122 }
3123
3124 // Get the report blocks from the latest received RTCP Sender or Receiver
3125 // Report. Each element in the vector contains the sender's SSRC and a
3126 // report block according to RFC 3550.
3127 std::vector<RTCPReportBlock> rtcp_report_blocks;
3128 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3129 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3130 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3131 return -1;
3132 }
3133
3134 if (rtcp_report_blocks.empty())
3135 return 0;
3136
3137 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3138 for (; it != rtcp_report_blocks.end(); ++it) {
3139 ReportBlock report_block;
3140 report_block.sender_SSRC = it->remoteSSRC;
3141 report_block.source_SSRC = it->sourceSSRC;
3142 report_block.fraction_lost = it->fractionLost;
3143 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3144 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3145 report_block.interarrival_jitter = it->jitter;
3146 report_block.last_SR_timestamp = it->lastSR;
3147 report_block.delay_since_last_SR = it->delaySinceLastSR;
3148 report_blocks->push_back(report_block);
3149 }
3150 return 0;
3151}
3152
niklase@google.com470e71d2011-07-07 08:21:25 +00003153int
3154Channel::GetRTPStatistics(CallStatistics& stats)
3155{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003156 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003157
3158 // The jitter statistics is updated for each received RTP packet and is
3159 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003160 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003161 StreamStatistician* statistician =
3162 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3163 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003164 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3165 _engineStatisticsPtr->SetLastError(
3166 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3167 "GetRTPStatistics() failed to read RTP statistics from the "
3168 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003169 }
3170
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003171 stats.fractionLost = statistics.fraction_lost;
3172 stats.cumulativeLost = statistics.cumulative_lost;
3173 stats.extendedMax = statistics.extended_max_sequence_number;
3174 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003175
3176 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3177 VoEId(_instanceId, _channelId),
3178 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003179 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003180 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3181 stats.jitterSamples);
3182
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003183 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003184 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003185 if (stats.rttMs == 0) {
3186 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3187 "GetRTPStatistics() failed to get RTT");
3188 } else {
3189 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003190 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003191 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003192
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003193 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003194
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003195 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003196 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003197 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003198 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003199
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003200 if (statistician) {
3201 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3202 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003203
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003204 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003205 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003206 {
3207 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3208 VoEId(_instanceId, _channelId),
3209 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003210 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003211 }
3212
3213 stats.bytesSent = bytesSent;
3214 stats.packetsSent = packetsSent;
3215 stats.bytesReceived = bytesReceived;
3216 stats.packetsReceived = packetsReceived;
3217
3218 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3219 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003220 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3221 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003222 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3223 stats.packetsReceived);
3224
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003225 // --- Timestamps
3226 {
3227 CriticalSectionScoped lock(ts_stats_lock_.get());
3228 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3229 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003230 return 0;
3231}
3232
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003233int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003234 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003235 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003236
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003237 if (enable) {
3238 if (redPayloadtype < 0 || redPayloadtype > 127) {
3239 _engineStatisticsPtr->SetLastError(
3240 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003241 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003242 return -1;
3243 }
3244
3245 if (SetRedPayloadType(redPayloadtype) < 0) {
3246 _engineStatisticsPtr->SetLastError(
3247 VE_CODEC_ERROR, kTraceError,
3248 "SetSecondarySendCodec() Failed to register RED ACM");
3249 return -1;
3250 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003251 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003252
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003253 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003254 _engineStatisticsPtr->SetLastError(
3255 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003256 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003257 return -1;
3258 }
3259 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003260}
3261
3262int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003263Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003264{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003265 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003266 if (enabled)
3267 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003268 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003269 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 {
3271 _engineStatisticsPtr->SetLastError(
3272 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003273 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003274 "module");
3275 return -1;
3276 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003277 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003278 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3279 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003280 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 enabled, redPayloadtype);
3282 return 0;
3283 }
3284 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3285 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003286 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003287 return 0;
3288}
3289
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003290int Channel::SetCodecFECStatus(bool enable) {
3291 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3292 "Channel::SetCodecFECStatus()");
3293
3294 if (audio_coding_->SetCodecFEC(enable) != 0) {
3295 _engineStatisticsPtr->SetLastError(
3296 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3297 "SetCodecFECStatus() failed to set FEC state");
3298 return -1;
3299 }
3300 return 0;
3301}
3302
3303bool Channel::GetCodecFECStatus() {
3304 bool enabled = audio_coding_->CodecFEC();
3305 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3306 VoEId(_instanceId, _channelId),
3307 "GetCodecFECStatus() => enabled=%d", enabled);
3308 return enabled;
3309}
3310
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003311void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3312 // None of these functions can fail.
3313 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003314 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3315 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003316 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003317 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003318 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003319 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003320}
3321
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003322// Called when we are missing one or more packets.
3323int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003324 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3325}
3326
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003327uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003328Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003329{
3330 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003331 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003332 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003333 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003334 return 0;
3335}
3336
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003337void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003338 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003339 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003340 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003341 CodecInst codec;
3342 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003343
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003344 if (!mono_recording_audio_.get()) {
3345 // Temporary space for DownConvertToCodecFormat.
3346 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003347 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003348 DownConvertToCodecFormat(audio_data,
3349 number_of_frames,
3350 number_of_channels,
3351 sample_rate,
3352 codec.channels,
3353 codec.plfreq,
3354 mono_recording_audio_.get(),
3355 &input_resampler_,
3356 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003357}
3358
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003359uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003360Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003361{
3362 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3363 "Channel::PrepareEncodeAndSend()");
3364
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003365 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003366 {
3367 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3368 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003369 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003370 }
3371
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003372 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003373 {
3374 MixOrReplaceAudioWithFile(mixingFrequency);
3375 }
3376
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003377 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3378 if (is_muted) {
3379 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003380 }
3381
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003382 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003383 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003384 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003385 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003386 if (_inputExternalMediaCallbackPtr)
3387 {
3388 _inputExternalMediaCallbackPtr->Process(
3389 _channelId,
3390 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003391 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003392 _audioFrame.samples_per_channel_,
3393 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003394 isStereo);
3395 }
3396 }
3397
3398 InsertInbandDtmfTone();
3399
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003400 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003401 size_t length =
3402 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003403 if (is_muted) {
3404 rms_level_.ProcessMuted(length);
3405 } else {
3406 rms_level_.Process(_audioFrame.data_, length);
3407 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003408 }
3409
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 return 0;
3411}
3412
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003413uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003414Channel::EncodeAndSend()
3415{
3416 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3417 "Channel::EncodeAndSend()");
3418
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003419 assert(_audioFrame.num_channels_ <= 2);
3420 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003421 {
3422 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3423 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003424 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003425 }
3426
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003427 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003428
3429 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3430
3431 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003432 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003433 // This call will trigger AudioPacketizationCallback::SendData if encoding
3434 // is done and payload is ready for packetization and transmission.
3435 // Otherwise, it will return without invoking the callback.
3436 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003437 {
3438 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3439 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003440 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003441 }
3442
Peter Kastingb7e50542015-06-11 12:55:50 -07003443 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003444 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003445}
3446
Minyue2013aec2015-05-13 14:14:42 +02003447void Channel::DisassociateSendChannel(int channel_id) {
3448 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3449 Channel* channel = associate_send_channel_.channel();
3450 if (channel && channel->ChannelId() == channel_id) {
3451 // If this channel is associated with a send channel of the specified
3452 // Channel ID, disassociate with it.
3453 ChannelOwner ref(NULL);
3454 associate_send_channel_ = ref;
3455 }
3456}
3457
niklase@google.com470e71d2011-07-07 08:21:25 +00003458int Channel::RegisterExternalMediaProcessing(
3459 ProcessingTypes type,
3460 VoEMediaProcess& processObject)
3461{
3462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3463 "Channel::RegisterExternalMediaProcessing()");
3464
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003465 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003466
3467 if (kPlaybackPerChannel == type)
3468 {
3469 if (_outputExternalMediaCallbackPtr)
3470 {
3471 _engineStatisticsPtr->SetLastError(
3472 VE_INVALID_OPERATION, kTraceError,
3473 "Channel::RegisterExternalMediaProcessing() "
3474 "output external media already enabled");
3475 return -1;
3476 }
3477 _outputExternalMediaCallbackPtr = &processObject;
3478 _outputExternalMedia = true;
3479 }
3480 else if (kRecordingPerChannel == type)
3481 {
3482 if (_inputExternalMediaCallbackPtr)
3483 {
3484 _engineStatisticsPtr->SetLastError(
3485 VE_INVALID_OPERATION, kTraceError,
3486 "Channel::RegisterExternalMediaProcessing() "
3487 "output external media already enabled");
3488 return -1;
3489 }
3490 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003491 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003492 }
3493 return 0;
3494}
3495
3496int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3497{
3498 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3499 "Channel::DeRegisterExternalMediaProcessing()");
3500
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003501 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003502
3503 if (kPlaybackPerChannel == type)
3504 {
3505 if (!_outputExternalMediaCallbackPtr)
3506 {
3507 _engineStatisticsPtr->SetLastError(
3508 VE_INVALID_OPERATION, kTraceWarning,
3509 "Channel::DeRegisterExternalMediaProcessing() "
3510 "output external media already disabled");
3511 return 0;
3512 }
3513 _outputExternalMedia = false;
3514 _outputExternalMediaCallbackPtr = NULL;
3515 }
3516 else if (kRecordingPerChannel == type)
3517 {
3518 if (!_inputExternalMediaCallbackPtr)
3519 {
3520 _engineStatisticsPtr->SetLastError(
3521 VE_INVALID_OPERATION, kTraceWarning,
3522 "Channel::DeRegisterExternalMediaProcessing() "
3523 "input external media already disabled");
3524 return 0;
3525 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003526 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003527 _inputExternalMediaCallbackPtr = NULL;
3528 }
3529
3530 return 0;
3531}
3532
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003533int Channel::SetExternalMixing(bool enabled) {
3534 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3535 "Channel::SetExternalMixing(enabled=%d)", enabled);
3536
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003537 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003538 {
3539 _engineStatisticsPtr->SetLastError(
3540 VE_INVALID_OPERATION, kTraceError,
3541 "Channel::SetExternalMixing() "
3542 "external mixing cannot be changed while playing.");
3543 return -1;
3544 }
3545
3546 _externalMixing = enabled;
3547
3548 return 0;
3549}
3550
niklase@google.com470e71d2011-07-07 08:21:25 +00003551int
niklase@google.com470e71d2011-07-07 08:21:25 +00003552Channel::GetNetworkStatistics(NetworkStatistics& stats)
3553{
3554 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3555 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003556 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003557}
3558
wu@webrtc.org24301a62013-12-13 19:17:43 +00003559void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3560 audio_coding_->GetDecodingCallStatistics(stats);
3561}
3562
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003563bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3564 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003565 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003566 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003568 "Channel::GetDelayEstimate() no valid estimate.");
3569 return false;
3570 }
3571 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3572 _recPacketDelayMs;
3573 *playout_buffer_delay_ms = playout_delay_ms_;
3574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3575 "Channel::GetDelayEstimate()");
3576 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003577}
3578
deadbeef74375882015-08-13 12:09:10 -07003579int Channel::LeastRequiredDelayMs() const {
3580 return audio_coding_->LeastRequiredDelayMs();
3581}
3582
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003583int Channel::SetInitialPlayoutDelay(int delay_ms)
3584{
3585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3586 "Channel::SetInitialPlayoutDelay()");
3587 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3588 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3589 {
3590 _engineStatisticsPtr->SetLastError(
3591 VE_INVALID_ARGUMENT, kTraceError,
3592 "SetInitialPlayoutDelay() invalid min delay");
3593 return -1;
3594 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003595 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003596 {
3597 _engineStatisticsPtr->SetLastError(
3598 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3599 "SetInitialPlayoutDelay() failed to set min playout delay");
3600 return -1;
3601 }
3602 return 0;
3603}
3604
3605
niklase@google.com470e71d2011-07-07 08:21:25 +00003606int
3607Channel::SetMinimumPlayoutDelay(int delayMs)
3608{
3609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3610 "Channel::SetMinimumPlayoutDelay()");
3611 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3612 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3613 {
3614 _engineStatisticsPtr->SetLastError(
3615 VE_INVALID_ARGUMENT, kTraceError,
3616 "SetMinimumPlayoutDelay() invalid min delay");
3617 return -1;
3618 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003619 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003620 {
3621 _engineStatisticsPtr->SetLastError(
3622 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3623 "SetMinimumPlayoutDelay() failed to set min playout delay");
3624 return -1;
3625 }
3626 return 0;
3627}
3628
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003629int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3631 "Channel::GetPlayoutTimestamp()");
deadbeef74375882015-08-13 12:09:10 -07003632 uint32_t playout_timestamp_rtp = 0;
3633 {
3634 CriticalSectionScoped cs(video_sync_lock_.get());
3635 playout_timestamp_rtp = playout_timestamp_rtp_;
3636 }
3637 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003638 _engineStatisticsPtr->SetLastError(
3639 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3640 "GetPlayoutTimestamp() failed to retrieve timestamp");
3641 return -1;
3642 }
deadbeef74375882015-08-13 12:09:10 -07003643 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003644 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3645 VoEId(_instanceId,_channelId),
3646 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3647 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003648}
3649
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003650int Channel::SetInitTimestamp(unsigned int timestamp) {
3651 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003652 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003653 if (channel_state_.Get().sending) {
3654 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3655 "SetInitTimestamp() already sending");
3656 return -1;
3657 }
3658 _rtpRtcpModule->SetStartTimestamp(timestamp);
3659 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003660}
3661
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003662int Channel::SetInitSequenceNumber(short sequenceNumber) {
3663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3664 "Channel::SetInitSequenceNumber()");
3665 if (channel_state_.Get().sending) {
3666 _engineStatisticsPtr->SetLastError(
3667 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3668 return -1;
3669 }
3670 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3671 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003672}
3673
3674int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003675Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003676{
3677 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3678 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003679 *rtpRtcpModule = _rtpRtcpModule.get();
3680 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003681 return 0;
3682}
3683
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003684// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3685// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003686int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003687Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003688{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003689 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003690 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003691
3692 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003693 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003694
3695 if (_inputFilePlayerPtr == NULL)
3696 {
3697 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3698 VoEId(_instanceId, _channelId),
3699 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3700 " doesnt exist");
3701 return -1;
3702 }
3703
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003704 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003705 fileSamples,
3706 mixingFrequency) == -1)
3707 {
3708 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3709 VoEId(_instanceId, _channelId),
3710 "Channel::MixOrReplaceAudioWithFile() file mixing "
3711 "failed");
3712 return -1;
3713 }
3714 if (fileSamples == 0)
3715 {
3716 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3717 VoEId(_instanceId, _channelId),
3718 "Channel::MixOrReplaceAudioWithFile() file is ended");
3719 return 0;
3720 }
3721 }
3722
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003723 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003724
3725 if (_mixFileWithMicrophone)
3726 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003727 // Currently file stream is always mono.
3728 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003729 MixWithSat(_audioFrame.data_,
3730 _audioFrame.num_channels_,
3731 fileBuffer.get(),
3732 1,
3733 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003734 }
3735 else
3736 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003737 // Replace ACM audio with file.
3738 // Currently file stream is always mono.
3739 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003740 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003741 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003742 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003743 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003744 mixingFrequency,
3745 AudioFrame::kNormalSpeech,
3746 AudioFrame::kVadUnknown,
3747 1);
3748
3749 }
3750 return 0;
3751}
3752
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003753int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003754Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003755 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003756{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003757 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003758
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003759 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003760 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003761
3762 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003763 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003764
3765 if (_outputFilePlayerPtr == NULL)
3766 {
3767 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3768 VoEId(_instanceId, _channelId),
3769 "Channel::MixAudioWithFile() file mixing failed");
3770 return -1;
3771 }
3772
3773 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003774 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003775 fileSamples,
3776 mixingFrequency) == -1)
3777 {
3778 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3779 VoEId(_instanceId, _channelId),
3780 "Channel::MixAudioWithFile() file mixing failed");
3781 return -1;
3782 }
3783 }
3784
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003785 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003786 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003787 // Currently file stream is always mono.
3788 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003789 MixWithSat(audioFrame.data_,
3790 audioFrame.num_channels_,
3791 fileBuffer.get(),
3792 1,
3793 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003794 }
3795 else
3796 {
3797 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003798 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3799 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003800 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003801 return -1;
3802 }
3803
3804 return 0;
3805}
3806
3807int
3808Channel::InsertInbandDtmfTone()
3809{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003810 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003811 if (_inbandDtmfQueue.PendingDtmf() &&
3812 !_inbandDtmfGenerator.IsAddingTone() &&
3813 _inbandDtmfGenerator.DelaySinceLastTone() >
3814 kMinTelephoneEventSeparationMs)
3815 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003816 int8_t eventCode(0);
3817 uint16_t lengthMs(0);
3818 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003819
3820 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3821 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3822 if (_playInbandDtmfEvent)
3823 {
3824 // Add tone to output mixer using a reduced length to minimize
3825 // risk of echo.
3826 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3827 attenuationDb);
3828 }
3829 }
3830
3831 if (_inbandDtmfGenerator.IsAddingTone())
3832 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003833 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003834 _inbandDtmfGenerator.GetSampleRate(frequency);
3835
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003836 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003837 {
3838 // Update sample rate of Dtmf tone since the mixing frequency
3839 // has changed.
3840 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003841 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003842 // Reset the tone to be added taking the new sample rate into
3843 // account.
3844 _inbandDtmfGenerator.ResetTone();
3845 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003846
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003847 int16_t toneBuffer[320];
3848 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003849 // Get 10ms tone segment and set time since last tone to zero
3850 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3851 {
3852 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3853 VoEId(_instanceId, _channelId),
3854 "Channel::EncodeAndSend() inserting Dtmf failed");
3855 return -1;
3856 }
3857
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003858 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003859 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003860 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003861 sample++)
3862 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003863 for (int channel = 0;
3864 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003865 channel++)
3866 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003867 const size_t index =
3868 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003869 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003870 }
3871 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003872
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003873 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003874 } else
3875 {
3876 // Add 10ms to "delay-since-last-tone" counter
3877 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3878 }
3879 return 0;
3880}
3881
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003882int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003883Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003884{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003885 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003886 if (_transportPtr == NULL)
3887 {
3888 return -1;
3889 }
3890 if (!RTCP)
3891 {
3892 return _transportPtr->SendPacket(_channelId, data, len);
3893 }
3894 else
3895 {
3896 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3897 }
3898}
3899
deadbeef74375882015-08-13 12:09:10 -07003900void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3901 uint32_t playout_timestamp = 0;
3902
3903 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3904 // This can happen if this channel has not been received any RTP packet. In
3905 // this case, NetEq is not capable of computing playout timestamp.
3906 return;
3907 }
3908
3909 uint16_t delay_ms = 0;
3910 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3911 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3912 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3913 " delay from the ADM");
3914 _engineStatisticsPtr->SetLastError(
3915 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3916 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3917 return;
3918 }
3919
3920 jitter_buffer_playout_timestamp_ = playout_timestamp;
3921
3922 // Remove the playout delay.
3923 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3924
3925 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3926 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3927 playout_timestamp);
3928
3929 {
3930 CriticalSectionScoped cs(video_sync_lock_.get());
3931 if (rtcp) {
3932 playout_timestamp_rtcp_ = playout_timestamp;
3933 } else {
3934 playout_timestamp_rtp_ = playout_timestamp;
3935 }
3936 playout_delay_ms_ = delay_ms;
3937 }
3938}
3939
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003940// Called for incoming RTP packets after successful RTP header parsing.
3941void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3942 uint16_t sequence_number) {
3943 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3944 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3945 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003946
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003947 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003948 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003949
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003950 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3951 // every incoming packet.
3952 uint32_t timestamp_diff_ms = (rtp_timestamp -
3953 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003954 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3955 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3956 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3957 // timestamp, the resulting difference is negative, but is set to zero.
3958 // This can happen when a network glitch causes a packet to arrive late,
3959 // and during long comfort noise periods with clock drift.
3960 timestamp_diff_ms = 0;
3961 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003962
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003963 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3964 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003965
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003967
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003968 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003969
deadbeef74375882015-08-13 12:09:10 -07003970 {
3971 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003972
deadbeef74375882015-08-13 12:09:10 -07003973 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3974 _recPacketDelayMs = packet_delay_ms;
3975 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003976
deadbeef74375882015-08-13 12:09:10 -07003977 if (_average_jitter_buffer_delay_us == 0) {
3978 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3979 return;
3980 }
3981
3982 // Filter average delay value using exponential filter (alpha is
3983 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3984 // risk of rounding error) and compensate for it in GetDelayEstimate()
3985 // later.
3986 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3987 1000 * timestamp_diff_ms + 500) / 8;
3988 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003989}
3990
3991void
3992Channel::RegisterReceiveCodecsToRTPModule()
3993{
3994 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3995 "Channel::RegisterReceiveCodecsToRTPModule()");
3996
3997
3998 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003999 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004000
4001 for (int idx = 0; idx < nSupportedCodecs; idx++)
4002 {
4003 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004004 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004005 (rtp_receiver_->RegisterReceivePayload(
4006 codec.plname,
4007 codec.pltype,
4008 codec.plfreq,
4009 codec.channels,
4010 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004011 {
4012 WEBRTC_TRACE(
4013 kTraceWarning,
4014 kTraceVoice,
4015 VoEId(_instanceId, _channelId),
4016 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4017 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4018 codec.plname, codec.pltype, codec.plfreq,
4019 codec.channels, codec.rate);
4020 }
4021 else
4022 {
4023 WEBRTC_TRACE(
4024 kTraceInfo,
4025 kTraceVoice,
4026 VoEId(_instanceId, _channelId),
4027 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004028 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004029 "receiver",
4030 codec.plname, codec.pltype, codec.plfreq,
4031 codec.channels, codec.rate);
4032 }
4033 }
4034}
4035
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004036// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004037int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004038 CodecInst codec;
4039 bool found_red = false;
4040
4041 // Get default RED settings from the ACM database
4042 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4043 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004044 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004045 if (!STR_CASE_CMP(codec.plname, "RED")) {
4046 found_red = true;
4047 break;
4048 }
4049 }
4050
4051 if (!found_red) {
4052 _engineStatisticsPtr->SetLastError(
4053 VE_CODEC_ERROR, kTraceError,
4054 "SetRedPayloadType() RED is not supported");
4055 return -1;
4056 }
4057
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004058 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004059 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004060 _engineStatisticsPtr->SetLastError(
4061 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4062 "SetRedPayloadType() RED registration in ACM module failed");
4063 return -1;
4064 }
4065
4066 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4067 _engineStatisticsPtr->SetLastError(
4068 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4069 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4070 return -1;
4071 }
4072 return 0;
4073}
4074
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004075int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4076 unsigned char id) {
4077 int error = 0;
4078 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4079 if (enable) {
4080 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4081 }
4082 return error;
4083}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004084
wu@webrtc.org94454b72014-06-05 20:34:08 +00004085int32_t Channel::GetPlayoutFrequency() {
4086 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4087 CodecInst current_recive_codec;
4088 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4089 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4090 // Even though the actual sampling rate for G.722 audio is
4091 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4092 // 8,000 Hz because that value was erroneously assigned in
4093 // RFC 1890 and must remain unchanged for backward compatibility.
4094 playout_frequency = 8000;
4095 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4096 // We are resampling Opus internally to 32,000 Hz until all our
4097 // DSP routines can operate at 48,000 Hz, but the RTP clock
4098 // rate for the Opus payload format is standardized to 48,000 Hz,
4099 // because that is the maximum supported decoding sampling rate.
4100 playout_frequency = 48000;
4101 }
4102 }
4103 return playout_frequency;
4104}
4105
Minyue2013aec2015-05-13 14:14:42 +02004106int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004107 RTCPMethod method = _rtpRtcpModule->RTCP();
4108 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004109 return 0;
4110 }
4111 std::vector<RTCPReportBlock> report_blocks;
4112 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004113
4114 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004115 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004116 if (allow_associate_channel) {
4117 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4118 Channel* channel = associate_send_channel_.channel();
4119 // Tries to get RTT from an associated channel. This is important for
4120 // receive-only channels.
4121 if (channel) {
4122 // To prevent infinite recursion and deadlock, calling GetRTT of
4123 // associate channel should always use "false" for argument:
4124 // |allow_associate_channel|.
4125 rtt = channel->GetRTT(false);
4126 }
4127 }
4128 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004129 }
4130
4131 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4132 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4133 for (; it != report_blocks.end(); ++it) {
4134 if (it->remoteSSRC == remoteSSRC)
4135 break;
4136 }
4137 if (it == report_blocks.end()) {
4138 // We have not received packets with SSRC matching the report blocks.
4139 // To calculate RTT we try with the SSRC of the first report block.
4140 // This is very important for send-only channels where we don't know
4141 // the SSRC of the other end.
4142 remoteSSRC = report_blocks[0].remoteSSRC;
4143 }
Minyue2013aec2015-05-13 14:14:42 +02004144
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004145 int64_t avg_rtt = 0;
4146 int64_t max_rtt= 0;
4147 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004148 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4149 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004150 return 0;
4151 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004152 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004153}
4154
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004155} // namespace voe
4156} // namespace webrtc