blob: d602bb4fdfc47bd63d44c66e780d29129fb7c726 [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
ivocb04965c2015-09-09 00:09:43 -0700631int32_t Channel::CreateChannel(Channel*& channel,
632 int32_t channelId,
633 uint32_t instanceId,
634 RtcEventLog* const event_log,
635 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
637 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
638 channelId, instanceId);
639
ivocb04965c2015-09-09 00:09:43 -0700640 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 if (channel == NULL)
642 {
643 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
644 VoEId(instanceId,channelId),
645 "Channel::CreateChannel() unable to allocate memory for"
646 " channel");
647 return -1;
648 }
649 return 0;
650}
651
652void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000653Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000654{
655 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
656 "Channel::PlayNotification(id=%d, durationMs=%d)",
657 id, durationMs);
658
659 // Not implement yet
660}
661
662void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000663Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000664{
665 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
666 "Channel::RecordNotification(id=%d, durationMs=%d)",
667 id, durationMs);
668
669 // Not implement yet
670}
671
672void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000673Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000674{
675 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
676 "Channel::PlayFileEnded(id=%d)", id);
677
678 if (id == _inputFilePlayerId)
679 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000680 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
682 VoEId(_instanceId,_channelId),
683 "Channel::PlayFileEnded() => input file player module is"
684 " shutdown");
685 }
686 else if (id == _outputFilePlayerId)
687 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000688 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000689 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
690 VoEId(_instanceId,_channelId),
691 "Channel::PlayFileEnded() => output file player module is"
692 " shutdown");
693 }
694}
695
696void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000697Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000698{
699 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
700 "Channel::RecordFileEnded(id=%d)", id);
701
702 assert(id == _outputFileRecorderId);
703
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000704 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000705
706 _outputFileRecording = false;
707 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
708 VoEId(_instanceId,_channelId),
709 "Channel::RecordFileEnded() => output file recorder module is"
710 " shutdown");
711}
712
pbos@webrtc.org92135212013-05-14 08:31:39 +0000713Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000714 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700715 RtcEventLog* const event_log,
716 const Config& config)
717 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 _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))),
ivocb04965c2015-09-09 00:09:43 -0700725 rtp_receive_statistics_(
726 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
727 rtp_receiver_(
728 RtpReceiver::CreateAudioReceiver(VoEModuleId(instanceId, channelId),
729 Clock::GetRealTimeClock(),
730 this,
731 this,
732 this,
733 rtp_payload_registry_.get())),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000734 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000735 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 _inputFilePlayerPtr(NULL),
738 _outputFilePlayerPtr(NULL),
739 _outputFileRecorderPtr(NULL),
740 // Avoid conflict with other channels by adding 1024 - 1026,
741 // won't use as much as 1024 channels.
742 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
743 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
744 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000746 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
747 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000748 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000749 _inputExternalMediaCallbackPtr(NULL),
750 _outputExternalMediaCallbackPtr(NULL),
ivocb04965c2015-09-09 00:09:43 -0700751 _timeStamp(0), // This is just an offset, RTP module will add it's own
752 // random offset
xians@google.com22963ab2011-08-03 12:40:23 +0000753 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000754 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000755 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000756 playout_timestamp_rtp_(0),
757 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000758 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000759 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000760 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000761 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000762 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
763 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000764 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000765 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000766 _outputMixerPtr(NULL),
767 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000768 _moduleProcessThreadPtr(NULL),
769 _audioDeviceModulePtr(NULL),
770 _voiceEngineObserverPtr(NULL),
771 _callbackCritSectPtr(NULL),
772 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000773 _rxVadObserverPtr(NULL),
774 _oldVadDecision(-1),
775 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000776 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000777 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000778 _mute(false),
779 _panLeft(1.0f),
780 _panRight(1.0f),
781 _outputGain(1.0f),
782 _playOutbandDtmfEvent(false),
783 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000784 _lastLocalTimeStamp(0),
785 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000786 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000787 _outputSpeechType(AudioFrame::kNormalSpeech),
deadbeef74375882015-08-13 12:09:10 -0700788 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000789 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000790 _previousTimestamp(0),
791 _recPacketDelayMs(20),
792 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000793 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000794 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000795 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000796 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200797 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
798 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
ivocb04965c2015-09-09 00:09:43 -0700799 associate_send_channel_(ChannelOwner(nullptr)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000800 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
801 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200802 AudioCodingModule::Config acm_config;
803 acm_config.id = VoEModuleId(instanceId, channelId);
804 if (config.Get<NetEqCapacityConfig>().enabled) {
805 // Clamping the buffer capacity at 20 packets. While going lower will
806 // probably work, it makes little sense.
807 acm_config.neteq_config.max_packets_in_buffer =
808 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
809 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200810 acm_config.neteq_config.enable_fast_accelerate =
811 config.Get<NetEqFastAccelerate>().enabled;
ivocb04965c2015-09-09 00:09:43 -0700812 acm_config.event_log = event_log;
Henrik Lundin64dad832015-05-11 12:44:23 +0200813 audio_coding_.reset(AudioCodingModule::Create(acm_config));
814
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 _inbandDtmfQueue.ResetDtmf();
816 _inbandDtmfGenerator.Init();
817 _outputAudioLevel.Clear();
818
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000819 RtpRtcp::Configuration configuration;
820 configuration.id = VoEModuleId(instanceId, channelId);
821 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000822 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000823 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000824 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000825 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000826
827 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000828
829 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
830 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
831 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000832
833 Config audioproc_config;
834 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
835 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000836}
837
838Channel::~Channel()
839{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000840 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
842 "Channel::~Channel() - dtor");
843
844 if (_outputExternalMedia)
845 {
846 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
847 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000848 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 {
850 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
851 }
852 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 StopPlayout();
854
855 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000856 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000857 if (_inputFilePlayerPtr)
858 {
859 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
860 _inputFilePlayerPtr->StopPlayingFile();
861 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
862 _inputFilePlayerPtr = NULL;
863 }
864 if (_outputFilePlayerPtr)
865 {
866 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
867 _outputFilePlayerPtr->StopPlayingFile();
868 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
869 _outputFilePlayerPtr = NULL;
870 }
871 if (_outputFileRecorderPtr)
872 {
873 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
874 _outputFileRecorderPtr->StopRecording();
875 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
876 _outputFileRecorderPtr = NULL;
877 }
878 }
879
880 // The order to safely shutdown modules in a channel is:
881 // 1. De-register callbacks in modules
882 // 2. De-register modules in process thread
883 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000884 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 {
886 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
887 VoEId(_instanceId,_channelId),
888 "~Channel() failed to de-register transport callback"
889 " (Audio coding module)");
890 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000891 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 {
893 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
894 VoEId(_instanceId,_channelId),
895 "~Channel() failed to de-register VAD callback"
896 " (Audio coding module)");
897 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000899 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
900
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 // End of modules shutdown
902
903 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000906 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000907}
908
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000909int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000910Channel::Init()
911{
912 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
913 "Channel::Init()");
914
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000915 channel_state_.Reset();
916
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 // --- Initial sanity
918
919 if ((_engineStatisticsPtr == NULL) ||
920 (_moduleProcessThreadPtr == NULL))
921 {
922 WEBRTC_TRACE(kTraceError, kTraceVoice,
923 VoEId(_instanceId,_channelId),
924 "Channel::Init() must call SetEngineInformation() first");
925 return -1;
926 }
927
928 // --- Add modules to process thread (for periodic schedulation)
929
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000930 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
931
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000932 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000933
Henrik Lundin45c64492015-03-30 19:00:44 +0200934 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000935#ifdef WEBRTC_CODEC_AVT
936 // out-of-band Dtmf tones are played out by default
Henrik Lundin45c64492015-03-30 19:00:44 +0200937 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000938#endif
Henrik Lundin45c64492015-03-30 19:00:44 +0200939 )
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 {
941 _engineStatisticsPtr->SetLastError(
942 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
943 "Channel::Init() unable to initialize the ACM - 1");
944 return -1;
945 }
946
947 // --- RTP/RTCP module initialization
948
949 // Ensure that RTCP is enabled by default for the created channel.
950 // Note that, the module will keep generating RTCP until it is explicitly
951 // disabled by the user.
952 // After StopListen (when no sockets exists), RTCP packets will no longer
953 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000954 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
955 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000956 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
957 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000959 (audio_coding_->RegisterTransportCallback(this) == -1) ||
960 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000961
962 if (fail)
963 {
964 _engineStatisticsPtr->SetLastError(
965 VE_CANNOT_INIT_CHANNEL, kTraceError,
966 "Channel::Init() callbacks not registered");
967 return -1;
968 }
969
970 // --- Register all supported codecs to the receiving side of the
971 // RTP/RTCP module
972
973 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000974 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000975
976 for (int idx = 0; idx < nSupportedCodecs; idx++)
977 {
978 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000979 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000980 (rtp_receiver_->RegisterReceivePayload(
981 codec.plname,
982 codec.pltype,
983 codec.plfreq,
984 codec.channels,
985 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000986 {
987 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
988 VoEId(_instanceId,_channelId),
989 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
990 "to RTP/RTCP receiver",
991 codec.plname, codec.pltype, codec.plfreq,
992 codec.channels, codec.rate);
993 }
994 else
995 {
996 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
997 VoEId(_instanceId,_channelId),
998 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
999 "the RTP/RTCP receiver",
1000 codec.plname, codec.pltype, codec.plfreq,
1001 codec.channels, codec.rate);
1002 }
1003
1004 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001005 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 {
1007 SetSendCodec(codec);
1008 }
1009
1010 // Register default PT for outband 'telephone-event'
1011 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1012 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001013 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001014 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
1016 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1017 VoEId(_instanceId,_channelId),
1018 "Channel::Init() failed to register outband "
1019 "'telephone-event' (%d/%d) correctly",
1020 codec.pltype, codec.plfreq);
1021 }
1022 }
1023
1024 if (!STR_CASE_CMP(codec.plname, "CN"))
1025 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001026 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1027 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001028 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 {
1030 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1031 VoEId(_instanceId,_channelId),
1032 "Channel::Init() failed to register CN (%d/%d) "
1033 "correctly - 1",
1034 codec.pltype, codec.plfreq);
1035 }
1036 }
1037#ifdef WEBRTC_CODEC_RED
1038 // Register RED to the receiving side of the ACM.
1039 // We will not receive an OnInitializeDecoder() callback for RED.
1040 if (!STR_CASE_CMP(codec.plname, "RED"))
1041 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001042 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
1044 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1045 VoEId(_instanceId,_channelId),
1046 "Channel::Init() failed to register RED (%d/%d) "
1047 "correctly",
1048 codec.pltype, codec.plfreq);
1049 }
1050 }
1051#endif
1052 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001053
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001054 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1055 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1056 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001058 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1059 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1060 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 }
1062
1063 return 0;
1064}
1065
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001066int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001067Channel::SetEngineInformation(Statistics& engineStatistics,
1068 OutputMixer& outputMixer,
1069 voe::TransmitMixer& transmitMixer,
1070 ProcessThread& moduleProcessThread,
1071 AudioDeviceModule& audioDeviceModule,
1072 VoiceEngineObserver* voiceEngineObserver,
1073 CriticalSectionWrapper* callbackCritSect)
1074{
1075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1076 "Channel::SetEngineInformation()");
1077 _engineStatisticsPtr = &engineStatistics;
1078 _outputMixerPtr = &outputMixer;
1079 _transmitMixerPtr = &transmitMixer,
1080 _moduleProcessThreadPtr = &moduleProcessThread;
1081 _audioDeviceModulePtr = &audioDeviceModule;
1082 _voiceEngineObserverPtr = voiceEngineObserver;
1083 _callbackCritSectPtr = callbackCritSect;
1084 return 0;
1085}
1086
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001087int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001088Channel::UpdateLocalTimeStamp()
1089{
1090
Peter Kastingb7e50542015-06-11 12:55:50 -07001091 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 return 0;
1093}
1094
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001095int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001096Channel::StartPlayout()
1097{
1098 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1099 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001100 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001101 {
1102 return 0;
1103 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001104
1105 if (!_externalMixing) {
1106 // Add participant as candidates for mixing.
1107 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1108 {
1109 _engineStatisticsPtr->SetLastError(
1110 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1111 "StartPlayout() failed to add participant to mixer");
1112 return -1;
1113 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001114 }
1115
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001116 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001117 if (RegisterFilePlayingToMixer() != 0)
1118 return -1;
1119
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 return 0;
1121}
1122
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001123int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001124Channel::StopPlayout()
1125{
1126 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1127 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001128 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 {
1130 return 0;
1131 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001132
1133 if (!_externalMixing) {
1134 // Remove participant as candidates for mixing
1135 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1136 {
1137 _engineStatisticsPtr->SetLastError(
1138 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1139 "StopPlayout() failed to remove participant from mixer");
1140 return -1;
1141 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 }
1143
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001144 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 _outputAudioLevel.Clear();
1146
1147 return 0;
1148}
1149
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001150int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001151Channel::StartSend()
1152{
1153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1154 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001155 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001156 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001157 if (send_sequence_number_)
1158 SetInitSequenceNumber(send_sequence_number_);
1159
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001160 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001162 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001164 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001165
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001166 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001167 {
1168 _engineStatisticsPtr->SetLastError(
1169 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1170 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001171 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001172 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001173 return -1;
1174 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001175
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 return 0;
1177}
1178
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001179int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001180Channel::StopSend()
1181{
1182 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1183 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001184 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001186 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001189
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001190 // Store the sequence number to be able to pick up the same sequence for
1191 // the next StartSend(). This is needed for restarting device, otherwise
1192 // it might cause libSRTP to complain about packets being replayed.
1193 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1194 // CL is landed. See issue
1195 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1196 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1197
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 // Reset sending SSRC and sequence number and triggers direct transmission
1199 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001200 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 {
1202 _engineStatisticsPtr->SetLastError(
1203 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1204 "StartSend() RTP/RTCP failed to stop sending");
1205 }
1206
niklase@google.com470e71d2011-07-07 08:21:25 +00001207 return 0;
1208}
1209
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001210int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001211Channel::StartReceiving()
1212{
1213 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1214 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001215 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 {
1217 return 0;
1218 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001219 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001220 _numberOfDiscardedPackets = 0;
1221 return 0;
1222}
1223
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001224int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001225Channel::StopReceiving()
1226{
1227 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1228 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001229 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 {
1231 return 0;
1232 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001233
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001234 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 return 0;
1236}
1237
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001238int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001239Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1240{
1241 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1242 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001243 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001244
1245 if (_voiceEngineObserverPtr)
1246 {
1247 _engineStatisticsPtr->SetLastError(
1248 VE_INVALID_OPERATION, kTraceError,
1249 "RegisterVoiceEngineObserver() observer already enabled");
1250 return -1;
1251 }
1252 _voiceEngineObserverPtr = &observer;
1253 return 0;
1254}
1255
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001256int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001257Channel::DeRegisterVoiceEngineObserver()
1258{
1259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1260 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001261 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001262
1263 if (!_voiceEngineObserverPtr)
1264 {
1265 _engineStatisticsPtr->SetLastError(
1266 VE_INVALID_OPERATION, kTraceWarning,
1267 "DeRegisterVoiceEngineObserver() observer already disabled");
1268 return 0;
1269 }
1270 _voiceEngineObserverPtr = NULL;
1271 return 0;
1272}
1273
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001274int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001275Channel::GetSendCodec(CodecInst& codec)
1276{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001277 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001278}
1279
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001280int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001281Channel::GetRecCodec(CodecInst& codec)
1282{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001283 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001284}
1285
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001286int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001287Channel::SetSendCodec(const CodecInst& codec)
1288{
1289 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1290 "Channel::SetSendCodec()");
1291
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001292 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 {
1294 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1295 "SetSendCodec() failed to register codec to ACM");
1296 return -1;
1297 }
1298
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001299 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001301 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1302 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001303 {
1304 WEBRTC_TRACE(
1305 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1306 "SetSendCodec() failed to register codec to"
1307 " RTP/RTCP module");
1308 return -1;
1309 }
1310 }
1311
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001312 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001313 {
1314 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1315 "SetSendCodec() failed to set audio packet size");
1316 return -1;
1317 }
1318
1319 return 0;
1320}
1321
Ivo Creusenadf89b72015-04-29 16:03:33 +02001322void Channel::SetBitRate(int bitrate_bps) {
1323 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1324 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1325 audio_coding_->SetBitRate(bitrate_bps);
1326}
1327
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001328void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001329 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001330 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1331
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001332 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001333 if (audio_coding_->SetPacketLossRate(
1334 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001335 assert(false); // This should not happen.
1336 }
1337}
1338
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001339int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001340Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1341{
1342 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1343 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001344 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001345 // To disable VAD, DTX must be disabled too
1346 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001347 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001348 {
1349 _engineStatisticsPtr->SetLastError(
1350 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1351 "SetVADStatus() failed to set VAD");
1352 return -1;
1353 }
1354 return 0;
1355}
1356
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001357int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001358Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1359{
1360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1361 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001362 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 {
1364 _engineStatisticsPtr->SetLastError(
1365 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1366 "GetVADStatus() failed to get VAD status");
1367 return -1;
1368 }
1369 disabledDTX = !disabledDTX;
1370 return 0;
1371}
1372
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001373int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001374Channel::SetRecPayloadType(const CodecInst& codec)
1375{
1376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1377 "Channel::SetRecPayloadType()");
1378
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001379 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001380 {
1381 _engineStatisticsPtr->SetLastError(
1382 VE_ALREADY_PLAYING, kTraceError,
1383 "SetRecPayloadType() unable to set PT while playing");
1384 return -1;
1385 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001386 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001387 {
1388 _engineStatisticsPtr->SetLastError(
1389 VE_ALREADY_LISTENING, kTraceError,
1390 "SetRecPayloadType() unable to set PT while listening");
1391 return -1;
1392 }
1393
1394 if (codec.pltype == -1)
1395 {
1396 // De-register the selected codec (RTP/RTCP module and ACM)
1397
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001398 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001399 CodecInst rxCodec = codec;
1400
1401 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001402 rtp_payload_registry_->ReceivePayloadType(
1403 rxCodec.plname,
1404 rxCodec.plfreq,
1405 rxCodec.channels,
1406 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1407 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001408 rxCodec.pltype = pltype;
1409
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001410 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 {
1412 _engineStatisticsPtr->SetLastError(
1413 VE_RTP_RTCP_MODULE_ERROR,
1414 kTraceError,
1415 "SetRecPayloadType() RTP/RTCP-module deregistration "
1416 "failed");
1417 return -1;
1418 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001419 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001420 {
1421 _engineStatisticsPtr->SetLastError(
1422 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1423 "SetRecPayloadType() ACM deregistration failed - 1");
1424 return -1;
1425 }
1426 return 0;
1427 }
1428
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001429 if (rtp_receiver_->RegisterReceivePayload(
1430 codec.plname,
1431 codec.pltype,
1432 codec.plfreq,
1433 codec.channels,
1434 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 {
1436 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001437 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1438 if (rtp_receiver_->RegisterReceivePayload(
1439 codec.plname,
1440 codec.pltype,
1441 codec.plfreq,
1442 codec.channels,
1443 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001444 {
1445 _engineStatisticsPtr->SetLastError(
1446 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1447 "SetRecPayloadType() RTP/RTCP-module registration failed");
1448 return -1;
1449 }
1450 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001451 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001453 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1454 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 {
1456 _engineStatisticsPtr->SetLastError(
1457 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1458 "SetRecPayloadType() ACM registration failed - 1");
1459 return -1;
1460 }
1461 }
1462 return 0;
1463}
1464
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001465int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001466Channel::GetRecPayloadType(CodecInst& codec)
1467{
1468 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1469 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001470 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001471 if (rtp_payload_registry_->ReceivePayloadType(
1472 codec.plname,
1473 codec.plfreq,
1474 codec.channels,
1475 (codec.rate < 0) ? 0 : codec.rate,
1476 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001477 {
1478 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001479 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001480 "GetRecPayloadType() failed to retrieve RX payload type");
1481 return -1;
1482 }
1483 codec.pltype = payloadType;
1484 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001485 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001486 return 0;
1487}
1488
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001489int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001490Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1491{
1492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1493 "Channel::SetSendCNPayloadType()");
1494
1495 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001496 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001497 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001498 if (frequency == kFreq32000Hz)
1499 samplingFreqHz = 32000;
1500 else if (frequency == kFreq16000Hz)
1501 samplingFreqHz = 16000;
1502
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001503 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 {
1505 _engineStatisticsPtr->SetLastError(
1506 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1507 "SetSendCNPayloadType() failed to retrieve default CN codec "
1508 "settings");
1509 return -1;
1510 }
1511
1512 // Modify the payload type (must be set to dynamic range)
1513 codec.pltype = type;
1514
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001515 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001516 {
1517 _engineStatisticsPtr->SetLastError(
1518 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1519 "SetSendCNPayloadType() failed to register CN to ACM");
1520 return -1;
1521 }
1522
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001523 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001525 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1526 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 {
1528 _engineStatisticsPtr->SetLastError(
1529 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1530 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1531 "module");
1532 return -1;
1533 }
1534 }
1535 return 0;
1536}
1537
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001538int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001540 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001541
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001542 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001543 _engineStatisticsPtr->SetLastError(
1544 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001545 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001546 return -1;
1547 }
1548 return 0;
1549}
1550
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001551int Channel::SetOpusDtx(bool enable_dtx) {
1552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1553 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001554 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001555 : audio_coding_->DisableOpusDtx();
1556 if (ret != 0) {
1557 _engineStatisticsPtr->SetLastError(
1558 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1559 return -1;
1560 }
1561 return 0;
1562}
1563
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001564int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001565{
1566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1567 "Channel::RegisterExternalTransport()");
1568
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001569 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001570
niklase@google.com470e71d2011-07-07 08:21:25 +00001571 if (_externalTransport)
1572 {
1573 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1574 kTraceError,
1575 "RegisterExternalTransport() external transport already enabled");
1576 return -1;
1577 }
1578 _externalTransport = true;
1579 _transportPtr = &transport;
1580 return 0;
1581}
1582
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001583int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001584Channel::DeRegisterExternalTransport()
1585{
1586 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1587 "Channel::DeRegisterExternalTransport()");
1588
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001589 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001590
niklase@google.com470e71d2011-07-07 08:21:25 +00001591 if (!_transportPtr)
1592 {
1593 _engineStatisticsPtr->SetLastError(
1594 VE_INVALID_OPERATION, kTraceWarning,
1595 "DeRegisterExternalTransport() external transport already "
1596 "disabled");
1597 return 0;
1598 }
1599 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001600 _transportPtr = NULL;
1601 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1602 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001603 return 0;
1604}
1605
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001606int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001607 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001608 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1609 "Channel::ReceivedRTPPacket()");
1610
1611 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001612 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001613
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001614 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001615 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001616 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1617 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1618 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001619 return -1;
1620 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001621 header.payload_type_frequency =
1622 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001623 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001624 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001625 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001626 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001627 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001628 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001629
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001630 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001631}
1632
1633bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001634 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001635 const RTPHeader& header,
1636 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001637 if (rtp_payload_registry_->IsRtx(header)) {
1638 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001639 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001640 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001641 assert(packet_length >= header.headerLength);
1642 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001643 PayloadUnion payload_specific;
1644 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001645 &payload_specific)) {
1646 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001647 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001648 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1649 payload_specific, in_order);
1650}
1651
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001652bool Channel::HandleRtxPacket(const uint8_t* packet,
1653 size_t packet_length,
1654 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001655 if (!rtp_payload_registry_->IsRtx(header))
1656 return false;
1657
1658 // Remove the RTX header and parse the original RTP header.
1659 if (packet_length < header.headerLength)
1660 return false;
1661 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1662 return false;
1663 if (restored_packet_in_use_) {
1664 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1665 "Multiple RTX headers detected, dropping packet");
1666 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001667 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001668 uint8_t* restored_packet_ptr = restored_packet_;
1669 if (!rtp_payload_registry_->RestoreOriginalPacket(
1670 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1671 header)) {
1672 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1673 "Incoming RTX packet: invalid RTP header");
1674 return false;
1675 }
1676 restored_packet_in_use_ = true;
1677 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1678 restored_packet_in_use_ = false;
1679 return ret;
1680}
1681
1682bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1683 StreamStatistician* statistician =
1684 rtp_receive_statistics_->GetStatistician(header.ssrc);
1685 if (!statistician)
1686 return false;
1687 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001688}
1689
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001690bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1691 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001692 // Retransmissions are handled separately if RTX is enabled.
1693 if (rtp_payload_registry_->RtxEnabled())
1694 return false;
1695 StreamStatistician* statistician =
1696 rtp_receive_statistics_->GetStatistician(header.ssrc);
1697 if (!statistician)
1698 return false;
1699 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001700 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001701 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001702 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001703 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001704}
1705
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001706int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001707 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1708 "Channel::ReceivedRTCPPacket()");
1709 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001710 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001711
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001712 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001713 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001714 _engineStatisticsPtr->SetLastError(
1715 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1716 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1717 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001718
Minyue2013aec2015-05-13 14:14:42 +02001719 int64_t rtt = GetRTT(true);
1720 if (rtt == 0) {
1721 // Waiting for valid RTT.
1722 return 0;
1723 }
1724 uint32_t ntp_secs = 0;
1725 uint32_t ntp_frac = 0;
1726 uint32_t rtp_timestamp = 0;
1727 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1728 &rtp_timestamp)) {
1729 // Waiting for RTCP.
1730 return 0;
1731 }
1732
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001733 {
1734 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001735 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001736 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001737 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001738}
1739
niklase@google.com470e71d2011-07-07 08:21:25 +00001740int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001741 bool loop,
1742 FileFormats format,
1743 int startPosition,
1744 float volumeScaling,
1745 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001746 const CodecInst* codecInst)
1747{
1748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1749 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1750 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1751 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1752 startPosition, stopPosition);
1753
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001754 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001755 {
1756 _engineStatisticsPtr->SetLastError(
1757 VE_ALREADY_PLAYING, kTraceError,
1758 "StartPlayingFileLocally() is already playing");
1759 return -1;
1760 }
1761
niklase@google.com470e71d2011-07-07 08:21:25 +00001762 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001763 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001764
1765 if (_outputFilePlayerPtr)
1766 {
1767 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1768 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1769 _outputFilePlayerPtr = NULL;
1770 }
1771
1772 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1773 _outputFilePlayerId, (const FileFormats)format);
1774
1775 if (_outputFilePlayerPtr == NULL)
1776 {
1777 _engineStatisticsPtr->SetLastError(
1778 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001779 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001780 return -1;
1781 }
1782
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001783 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001784
1785 if (_outputFilePlayerPtr->StartPlayingFile(
1786 fileName,
1787 loop,
1788 startPosition,
1789 volumeScaling,
1790 notificationTime,
1791 stopPosition,
1792 (const CodecInst*)codecInst) != 0)
1793 {
1794 _engineStatisticsPtr->SetLastError(
1795 VE_BAD_FILE, kTraceError,
1796 "StartPlayingFile() failed to start file playout");
1797 _outputFilePlayerPtr->StopPlayingFile();
1798 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1799 _outputFilePlayerPtr = NULL;
1800 return -1;
1801 }
1802 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001803 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001804 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001805
1806 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001807 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001808
1809 return 0;
1810}
1811
1812int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001813 FileFormats format,
1814 int startPosition,
1815 float volumeScaling,
1816 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001817 const CodecInst* codecInst)
1818{
1819 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1820 "Channel::StartPlayingFileLocally(format=%d,"
1821 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1822 format, volumeScaling, startPosition, stopPosition);
1823
1824 if(stream == NULL)
1825 {
1826 _engineStatisticsPtr->SetLastError(
1827 VE_BAD_FILE, kTraceError,
1828 "StartPlayingFileLocally() NULL as input stream");
1829 return -1;
1830 }
1831
1832
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001833 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001834 {
1835 _engineStatisticsPtr->SetLastError(
1836 VE_ALREADY_PLAYING, kTraceError,
1837 "StartPlayingFileLocally() is already playing");
1838 return -1;
1839 }
1840
niklase@google.com470e71d2011-07-07 08:21:25 +00001841 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001842 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001843
1844 // Destroy the old instance
1845 if (_outputFilePlayerPtr)
1846 {
1847 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1848 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1849 _outputFilePlayerPtr = NULL;
1850 }
1851
1852 // Create the instance
1853 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1854 _outputFilePlayerId,
1855 (const FileFormats)format);
1856
1857 if (_outputFilePlayerPtr == NULL)
1858 {
1859 _engineStatisticsPtr->SetLastError(
1860 VE_INVALID_ARGUMENT, kTraceError,
1861 "StartPlayingFileLocally() filePlayer format isnot correct");
1862 return -1;
1863 }
1864
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001865 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001866
1867 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1868 volumeScaling,
1869 notificationTime,
1870 stopPosition, codecInst) != 0)
1871 {
1872 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1873 "StartPlayingFile() failed to "
1874 "start file playout");
1875 _outputFilePlayerPtr->StopPlayingFile();
1876 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1877 _outputFilePlayerPtr = NULL;
1878 return -1;
1879 }
1880 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001881 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001882 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001883
1884 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001885 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001886
niklase@google.com470e71d2011-07-07 08:21:25 +00001887 return 0;
1888}
1889
1890int Channel::StopPlayingFileLocally()
1891{
1892 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1893 "Channel::StopPlayingFileLocally()");
1894
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001895 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001896 {
1897 _engineStatisticsPtr->SetLastError(
1898 VE_INVALID_OPERATION, kTraceWarning,
1899 "StopPlayingFileLocally() isnot playing");
1900 return 0;
1901 }
1902
niklase@google.com470e71d2011-07-07 08:21:25 +00001903 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001904 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001905
1906 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1907 {
1908 _engineStatisticsPtr->SetLastError(
1909 VE_STOP_RECORDING_FAILED, kTraceError,
1910 "StopPlayingFile() could not stop playing");
1911 return -1;
1912 }
1913 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1914 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1915 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001916 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001917 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001918 // _fileCritSect cannot be taken while calling
1919 // SetAnonymousMixibilityStatus. Refer to comments in
1920 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001921 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1922 {
1923 _engineStatisticsPtr->SetLastError(
1924 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001925 "StopPlayingFile() failed to stop participant from playing as"
1926 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001927 return -1;
1928 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001929
1930 return 0;
1931}
1932
1933int Channel::IsPlayingFileLocally() const
1934{
1935 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1936 "Channel::IsPlayingFileLocally()");
1937
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001938 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001939}
1940
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001941int Channel::RegisterFilePlayingToMixer()
1942{
1943 // Return success for not registering for file playing to mixer if:
1944 // 1. playing file before playout is started on that channel.
1945 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001946 if (!channel_state_.Get().playing ||
1947 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001948 {
1949 return 0;
1950 }
1951
1952 // |_fileCritSect| cannot be taken while calling
1953 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1954 // frames can be pulled by the mixer. Since the frames are generated from
1955 // the file, _fileCritSect will be taken. This would result in a deadlock.
1956 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1957 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001958 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001959 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001960 _engineStatisticsPtr->SetLastError(
1961 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1962 "StartPlayingFile() failed to add participant as file to mixer");
1963 _outputFilePlayerPtr->StopPlayingFile();
1964 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1965 _outputFilePlayerPtr = NULL;
1966 return -1;
1967 }
1968
1969 return 0;
1970}
1971
niklase@google.com470e71d2011-07-07 08:21:25 +00001972int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001973 bool loop,
1974 FileFormats format,
1975 int startPosition,
1976 float volumeScaling,
1977 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001978 const CodecInst* codecInst)
1979{
1980 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1981 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1982 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1983 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1984 startPosition, stopPosition);
1985
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001986 CriticalSectionScoped cs(&_fileCritSect);
1987
1988 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001989 {
1990 _engineStatisticsPtr->SetLastError(
1991 VE_ALREADY_PLAYING, kTraceWarning,
1992 "StartPlayingFileAsMicrophone() filePlayer is playing");
1993 return 0;
1994 }
1995
niklase@google.com470e71d2011-07-07 08:21:25 +00001996 // Destroy the old instance
1997 if (_inputFilePlayerPtr)
1998 {
1999 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2000 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2001 _inputFilePlayerPtr = NULL;
2002 }
2003
2004 // Create the instance
2005 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2006 _inputFilePlayerId, (const FileFormats)format);
2007
2008 if (_inputFilePlayerPtr == NULL)
2009 {
2010 _engineStatisticsPtr->SetLastError(
2011 VE_INVALID_ARGUMENT, kTraceError,
2012 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2013 return -1;
2014 }
2015
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002016 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002017
2018 if (_inputFilePlayerPtr->StartPlayingFile(
2019 fileName,
2020 loop,
2021 startPosition,
2022 volumeScaling,
2023 notificationTime,
2024 stopPosition,
2025 (const CodecInst*)codecInst) != 0)
2026 {
2027 _engineStatisticsPtr->SetLastError(
2028 VE_BAD_FILE, kTraceError,
2029 "StartPlayingFile() failed to start file playout");
2030 _inputFilePlayerPtr->StopPlayingFile();
2031 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2032 _inputFilePlayerPtr = NULL;
2033 return -1;
2034 }
2035 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002036 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002037
2038 return 0;
2039}
2040
2041int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002042 FileFormats format,
2043 int startPosition,
2044 float volumeScaling,
2045 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002046 const CodecInst* codecInst)
2047{
2048 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2049 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2050 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2051 format, volumeScaling, startPosition, stopPosition);
2052
2053 if(stream == NULL)
2054 {
2055 _engineStatisticsPtr->SetLastError(
2056 VE_BAD_FILE, kTraceError,
2057 "StartPlayingFileAsMicrophone NULL as input stream");
2058 return -1;
2059 }
2060
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002061 CriticalSectionScoped cs(&_fileCritSect);
2062
2063 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002064 {
2065 _engineStatisticsPtr->SetLastError(
2066 VE_ALREADY_PLAYING, kTraceWarning,
2067 "StartPlayingFileAsMicrophone() is playing");
2068 return 0;
2069 }
2070
niklase@google.com470e71d2011-07-07 08:21:25 +00002071 // Destroy the old instance
2072 if (_inputFilePlayerPtr)
2073 {
2074 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2075 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2076 _inputFilePlayerPtr = NULL;
2077 }
2078
2079 // Create the instance
2080 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2081 _inputFilePlayerId, (const FileFormats)format);
2082
2083 if (_inputFilePlayerPtr == NULL)
2084 {
2085 _engineStatisticsPtr->SetLastError(
2086 VE_INVALID_ARGUMENT, kTraceError,
2087 "StartPlayingInputFile() filePlayer format isnot correct");
2088 return -1;
2089 }
2090
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002091 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002092
2093 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2094 volumeScaling, notificationTime,
2095 stopPosition, codecInst) != 0)
2096 {
2097 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2098 "StartPlayingFile() failed to start "
2099 "file playout");
2100 _inputFilePlayerPtr->StopPlayingFile();
2101 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2102 _inputFilePlayerPtr = NULL;
2103 return -1;
2104 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002105
niklase@google.com470e71d2011-07-07 08:21:25 +00002106 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002107 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002108
2109 return 0;
2110}
2111
2112int Channel::StopPlayingFileAsMicrophone()
2113{
2114 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2115 "Channel::StopPlayingFileAsMicrophone()");
2116
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002117 CriticalSectionScoped cs(&_fileCritSect);
2118
2119 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002120 {
2121 _engineStatisticsPtr->SetLastError(
2122 VE_INVALID_OPERATION, kTraceWarning,
2123 "StopPlayingFileAsMicrophone() isnot playing");
2124 return 0;
2125 }
2126
niklase@google.com470e71d2011-07-07 08:21:25 +00002127 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2128 {
2129 _engineStatisticsPtr->SetLastError(
2130 VE_STOP_RECORDING_FAILED, kTraceError,
2131 "StopPlayingFile() could not stop playing");
2132 return -1;
2133 }
2134 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2135 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2136 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002137 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002138
2139 return 0;
2140}
2141
2142int Channel::IsPlayingFileAsMicrophone() const
2143{
2144 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2145 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002146 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002147}
2148
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002149int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002150 const CodecInst* codecInst)
2151{
2152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2153 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2154
2155 if (_outputFileRecording)
2156 {
2157 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2158 "StartRecordingPlayout() is already recording");
2159 return 0;
2160 }
2161
2162 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002163 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002164 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2165
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002166 if ((codecInst != NULL) &&
2167 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002168 {
2169 _engineStatisticsPtr->SetLastError(
2170 VE_BAD_ARGUMENT, kTraceError,
2171 "StartRecordingPlayout() invalid compression");
2172 return(-1);
2173 }
2174 if(codecInst == NULL)
2175 {
2176 format = kFileFormatPcm16kHzFile;
2177 codecInst=&dummyCodec;
2178 }
2179 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2180 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2181 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2182 {
2183 format = kFileFormatWavFile;
2184 }
2185 else
2186 {
2187 format = kFileFormatCompressedFile;
2188 }
2189
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002190 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002191
2192 // Destroy the old instance
2193 if (_outputFileRecorderPtr)
2194 {
2195 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2196 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2197 _outputFileRecorderPtr = NULL;
2198 }
2199
2200 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2201 _outputFileRecorderId, (const FileFormats)format);
2202 if (_outputFileRecorderPtr == NULL)
2203 {
2204 _engineStatisticsPtr->SetLastError(
2205 VE_INVALID_ARGUMENT, kTraceError,
2206 "StartRecordingPlayout() fileRecorder format isnot correct");
2207 return -1;
2208 }
2209
2210 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2211 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2212 {
2213 _engineStatisticsPtr->SetLastError(
2214 VE_BAD_FILE, kTraceError,
2215 "StartRecordingAudioFile() failed to start file recording");
2216 _outputFileRecorderPtr->StopRecording();
2217 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2218 _outputFileRecorderPtr = NULL;
2219 return -1;
2220 }
2221 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2222 _outputFileRecording = true;
2223
2224 return 0;
2225}
2226
2227int Channel::StartRecordingPlayout(OutStream* stream,
2228 const CodecInst* codecInst)
2229{
2230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2231 "Channel::StartRecordingPlayout()");
2232
2233 if (_outputFileRecording)
2234 {
2235 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2236 "StartRecordingPlayout() is already recording");
2237 return 0;
2238 }
2239
2240 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002241 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002242 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2243
2244 if (codecInst != NULL && codecInst->channels != 1)
2245 {
2246 _engineStatisticsPtr->SetLastError(
2247 VE_BAD_ARGUMENT, kTraceError,
2248 "StartRecordingPlayout() invalid compression");
2249 return(-1);
2250 }
2251 if(codecInst == NULL)
2252 {
2253 format = kFileFormatPcm16kHzFile;
2254 codecInst=&dummyCodec;
2255 }
2256 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2257 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2258 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2259 {
2260 format = kFileFormatWavFile;
2261 }
2262 else
2263 {
2264 format = kFileFormatCompressedFile;
2265 }
2266
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002267 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002268
2269 // Destroy the old instance
2270 if (_outputFileRecorderPtr)
2271 {
2272 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2273 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2274 _outputFileRecorderPtr = NULL;
2275 }
2276
2277 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2278 _outputFileRecorderId, (const FileFormats)format);
2279 if (_outputFileRecorderPtr == NULL)
2280 {
2281 _engineStatisticsPtr->SetLastError(
2282 VE_INVALID_ARGUMENT, kTraceError,
2283 "StartRecordingPlayout() fileRecorder format isnot correct");
2284 return -1;
2285 }
2286
2287 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2288 notificationTime) != 0)
2289 {
2290 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2291 "StartRecordingPlayout() failed to "
2292 "start file recording");
2293 _outputFileRecorderPtr->StopRecording();
2294 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2295 _outputFileRecorderPtr = NULL;
2296 return -1;
2297 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002298
niklase@google.com470e71d2011-07-07 08:21:25 +00002299 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2300 _outputFileRecording = true;
2301
2302 return 0;
2303}
2304
2305int Channel::StopRecordingPlayout()
2306{
2307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2308 "Channel::StopRecordingPlayout()");
2309
2310 if (!_outputFileRecording)
2311 {
2312 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2313 "StopRecordingPlayout() isnot recording");
2314 return -1;
2315 }
2316
2317
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002318 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002319
2320 if (_outputFileRecorderPtr->StopRecording() != 0)
2321 {
2322 _engineStatisticsPtr->SetLastError(
2323 VE_STOP_RECORDING_FAILED, kTraceError,
2324 "StopRecording() could not stop recording");
2325 return(-1);
2326 }
2327 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2328 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2329 _outputFileRecorderPtr = NULL;
2330 _outputFileRecording = false;
2331
2332 return 0;
2333}
2334
2335void
2336Channel::SetMixWithMicStatus(bool mix)
2337{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002338 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002339 _mixFileWithMicrophone=mix;
2340}
2341
2342int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002343Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002344{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002345 int8_t currentLevel = _outputAudioLevel.Level();
2346 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002347 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2348 VoEId(_instanceId,_channelId),
2349 "GetSpeechOutputLevel() => level=%u", level);
2350 return 0;
2351}
2352
2353int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002354Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002355{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002356 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2357 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002358 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2359 VoEId(_instanceId,_channelId),
2360 "GetSpeechOutputLevelFullRange() => level=%u", level);
2361 return 0;
2362}
2363
2364int
2365Channel::SetMute(bool enable)
2366{
wu@webrtc.org63420662013-10-17 18:28:55 +00002367 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002368 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2369 "Channel::SetMute(enable=%d)", enable);
2370 _mute = enable;
2371 return 0;
2372}
2373
2374bool
2375Channel::Mute() const
2376{
wu@webrtc.org63420662013-10-17 18:28:55 +00002377 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002378 return _mute;
2379}
2380
2381int
2382Channel::SetOutputVolumePan(float left, float right)
2383{
wu@webrtc.org63420662013-10-17 18:28:55 +00002384 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002385 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2386 "Channel::SetOutputVolumePan()");
2387 _panLeft = left;
2388 _panRight = right;
2389 return 0;
2390}
2391
2392int
2393Channel::GetOutputVolumePan(float& left, float& right) const
2394{
wu@webrtc.org63420662013-10-17 18:28:55 +00002395 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002396 left = _panLeft;
2397 right = _panRight;
2398 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2399 VoEId(_instanceId,_channelId),
2400 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2401 return 0;
2402}
2403
2404int
2405Channel::SetChannelOutputVolumeScaling(float scaling)
2406{
wu@webrtc.org63420662013-10-17 18:28:55 +00002407 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2409 "Channel::SetChannelOutputVolumeScaling()");
2410 _outputGain = scaling;
2411 return 0;
2412}
2413
2414int
2415Channel::GetChannelOutputVolumeScaling(float& scaling) const
2416{
wu@webrtc.org63420662013-10-17 18:28:55 +00002417 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002418 scaling = _outputGain;
2419 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2420 VoEId(_instanceId,_channelId),
2421 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2422 return 0;
2423}
2424
niklase@google.com470e71d2011-07-07 08:21:25 +00002425int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002426 int lengthMs, int attenuationDb,
2427 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002428{
2429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2430 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2431 playDtmfEvent);
2432
2433 _playOutbandDtmfEvent = playDtmfEvent;
2434
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002435 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002436 attenuationDb) != 0)
2437 {
2438 _engineStatisticsPtr->SetLastError(
2439 VE_SEND_DTMF_FAILED,
2440 kTraceWarning,
2441 "SendTelephoneEventOutband() failed to send event");
2442 return -1;
2443 }
2444 return 0;
2445}
2446
2447int Channel::SendTelephoneEventInband(unsigned char eventCode,
2448 int lengthMs,
2449 int attenuationDb,
2450 bool playDtmfEvent)
2451{
2452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2453 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2454 playDtmfEvent);
2455
2456 _playInbandDtmfEvent = playDtmfEvent;
2457 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2458
2459 return 0;
2460}
2461
2462int
niklase@google.com470e71d2011-07-07 08:21:25 +00002463Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2464{
2465 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2466 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002467 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002468 {
2469 _engineStatisticsPtr->SetLastError(
2470 VE_INVALID_ARGUMENT, kTraceError,
2471 "SetSendTelephoneEventPayloadType() invalid type");
2472 return -1;
2473 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002474 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002475 codec.plfreq = 8000;
2476 codec.pltype = type;
2477 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002478 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002479 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002480 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2481 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2482 _engineStatisticsPtr->SetLastError(
2483 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2484 "SetSendTelephoneEventPayloadType() failed to register send"
2485 "payload type");
2486 return -1;
2487 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002488 }
2489 _sendTelephoneEventPayloadType = type;
2490 return 0;
2491}
2492
2493int
2494Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2495{
2496 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2497 "Channel::GetSendTelephoneEventPayloadType()");
2498 type = _sendTelephoneEventPayloadType;
2499 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2500 VoEId(_instanceId,_channelId),
2501 "GetSendTelephoneEventPayloadType() => type=%u", type);
2502 return 0;
2503}
2504
niklase@google.com470e71d2011-07-07 08:21:25 +00002505int
2506Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2507{
2508 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2509 "Channel::UpdateRxVadDetection()");
2510
2511 int vadDecision = 1;
2512
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002513 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002514
2515 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2516 {
2517 OnRxVadDetected(vadDecision);
2518 _oldVadDecision = vadDecision;
2519 }
2520
2521 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2522 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2523 vadDecision);
2524 return 0;
2525}
2526
2527int
2528Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2529{
2530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2531 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002532 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002533
2534 if (_rxVadObserverPtr)
2535 {
2536 _engineStatisticsPtr->SetLastError(
2537 VE_INVALID_OPERATION, kTraceError,
2538 "RegisterRxVadObserver() observer already enabled");
2539 return -1;
2540 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002541 _rxVadObserverPtr = &observer;
2542 _RxVadDetection = true;
2543 return 0;
2544}
2545
2546int
2547Channel::DeRegisterRxVadObserver()
2548{
2549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2550 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002551 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002552
2553 if (!_rxVadObserverPtr)
2554 {
2555 _engineStatisticsPtr->SetLastError(
2556 VE_INVALID_OPERATION, kTraceWarning,
2557 "DeRegisterRxVadObserver() observer already disabled");
2558 return 0;
2559 }
2560 _rxVadObserverPtr = NULL;
2561 _RxVadDetection = false;
2562 return 0;
2563}
2564
2565int
2566Channel::VoiceActivityIndicator(int &activity)
2567{
2568 activity = _sendFrameType;
2569
2570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002571 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002572 return 0;
2573}
2574
2575#ifdef WEBRTC_VOICE_ENGINE_AGC
2576
2577int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002578Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002579{
2580 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2581 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2582 (int)enable, (int)mode);
2583
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002584 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002585 switch (mode)
2586 {
2587 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002588 break;
2589 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002590 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002591 break;
2592 case kAgcFixedDigital:
2593 agcMode = GainControl::kFixedDigital;
2594 break;
2595 case kAgcAdaptiveDigital:
2596 agcMode =GainControl::kAdaptiveDigital;
2597 break;
2598 default:
2599 _engineStatisticsPtr->SetLastError(
2600 VE_INVALID_ARGUMENT, kTraceError,
2601 "SetRxAgcStatus() invalid Agc mode");
2602 return -1;
2603 }
2604
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002605 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002606 {
2607 _engineStatisticsPtr->SetLastError(
2608 VE_APM_ERROR, kTraceError,
2609 "SetRxAgcStatus() failed to set Agc mode");
2610 return -1;
2611 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002612 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002613 {
2614 _engineStatisticsPtr->SetLastError(
2615 VE_APM_ERROR, kTraceError,
2616 "SetRxAgcStatus() failed to set Agc state");
2617 return -1;
2618 }
2619
2620 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002621 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002622
2623 return 0;
2624}
2625
2626int
2627Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2628{
2629 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2630 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2631
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002632 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002633 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002634 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002635
2636 enabled = enable;
2637
2638 switch (agcMode)
2639 {
2640 case GainControl::kFixedDigital:
2641 mode = kAgcFixedDigital;
2642 break;
2643 case GainControl::kAdaptiveDigital:
2644 mode = kAgcAdaptiveDigital;
2645 break;
2646 default:
2647 _engineStatisticsPtr->SetLastError(
2648 VE_APM_ERROR, kTraceError,
2649 "GetRxAgcStatus() invalid Agc mode");
2650 return -1;
2651 }
2652
2653 return 0;
2654}
2655
2656int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002657Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002658{
2659 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2660 "Channel::SetRxAgcConfig()");
2661
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002662 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002663 config.targetLeveldBOv) != 0)
2664 {
2665 _engineStatisticsPtr->SetLastError(
2666 VE_APM_ERROR, kTraceError,
2667 "SetRxAgcConfig() failed to set target peak |level|"
2668 "(or envelope) of the Agc");
2669 return -1;
2670 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002671 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002672 config.digitalCompressionGaindB) != 0)
2673 {
2674 _engineStatisticsPtr->SetLastError(
2675 VE_APM_ERROR, kTraceError,
2676 "SetRxAgcConfig() failed to set the range in |gain| the"
2677 " digital compression stage may apply");
2678 return -1;
2679 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002680 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002681 config.limiterEnable) != 0)
2682 {
2683 _engineStatisticsPtr->SetLastError(
2684 VE_APM_ERROR, kTraceError,
2685 "SetRxAgcConfig() failed to set hard limiter to the signal");
2686 return -1;
2687 }
2688
2689 return 0;
2690}
2691
2692int
2693Channel::GetRxAgcConfig(AgcConfig& config)
2694{
2695 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2696 "Channel::GetRxAgcConfig(config=%?)");
2697
2698 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002699 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002700 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002701 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002702 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002703 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002704
2705 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2706 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2707 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2708 " limiterEnable=%d",
2709 config.targetLeveldBOv,
2710 config.digitalCompressionGaindB,
2711 config.limiterEnable);
2712
2713 return 0;
2714}
2715
2716#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2717
2718#ifdef WEBRTC_VOICE_ENGINE_NR
2719
2720int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002721Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002722{
2723 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2724 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2725 (int)enable, (int)mode);
2726
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002727 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 switch (mode)
2729 {
2730
2731 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002732 break;
2733 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002734 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002735 break;
2736 case kNsConference:
2737 nsLevel = NoiseSuppression::kHigh;
2738 break;
2739 case kNsLowSuppression:
2740 nsLevel = NoiseSuppression::kLow;
2741 break;
2742 case kNsModerateSuppression:
2743 nsLevel = NoiseSuppression::kModerate;
2744 break;
2745 case kNsHighSuppression:
2746 nsLevel = NoiseSuppression::kHigh;
2747 break;
2748 case kNsVeryHighSuppression:
2749 nsLevel = NoiseSuppression::kVeryHigh;
2750 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002751 }
2752
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002753 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002754 != 0)
2755 {
2756 _engineStatisticsPtr->SetLastError(
2757 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002758 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002759 return -1;
2760 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002761 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 {
2763 _engineStatisticsPtr->SetLastError(
2764 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002765 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002766 return -1;
2767 }
2768
2769 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002770 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002771
2772 return 0;
2773}
2774
2775int
2776Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2777{
2778 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2779 "Channel::GetRxNsStatus(enable=?, mode=?)");
2780
2781 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002782 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002783 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002784 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002785
2786 enabled = enable;
2787
2788 switch (ncLevel)
2789 {
2790 case NoiseSuppression::kLow:
2791 mode = kNsLowSuppression;
2792 break;
2793 case NoiseSuppression::kModerate:
2794 mode = kNsModerateSuppression;
2795 break;
2796 case NoiseSuppression::kHigh:
2797 mode = kNsHighSuppression;
2798 break;
2799 case NoiseSuppression::kVeryHigh:
2800 mode = kNsVeryHighSuppression;
2801 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 }
2803
2804 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2805 VoEId(_instanceId,_channelId),
2806 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2807 return 0;
2808}
2809
2810#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2811
2812int
niklase@google.com470e71d2011-07-07 08:21:25 +00002813Channel::SetLocalSSRC(unsigned int ssrc)
2814{
2815 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2816 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002817 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002818 {
2819 _engineStatisticsPtr->SetLastError(
2820 VE_ALREADY_SENDING, kTraceError,
2821 "SetLocalSSRC() already sending");
2822 return -1;
2823 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002824 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002825 return 0;
2826}
2827
2828int
2829Channel::GetLocalSSRC(unsigned int& ssrc)
2830{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002831 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002832 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2833 VoEId(_instanceId,_channelId),
2834 "GetLocalSSRC() => ssrc=%lu", ssrc);
2835 return 0;
2836}
2837
2838int
2839Channel::GetRemoteSSRC(unsigned int& ssrc)
2840{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002841 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002842 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2843 VoEId(_instanceId,_channelId),
2844 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2845 return 0;
2846}
2847
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002848int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002849 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002850 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002851}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002852
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002853int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2854 unsigned char id) {
2855 rtp_header_parser_->DeregisterRtpHeaderExtension(
2856 kRtpExtensionAudioLevel);
2857 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2858 kRtpExtensionAudioLevel, id)) {
2859 return -1;
2860 }
2861 return 0;
2862}
2863
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002864int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2865 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2866}
2867
2868int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2869 rtp_header_parser_->DeregisterRtpHeaderExtension(
2870 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002871 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2872 kRtpExtensionAbsoluteSendTime, id)) {
2873 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002874 }
2875 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002876}
2877
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002878void Channel::SetRTCPStatus(bool enable) {
2879 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2880 "Channel::SetRTCPStatus()");
2881 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002882}
2883
2884int
2885Channel::GetRTCPStatus(bool& enabled)
2886{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002887 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002888 enabled = (method != kRtcpOff);
2889 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2890 VoEId(_instanceId,_channelId),
2891 "GetRTCPStatus() => enabled=%d", enabled);
2892 return 0;
2893}
2894
2895int
2896Channel::SetRTCP_CNAME(const char cName[256])
2897{
2898 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2899 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002900 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 {
2902 _engineStatisticsPtr->SetLastError(
2903 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2904 "SetRTCP_CNAME() failed to set RTCP CNAME");
2905 return -1;
2906 }
2907 return 0;
2908}
2909
2910int
niklase@google.com470e71d2011-07-07 08:21:25 +00002911Channel::GetRemoteRTCP_CNAME(char cName[256])
2912{
2913 if (cName == NULL)
2914 {
2915 _engineStatisticsPtr->SetLastError(
2916 VE_INVALID_ARGUMENT, kTraceError,
2917 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2918 return -1;
2919 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002920 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002921 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002922 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002923 {
2924 _engineStatisticsPtr->SetLastError(
2925 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2926 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2927 return -1;
2928 }
2929 strcpy(cName, cname);
2930 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2931 VoEId(_instanceId, _channelId),
2932 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2933 return 0;
2934}
2935
2936int
2937Channel::GetRemoteRTCPData(
2938 unsigned int& NTPHigh,
2939 unsigned int& NTPLow,
2940 unsigned int& timestamp,
2941 unsigned int& playoutTimestamp,
2942 unsigned int* jitter,
2943 unsigned short* fractionLost)
2944{
2945 // --- Information from sender info in received Sender Reports
2946
2947 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002948 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002949 {
2950 _engineStatisticsPtr->SetLastError(
2951 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002952 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002953 "side");
2954 return -1;
2955 }
2956
2957 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2958 // and octet count)
2959 NTPHigh = senderInfo.NTPseconds;
2960 NTPLow = senderInfo.NTPfraction;
2961 timestamp = senderInfo.RTPtimeStamp;
2962
2963 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2964 VoEId(_instanceId, _channelId),
2965 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2966 "timestamp=%lu",
2967 NTPHigh, NTPLow, timestamp);
2968
2969 // --- Locally derived information
2970
2971 // This value is updated on each incoming RTCP packet (0 when no packet
2972 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002973 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002974
2975 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2976 VoEId(_instanceId, _channelId),
2977 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002978 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002979
2980 if (NULL != jitter || NULL != fractionLost)
2981 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002982 // Get all RTCP receiver report blocks that have been received on this
2983 // channel. If we receive RTP packets from a remote source we know the
2984 // remote SSRC and use the report block from him.
2985 // Otherwise use the first report block.
2986 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002987 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002988 remote_stats.empty()) {
2989 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2990 VoEId(_instanceId, _channelId),
2991 "GetRemoteRTCPData() failed to measure statistics due"
2992 " to lack of received RTP and/or RTCP packets");
2993 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002994 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002995
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002996 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002997 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2998 for (; it != remote_stats.end(); ++it) {
2999 if (it->remoteSSRC == remoteSSRC)
3000 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003001 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003002
3003 if (it == remote_stats.end()) {
3004 // If we have not received any RTCP packets from this SSRC it probably
3005 // means that we have not received any RTP packets.
3006 // Use the first received report block instead.
3007 it = remote_stats.begin();
3008 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003009 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003010
xians@webrtc.org79af7342012-01-31 12:22:14 +00003011 if (jitter) {
3012 *jitter = it->jitter;
3013 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3014 VoEId(_instanceId, _channelId),
3015 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3016 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003017
xians@webrtc.org79af7342012-01-31 12:22:14 +00003018 if (fractionLost) {
3019 *fractionLost = it->fractionLost;
3020 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3021 VoEId(_instanceId, _channelId),
3022 "GetRemoteRTCPData() => fractionLost = %lu",
3023 *fractionLost);
3024 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003025 }
3026 return 0;
3027}
3028
3029int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003030Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003031 unsigned int name,
3032 const char* data,
3033 unsigned short dataLengthInBytes)
3034{
3035 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3036 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003037 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003038 {
3039 _engineStatisticsPtr->SetLastError(
3040 VE_NOT_SENDING, kTraceError,
3041 "SendApplicationDefinedRTCPPacket() not sending");
3042 return -1;
3043 }
3044 if (NULL == data)
3045 {
3046 _engineStatisticsPtr->SetLastError(
3047 VE_INVALID_ARGUMENT, kTraceError,
3048 "SendApplicationDefinedRTCPPacket() invalid data value");
3049 return -1;
3050 }
3051 if (dataLengthInBytes % 4 != 0)
3052 {
3053 _engineStatisticsPtr->SetLastError(
3054 VE_INVALID_ARGUMENT, kTraceError,
3055 "SendApplicationDefinedRTCPPacket() invalid length value");
3056 return -1;
3057 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003058 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003059 if (status == kRtcpOff)
3060 {
3061 _engineStatisticsPtr->SetLastError(
3062 VE_RTCP_ERROR, kTraceError,
3063 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3064 return -1;
3065 }
3066
3067 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003068 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003069 subType,
3070 name,
3071 (const unsigned char*) data,
3072 dataLengthInBytes) != 0)
3073 {
3074 _engineStatisticsPtr->SetLastError(
3075 VE_SEND_ERROR, kTraceError,
3076 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3077 return -1;
3078 }
3079 return 0;
3080}
3081
3082int
3083Channel::GetRTPStatistics(
3084 unsigned int& averageJitterMs,
3085 unsigned int& maxJitterMs,
3086 unsigned int& discardedPackets)
3087{
niklase@google.com470e71d2011-07-07 08:21:25 +00003088 // The jitter statistics is updated for each received RTP packet and is
3089 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003090 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3091 // If RTCP is off, there is no timed thread in the RTCP module regularly
3092 // generating new stats, trigger the update manually here instead.
3093 StreamStatistician* statistician =
3094 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3095 if (statistician) {
3096 // Don't use returned statistics, use data from proxy instead so that
3097 // max jitter can be fetched atomically.
3098 RtcpStatistics s;
3099 statistician->GetStatistics(&s, true);
3100 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003101 }
3102
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003103 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003104 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003105 if (playoutFrequency > 0) {
3106 // Scale RTP statistics given the current playout frequency
3107 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3108 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003109 }
3110
3111 discardedPackets = _numberOfDiscardedPackets;
3112
3113 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3114 VoEId(_instanceId, _channelId),
3115 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003116 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003117 averageJitterMs, maxJitterMs, discardedPackets);
3118 return 0;
3119}
3120
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003121int Channel::GetRemoteRTCPReportBlocks(
3122 std::vector<ReportBlock>* report_blocks) {
3123 if (report_blocks == NULL) {
3124 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3125 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3126 return -1;
3127 }
3128
3129 // Get the report blocks from the latest received RTCP Sender or Receiver
3130 // Report. Each element in the vector contains the sender's SSRC and a
3131 // report block according to RFC 3550.
3132 std::vector<RTCPReportBlock> rtcp_report_blocks;
3133 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3134 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3135 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3136 return -1;
3137 }
3138
3139 if (rtcp_report_blocks.empty())
3140 return 0;
3141
3142 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3143 for (; it != rtcp_report_blocks.end(); ++it) {
3144 ReportBlock report_block;
3145 report_block.sender_SSRC = it->remoteSSRC;
3146 report_block.source_SSRC = it->sourceSSRC;
3147 report_block.fraction_lost = it->fractionLost;
3148 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3149 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3150 report_block.interarrival_jitter = it->jitter;
3151 report_block.last_SR_timestamp = it->lastSR;
3152 report_block.delay_since_last_SR = it->delaySinceLastSR;
3153 report_blocks->push_back(report_block);
3154 }
3155 return 0;
3156}
3157
niklase@google.com470e71d2011-07-07 08:21:25 +00003158int
3159Channel::GetRTPStatistics(CallStatistics& stats)
3160{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003161 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003162
3163 // The jitter statistics is updated for each received RTP packet and is
3164 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003165 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003166 StreamStatistician* statistician =
3167 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3168 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003169 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3170 _engineStatisticsPtr->SetLastError(
3171 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3172 "GetRTPStatistics() failed to read RTP statistics from the "
3173 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003174 }
3175
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003176 stats.fractionLost = statistics.fraction_lost;
3177 stats.cumulativeLost = statistics.cumulative_lost;
3178 stats.extendedMax = statistics.extended_max_sequence_number;
3179 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003180
3181 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3182 VoEId(_instanceId, _channelId),
3183 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003184 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003185 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3186 stats.jitterSamples);
3187
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003188 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003189 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003190 if (stats.rttMs == 0) {
3191 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3192 "GetRTPStatistics() failed to get RTT");
3193 } else {
3194 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003195 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003196 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003197
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003198 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003199
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003200 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003201 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003202 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003203 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003204
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003205 if (statistician) {
3206 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3207 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003208
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003209 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003210 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003211 {
3212 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3213 VoEId(_instanceId, _channelId),
3214 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003215 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003216 }
3217
3218 stats.bytesSent = bytesSent;
3219 stats.packetsSent = packetsSent;
3220 stats.bytesReceived = bytesReceived;
3221 stats.packetsReceived = packetsReceived;
3222
3223 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3224 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003225 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3226 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003227 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3228 stats.packetsReceived);
3229
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003230 // --- Timestamps
3231 {
3232 CriticalSectionScoped lock(ts_stats_lock_.get());
3233 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3234 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003235 return 0;
3236}
3237
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003238int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003239 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003240 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003241
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003242 if (enable) {
3243 if (redPayloadtype < 0 || redPayloadtype > 127) {
3244 _engineStatisticsPtr->SetLastError(
3245 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003246 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003247 return -1;
3248 }
3249
3250 if (SetRedPayloadType(redPayloadtype) < 0) {
3251 _engineStatisticsPtr->SetLastError(
3252 VE_CODEC_ERROR, kTraceError,
3253 "SetSecondarySendCodec() Failed to register RED ACM");
3254 return -1;
3255 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003256 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003257
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003258 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003259 _engineStatisticsPtr->SetLastError(
3260 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003261 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003262 return -1;
3263 }
3264 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003265}
3266
3267int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003268Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003269{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003270 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003271 if (enabled)
3272 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003273 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003274 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003275 {
3276 _engineStatisticsPtr->SetLastError(
3277 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003278 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003279 "module");
3280 return -1;
3281 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003282 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003283 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3284 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003285 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003286 enabled, redPayloadtype);
3287 return 0;
3288 }
3289 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3290 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003291 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003292 return 0;
3293}
3294
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003295int Channel::SetCodecFECStatus(bool enable) {
3296 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3297 "Channel::SetCodecFECStatus()");
3298
3299 if (audio_coding_->SetCodecFEC(enable) != 0) {
3300 _engineStatisticsPtr->SetLastError(
3301 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3302 "SetCodecFECStatus() failed to set FEC state");
3303 return -1;
3304 }
3305 return 0;
3306}
3307
3308bool Channel::GetCodecFECStatus() {
3309 bool enabled = audio_coding_->CodecFEC();
3310 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3311 VoEId(_instanceId, _channelId),
3312 "GetCodecFECStatus() => enabled=%d", enabled);
3313 return enabled;
3314}
3315
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003316void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3317 // None of these functions can fail.
3318 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003319 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3320 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003321 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003322 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003323 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003324 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003325}
3326
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003327// Called when we are missing one or more packets.
3328int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003329 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3330}
3331
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003332uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003333Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003334{
3335 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003336 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003337 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003338 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003339 return 0;
3340}
3341
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003342void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003343 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003344 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003345 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003346 CodecInst codec;
3347 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003348
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003349 if (!mono_recording_audio_.get()) {
3350 // Temporary space for DownConvertToCodecFormat.
3351 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003352 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003353 DownConvertToCodecFormat(audio_data,
3354 number_of_frames,
3355 number_of_channels,
3356 sample_rate,
3357 codec.channels,
3358 codec.plfreq,
3359 mono_recording_audio_.get(),
3360 &input_resampler_,
3361 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003362}
3363
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003364uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003365Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003366{
3367 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3368 "Channel::PrepareEncodeAndSend()");
3369
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003370 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003371 {
3372 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3373 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003374 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003375 }
3376
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003377 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003378 {
3379 MixOrReplaceAudioWithFile(mixingFrequency);
3380 }
3381
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003382 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3383 if (is_muted) {
3384 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003385 }
3386
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003387 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003388 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003389 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003390 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003391 if (_inputExternalMediaCallbackPtr)
3392 {
3393 _inputExternalMediaCallbackPtr->Process(
3394 _channelId,
3395 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003396 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003397 _audioFrame.samples_per_channel_,
3398 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003399 isStereo);
3400 }
3401 }
3402
3403 InsertInbandDtmfTone();
3404
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003405 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003406 size_t length =
3407 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003408 if (is_muted) {
3409 rms_level_.ProcessMuted(length);
3410 } else {
3411 rms_level_.Process(_audioFrame.data_, length);
3412 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003413 }
3414
niklase@google.com470e71d2011-07-07 08:21:25 +00003415 return 0;
3416}
3417
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003418uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003419Channel::EncodeAndSend()
3420{
3421 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3422 "Channel::EncodeAndSend()");
3423
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003424 assert(_audioFrame.num_channels_ <= 2);
3425 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003426 {
3427 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3428 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003429 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003430 }
3431
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003432 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003433
3434 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3435
3436 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003437 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003438 // This call will trigger AudioPacketizationCallback::SendData if encoding
3439 // is done and payload is ready for packetization and transmission.
3440 // Otherwise, it will return without invoking the callback.
3441 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003442 {
3443 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3444 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003445 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003446 }
3447
Peter Kastingb7e50542015-06-11 12:55:50 -07003448 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003449 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003450}
3451
Minyue2013aec2015-05-13 14:14:42 +02003452void Channel::DisassociateSendChannel(int channel_id) {
3453 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3454 Channel* channel = associate_send_channel_.channel();
3455 if (channel && channel->ChannelId() == channel_id) {
3456 // If this channel is associated with a send channel of the specified
3457 // Channel ID, disassociate with it.
3458 ChannelOwner ref(NULL);
3459 associate_send_channel_ = ref;
3460 }
3461}
3462
niklase@google.com470e71d2011-07-07 08:21:25 +00003463int Channel::RegisterExternalMediaProcessing(
3464 ProcessingTypes type,
3465 VoEMediaProcess& processObject)
3466{
3467 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3468 "Channel::RegisterExternalMediaProcessing()");
3469
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003470 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003471
3472 if (kPlaybackPerChannel == type)
3473 {
3474 if (_outputExternalMediaCallbackPtr)
3475 {
3476 _engineStatisticsPtr->SetLastError(
3477 VE_INVALID_OPERATION, kTraceError,
3478 "Channel::RegisterExternalMediaProcessing() "
3479 "output external media already enabled");
3480 return -1;
3481 }
3482 _outputExternalMediaCallbackPtr = &processObject;
3483 _outputExternalMedia = true;
3484 }
3485 else if (kRecordingPerChannel == type)
3486 {
3487 if (_inputExternalMediaCallbackPtr)
3488 {
3489 _engineStatisticsPtr->SetLastError(
3490 VE_INVALID_OPERATION, kTraceError,
3491 "Channel::RegisterExternalMediaProcessing() "
3492 "output external media already enabled");
3493 return -1;
3494 }
3495 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003496 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003497 }
3498 return 0;
3499}
3500
3501int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3502{
3503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3504 "Channel::DeRegisterExternalMediaProcessing()");
3505
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003506 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003507
3508 if (kPlaybackPerChannel == type)
3509 {
3510 if (!_outputExternalMediaCallbackPtr)
3511 {
3512 _engineStatisticsPtr->SetLastError(
3513 VE_INVALID_OPERATION, kTraceWarning,
3514 "Channel::DeRegisterExternalMediaProcessing() "
3515 "output external media already disabled");
3516 return 0;
3517 }
3518 _outputExternalMedia = false;
3519 _outputExternalMediaCallbackPtr = NULL;
3520 }
3521 else if (kRecordingPerChannel == type)
3522 {
3523 if (!_inputExternalMediaCallbackPtr)
3524 {
3525 _engineStatisticsPtr->SetLastError(
3526 VE_INVALID_OPERATION, kTraceWarning,
3527 "Channel::DeRegisterExternalMediaProcessing() "
3528 "input external media already disabled");
3529 return 0;
3530 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003531 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003532 _inputExternalMediaCallbackPtr = NULL;
3533 }
3534
3535 return 0;
3536}
3537
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003538int Channel::SetExternalMixing(bool enabled) {
3539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3540 "Channel::SetExternalMixing(enabled=%d)", enabled);
3541
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003542 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003543 {
3544 _engineStatisticsPtr->SetLastError(
3545 VE_INVALID_OPERATION, kTraceError,
3546 "Channel::SetExternalMixing() "
3547 "external mixing cannot be changed while playing.");
3548 return -1;
3549 }
3550
3551 _externalMixing = enabled;
3552
3553 return 0;
3554}
3555
niklase@google.com470e71d2011-07-07 08:21:25 +00003556int
niklase@google.com470e71d2011-07-07 08:21:25 +00003557Channel::GetNetworkStatistics(NetworkStatistics& stats)
3558{
3559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3560 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003561 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003562}
3563
wu@webrtc.org24301a62013-12-13 19:17:43 +00003564void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3565 audio_coding_->GetDecodingCallStatistics(stats);
3566}
3567
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003568bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3569 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003570 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003571 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003572 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003573 "Channel::GetDelayEstimate() no valid estimate.");
3574 return false;
3575 }
3576 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3577 _recPacketDelayMs;
3578 *playout_buffer_delay_ms = playout_delay_ms_;
3579 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3580 "Channel::GetDelayEstimate()");
3581 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003582}
3583
deadbeef74375882015-08-13 12:09:10 -07003584int Channel::LeastRequiredDelayMs() const {
3585 return audio_coding_->LeastRequiredDelayMs();
3586}
3587
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003588int Channel::SetInitialPlayoutDelay(int delay_ms)
3589{
3590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3591 "Channel::SetInitialPlayoutDelay()");
3592 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3593 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3594 {
3595 _engineStatisticsPtr->SetLastError(
3596 VE_INVALID_ARGUMENT, kTraceError,
3597 "SetInitialPlayoutDelay() invalid min delay");
3598 return -1;
3599 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003600 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003601 {
3602 _engineStatisticsPtr->SetLastError(
3603 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3604 "SetInitialPlayoutDelay() failed to set min playout delay");
3605 return -1;
3606 }
3607 return 0;
3608}
3609
3610
niklase@google.com470e71d2011-07-07 08:21:25 +00003611int
3612Channel::SetMinimumPlayoutDelay(int delayMs)
3613{
3614 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3615 "Channel::SetMinimumPlayoutDelay()");
3616 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3617 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3618 {
3619 _engineStatisticsPtr->SetLastError(
3620 VE_INVALID_ARGUMENT, kTraceError,
3621 "SetMinimumPlayoutDelay() invalid min delay");
3622 return -1;
3623 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003624 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003625 {
3626 _engineStatisticsPtr->SetLastError(
3627 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3628 "SetMinimumPlayoutDelay() failed to set min playout delay");
3629 return -1;
3630 }
3631 return 0;
3632}
3633
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003634int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3636 "Channel::GetPlayoutTimestamp()");
deadbeef74375882015-08-13 12:09:10 -07003637 uint32_t playout_timestamp_rtp = 0;
3638 {
3639 CriticalSectionScoped cs(video_sync_lock_.get());
3640 playout_timestamp_rtp = playout_timestamp_rtp_;
3641 }
3642 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003643 _engineStatisticsPtr->SetLastError(
3644 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3645 "GetPlayoutTimestamp() failed to retrieve timestamp");
3646 return -1;
3647 }
deadbeef74375882015-08-13 12:09:10 -07003648 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003649 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3650 VoEId(_instanceId,_channelId),
3651 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3652 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003653}
3654
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003655int Channel::SetInitTimestamp(unsigned int timestamp) {
3656 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003657 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003658 if (channel_state_.Get().sending) {
3659 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3660 "SetInitTimestamp() already sending");
3661 return -1;
3662 }
3663 _rtpRtcpModule->SetStartTimestamp(timestamp);
3664 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003665}
3666
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003667int Channel::SetInitSequenceNumber(short sequenceNumber) {
3668 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3669 "Channel::SetInitSequenceNumber()");
3670 if (channel_state_.Get().sending) {
3671 _engineStatisticsPtr->SetLastError(
3672 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3673 return -1;
3674 }
3675 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3676 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003677}
3678
3679int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003680Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003681{
3682 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3683 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003684 *rtpRtcpModule = _rtpRtcpModule.get();
3685 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003686 return 0;
3687}
3688
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003689// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3690// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003691int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003692Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003693{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003694 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003695 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003696
3697 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003698 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003699
3700 if (_inputFilePlayerPtr == NULL)
3701 {
3702 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3703 VoEId(_instanceId, _channelId),
3704 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3705 " doesnt exist");
3706 return -1;
3707 }
3708
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003709 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003710 fileSamples,
3711 mixingFrequency) == -1)
3712 {
3713 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3714 VoEId(_instanceId, _channelId),
3715 "Channel::MixOrReplaceAudioWithFile() file mixing "
3716 "failed");
3717 return -1;
3718 }
3719 if (fileSamples == 0)
3720 {
3721 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3722 VoEId(_instanceId, _channelId),
3723 "Channel::MixOrReplaceAudioWithFile() file is ended");
3724 return 0;
3725 }
3726 }
3727
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003728 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003729
3730 if (_mixFileWithMicrophone)
3731 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003732 // Currently file stream is always mono.
3733 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003734 MixWithSat(_audioFrame.data_,
3735 _audioFrame.num_channels_,
3736 fileBuffer.get(),
3737 1,
3738 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003739 }
3740 else
3741 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003742 // Replace ACM audio with file.
3743 // Currently file stream is always mono.
3744 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003746 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003747 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003748 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003749 mixingFrequency,
3750 AudioFrame::kNormalSpeech,
3751 AudioFrame::kVadUnknown,
3752 1);
3753
3754 }
3755 return 0;
3756}
3757
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003758int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003759Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003760 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003761{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003762 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003763
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003764 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003765 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003766
3767 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003768 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003769
3770 if (_outputFilePlayerPtr == NULL)
3771 {
3772 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3773 VoEId(_instanceId, _channelId),
3774 "Channel::MixAudioWithFile() file mixing failed");
3775 return -1;
3776 }
3777
3778 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003779 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003780 fileSamples,
3781 mixingFrequency) == -1)
3782 {
3783 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3784 VoEId(_instanceId, _channelId),
3785 "Channel::MixAudioWithFile() file mixing failed");
3786 return -1;
3787 }
3788 }
3789
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003790 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003791 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003792 // Currently file stream is always mono.
3793 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003794 MixWithSat(audioFrame.data_,
3795 audioFrame.num_channels_,
3796 fileBuffer.get(),
3797 1,
3798 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003799 }
3800 else
3801 {
3802 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003803 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3804 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003805 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003806 return -1;
3807 }
3808
3809 return 0;
3810}
3811
3812int
3813Channel::InsertInbandDtmfTone()
3814{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003815 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003816 if (_inbandDtmfQueue.PendingDtmf() &&
3817 !_inbandDtmfGenerator.IsAddingTone() &&
3818 _inbandDtmfGenerator.DelaySinceLastTone() >
3819 kMinTelephoneEventSeparationMs)
3820 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003821 int8_t eventCode(0);
3822 uint16_t lengthMs(0);
3823 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003824
3825 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3826 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3827 if (_playInbandDtmfEvent)
3828 {
3829 // Add tone to output mixer using a reduced length to minimize
3830 // risk of echo.
3831 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3832 attenuationDb);
3833 }
3834 }
3835
3836 if (_inbandDtmfGenerator.IsAddingTone())
3837 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003838 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003839 _inbandDtmfGenerator.GetSampleRate(frequency);
3840
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003841 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003842 {
3843 // Update sample rate of Dtmf tone since the mixing frequency
3844 // has changed.
3845 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003846 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003847 // Reset the tone to be added taking the new sample rate into
3848 // account.
3849 _inbandDtmfGenerator.ResetTone();
3850 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003851
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003852 int16_t toneBuffer[320];
3853 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003854 // Get 10ms tone segment and set time since last tone to zero
3855 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3856 {
3857 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3858 VoEId(_instanceId, _channelId),
3859 "Channel::EncodeAndSend() inserting Dtmf failed");
3860 return -1;
3861 }
3862
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003863 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003864 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003865 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003866 sample++)
3867 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003868 for (int channel = 0;
3869 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003870 channel++)
3871 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003872 const size_t index =
3873 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003874 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003875 }
3876 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003877
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003878 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003879 } else
3880 {
3881 // Add 10ms to "delay-since-last-tone" counter
3882 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3883 }
3884 return 0;
3885}
3886
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003887int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003888Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003889{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003890 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003891 if (_transportPtr == NULL)
3892 {
3893 return -1;
3894 }
3895 if (!RTCP)
3896 {
3897 return _transportPtr->SendPacket(_channelId, data, len);
3898 }
3899 else
3900 {
3901 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3902 }
3903}
3904
deadbeef74375882015-08-13 12:09:10 -07003905void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3906 uint32_t playout_timestamp = 0;
3907
3908 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3909 // This can happen if this channel has not been received any RTP packet. In
3910 // this case, NetEq is not capable of computing playout timestamp.
3911 return;
3912 }
3913
3914 uint16_t delay_ms = 0;
3915 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3916 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3917 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3918 " delay from the ADM");
3919 _engineStatisticsPtr->SetLastError(
3920 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3921 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3922 return;
3923 }
3924
3925 jitter_buffer_playout_timestamp_ = playout_timestamp;
3926
3927 // Remove the playout delay.
3928 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3929
3930 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3931 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3932 playout_timestamp);
3933
3934 {
3935 CriticalSectionScoped cs(video_sync_lock_.get());
3936 if (rtcp) {
3937 playout_timestamp_rtcp_ = playout_timestamp;
3938 } else {
3939 playout_timestamp_rtp_ = playout_timestamp;
3940 }
3941 playout_delay_ms_ = delay_ms;
3942 }
3943}
3944
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003945// Called for incoming RTP packets after successful RTP header parsing.
3946void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3947 uint16_t sequence_number) {
3948 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3949 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3950 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003951
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003952 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003953 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003954
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003955 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3956 // every incoming packet.
3957 uint32_t timestamp_diff_ms = (rtp_timestamp -
3958 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003959 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3960 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3961 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3962 // timestamp, the resulting difference is negative, but is set to zero.
3963 // This can happen when a network glitch causes a packet to arrive late,
3964 // and during long comfort noise periods with clock drift.
3965 timestamp_diff_ms = 0;
3966 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003967
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003968 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3969 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003970
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003971 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003972
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003973 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003974
deadbeef74375882015-08-13 12:09:10 -07003975 {
3976 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003977
deadbeef74375882015-08-13 12:09:10 -07003978 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3979 _recPacketDelayMs = packet_delay_ms;
3980 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003981
deadbeef74375882015-08-13 12:09:10 -07003982 if (_average_jitter_buffer_delay_us == 0) {
3983 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3984 return;
3985 }
3986
3987 // Filter average delay value using exponential filter (alpha is
3988 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3989 // risk of rounding error) and compensate for it in GetDelayEstimate()
3990 // later.
3991 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3992 1000 * timestamp_diff_ms + 500) / 8;
3993 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003994}
3995
3996void
3997Channel::RegisterReceiveCodecsToRTPModule()
3998{
3999 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4000 "Channel::RegisterReceiveCodecsToRTPModule()");
4001
4002
4003 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004004 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004005
4006 for (int idx = 0; idx < nSupportedCodecs; idx++)
4007 {
4008 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004009 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004010 (rtp_receiver_->RegisterReceivePayload(
4011 codec.plname,
4012 codec.pltype,
4013 codec.plfreq,
4014 codec.channels,
4015 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004016 {
4017 WEBRTC_TRACE(
4018 kTraceWarning,
4019 kTraceVoice,
4020 VoEId(_instanceId, _channelId),
4021 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4022 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4023 codec.plname, codec.pltype, codec.plfreq,
4024 codec.channels, codec.rate);
4025 }
4026 else
4027 {
4028 WEBRTC_TRACE(
4029 kTraceInfo,
4030 kTraceVoice,
4031 VoEId(_instanceId, _channelId),
4032 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004033 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004034 "receiver",
4035 codec.plname, codec.pltype, codec.plfreq,
4036 codec.channels, codec.rate);
4037 }
4038 }
4039}
4040
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004041// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004042int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004043 CodecInst codec;
4044 bool found_red = false;
4045
4046 // Get default RED settings from the ACM database
4047 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4048 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004049 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004050 if (!STR_CASE_CMP(codec.plname, "RED")) {
4051 found_red = true;
4052 break;
4053 }
4054 }
4055
4056 if (!found_red) {
4057 _engineStatisticsPtr->SetLastError(
4058 VE_CODEC_ERROR, kTraceError,
4059 "SetRedPayloadType() RED is not supported");
4060 return -1;
4061 }
4062
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004063 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004064 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004065 _engineStatisticsPtr->SetLastError(
4066 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4067 "SetRedPayloadType() RED registration in ACM module failed");
4068 return -1;
4069 }
4070
4071 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4072 _engineStatisticsPtr->SetLastError(
4073 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4074 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4075 return -1;
4076 }
4077 return 0;
4078}
4079
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004080int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4081 unsigned char id) {
4082 int error = 0;
4083 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4084 if (enable) {
4085 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4086 }
4087 return error;
4088}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004089
wu@webrtc.org94454b72014-06-05 20:34:08 +00004090int32_t Channel::GetPlayoutFrequency() {
4091 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4092 CodecInst current_recive_codec;
4093 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4094 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4095 // Even though the actual sampling rate for G.722 audio is
4096 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4097 // 8,000 Hz because that value was erroneously assigned in
4098 // RFC 1890 and must remain unchanged for backward compatibility.
4099 playout_frequency = 8000;
4100 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4101 // We are resampling Opus internally to 32,000 Hz until all our
4102 // DSP routines can operate at 48,000 Hz, but the RTP clock
4103 // rate for the Opus payload format is standardized to 48,000 Hz,
4104 // because that is the maximum supported decoding sampling rate.
4105 playout_frequency = 48000;
4106 }
4107 }
4108 return playout_frequency;
4109}
4110
Minyue2013aec2015-05-13 14:14:42 +02004111int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004112 RTCPMethod method = _rtpRtcpModule->RTCP();
4113 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004114 return 0;
4115 }
4116 std::vector<RTCPReportBlock> report_blocks;
4117 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004118
4119 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004120 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004121 if (allow_associate_channel) {
4122 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4123 Channel* channel = associate_send_channel_.channel();
4124 // Tries to get RTT from an associated channel. This is important for
4125 // receive-only channels.
4126 if (channel) {
4127 // To prevent infinite recursion and deadlock, calling GetRTT of
4128 // associate channel should always use "false" for argument:
4129 // |allow_associate_channel|.
4130 rtt = channel->GetRTT(false);
4131 }
4132 }
4133 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004134 }
4135
4136 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4137 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4138 for (; it != report_blocks.end(); ++it) {
4139 if (it->remoteSSRC == remoteSSRC)
4140 break;
4141 }
4142 if (it == report_blocks.end()) {
4143 // We have not received packets with SSRC matching the report blocks.
4144 // To calculate RTT we try with the SSRC of the first report block.
4145 // This is very important for send-only channels where we don't know
4146 // the SSRC of the other end.
4147 remoteSSRC = report_blocks[0].remoteSSRC;
4148 }
Minyue2013aec2015-05-13 14:14:42 +02004149
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004150 int64_t avg_rtt = 0;
4151 int64_t max_rtt= 0;
4152 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004153 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4154 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004155 return 0;
4156 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004157 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004158}
4159
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004160} // namespace voe
4161} // namespace webrtc