blob: fb29dfabab35ee5dbcf3d481de0449d65f8060e2 [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 // out-of-band Dtmf tones are played out by default
kwiberg1f9baab2015-09-16 19:29:43 -0700936 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000937 _engineStatisticsPtr->SetLastError(
938 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
939 "Channel::Init() unable to initialize the ACM - 1");
940 return -1;
941 }
942
943 // --- RTP/RTCP module initialization
944
945 // Ensure that RTCP is enabled by default for the created channel.
946 // Note that, the module will keep generating RTCP until it is explicitly
947 // disabled by the user.
948 // After StopListen (when no sockets exists), RTCP packets will no longer
949 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000950 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
951 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000952 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
953 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000955 (audio_coding_->RegisterTransportCallback(this) == -1) ||
956 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000957
958 if (fail)
959 {
960 _engineStatisticsPtr->SetLastError(
961 VE_CANNOT_INIT_CHANNEL, kTraceError,
962 "Channel::Init() callbacks not registered");
963 return -1;
964 }
965
966 // --- Register all supported codecs to the receiving side of the
967 // RTP/RTCP module
968
969 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000970 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000971
972 for (int idx = 0; idx < nSupportedCodecs; idx++)
973 {
974 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000975 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000976 (rtp_receiver_->RegisterReceivePayload(
977 codec.plname,
978 codec.pltype,
979 codec.plfreq,
980 codec.channels,
981 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 {
983 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
984 VoEId(_instanceId,_channelId),
985 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
986 "to RTP/RTCP receiver",
987 codec.plname, codec.pltype, codec.plfreq,
988 codec.channels, codec.rate);
989 }
990 else
991 {
992 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
993 VoEId(_instanceId,_channelId),
994 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
995 "the RTP/RTCP receiver",
996 codec.plname, codec.pltype, codec.plfreq,
997 codec.channels, codec.rate);
998 }
999
1000 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001001 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 {
1003 SetSendCodec(codec);
1004 }
1005
1006 // Register default PT for outband 'telephone-event'
1007 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1008 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001009 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001010 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001011 {
1012 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1013 VoEId(_instanceId,_channelId),
1014 "Channel::Init() failed to register outband "
1015 "'telephone-event' (%d/%d) correctly",
1016 codec.pltype, codec.plfreq);
1017 }
1018 }
1019
1020 if (!STR_CASE_CMP(codec.plname, "CN"))
1021 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001022 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1023 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001024 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 {
1026 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1027 VoEId(_instanceId,_channelId),
1028 "Channel::Init() failed to register CN (%d/%d) "
1029 "correctly - 1",
1030 codec.pltype, codec.plfreq);
1031 }
1032 }
1033#ifdef WEBRTC_CODEC_RED
1034 // Register RED to the receiving side of the ACM.
1035 // We will not receive an OnInitializeDecoder() callback for RED.
1036 if (!STR_CASE_CMP(codec.plname, "RED"))
1037 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001038 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 {
1040 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1041 VoEId(_instanceId,_channelId),
1042 "Channel::Init() failed to register RED (%d/%d) "
1043 "correctly",
1044 codec.pltype, codec.plfreq);
1045 }
1046 }
1047#endif
1048 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001049
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001050 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1051 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1052 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001053 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001054 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1055 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1056 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 }
1058
1059 return 0;
1060}
1061
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001062int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001063Channel::SetEngineInformation(Statistics& engineStatistics,
1064 OutputMixer& outputMixer,
1065 voe::TransmitMixer& transmitMixer,
1066 ProcessThread& moduleProcessThread,
1067 AudioDeviceModule& audioDeviceModule,
1068 VoiceEngineObserver* voiceEngineObserver,
1069 CriticalSectionWrapper* callbackCritSect)
1070{
1071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1072 "Channel::SetEngineInformation()");
1073 _engineStatisticsPtr = &engineStatistics;
1074 _outputMixerPtr = &outputMixer;
1075 _transmitMixerPtr = &transmitMixer,
1076 _moduleProcessThreadPtr = &moduleProcessThread;
1077 _audioDeviceModulePtr = &audioDeviceModule;
1078 _voiceEngineObserverPtr = voiceEngineObserver;
1079 _callbackCritSectPtr = callbackCritSect;
1080 return 0;
1081}
1082
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001083int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001084Channel::UpdateLocalTimeStamp()
1085{
1086
Peter Kastingb7e50542015-06-11 12:55:50 -07001087 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 return 0;
1089}
1090
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001091int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001092Channel::StartPlayout()
1093{
1094 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1095 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001096 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 {
1098 return 0;
1099 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001100
1101 if (!_externalMixing) {
1102 // Add participant as candidates for mixing.
1103 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1104 {
1105 _engineStatisticsPtr->SetLastError(
1106 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1107 "StartPlayout() failed to add participant to mixer");
1108 return -1;
1109 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001110 }
1111
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001112 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001113 if (RegisterFilePlayingToMixer() != 0)
1114 return -1;
1115
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 return 0;
1117}
1118
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001119int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001120Channel::StopPlayout()
1121{
1122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1123 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001124 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001125 {
1126 return 0;
1127 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001128
1129 if (!_externalMixing) {
1130 // Remove participant as candidates for mixing
1131 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1132 {
1133 _engineStatisticsPtr->SetLastError(
1134 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1135 "StopPlayout() failed to remove participant from mixer");
1136 return -1;
1137 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 }
1139
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001140 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 _outputAudioLevel.Clear();
1142
1143 return 0;
1144}
1145
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001146int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001147Channel::StartSend()
1148{
1149 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1150 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001151 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001152 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001153 if (send_sequence_number_)
1154 SetInitSequenceNumber(send_sequence_number_);
1155
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001156 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001158 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001159 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001160 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001161
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001162 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 {
1164 _engineStatisticsPtr->SetLastError(
1165 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1166 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001167 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001168 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 return -1;
1170 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001171
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 return 0;
1173}
1174
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001175int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001176Channel::StopSend()
1177{
1178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1179 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001180 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001182 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001183 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001184 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001185
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001186 // Store the sequence number to be able to pick up the same sequence for
1187 // the next StartSend(). This is needed for restarting device, otherwise
1188 // it might cause libSRTP to complain about packets being replayed.
1189 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1190 // CL is landed. See issue
1191 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1192 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1193
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 // Reset sending SSRC and sequence number and triggers direct transmission
1195 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001196 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001197 {
1198 _engineStatisticsPtr->SetLastError(
1199 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1200 "StartSend() RTP/RTCP failed to stop sending");
1201 }
1202
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 return 0;
1204}
1205
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001206int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001207Channel::StartReceiving()
1208{
1209 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1210 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001211 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 {
1213 return 0;
1214 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001215 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 _numberOfDiscardedPackets = 0;
1217 return 0;
1218}
1219
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001220int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001221Channel::StopReceiving()
1222{
1223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1224 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001225 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 {
1227 return 0;
1228 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001229
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001230 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001231 return 0;
1232}
1233
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001234int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001235Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1236{
1237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1238 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001239 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001240
1241 if (_voiceEngineObserverPtr)
1242 {
1243 _engineStatisticsPtr->SetLastError(
1244 VE_INVALID_OPERATION, kTraceError,
1245 "RegisterVoiceEngineObserver() observer already enabled");
1246 return -1;
1247 }
1248 _voiceEngineObserverPtr = &observer;
1249 return 0;
1250}
1251
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001252int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001253Channel::DeRegisterVoiceEngineObserver()
1254{
1255 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1256 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001257 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001258
1259 if (!_voiceEngineObserverPtr)
1260 {
1261 _engineStatisticsPtr->SetLastError(
1262 VE_INVALID_OPERATION, kTraceWarning,
1263 "DeRegisterVoiceEngineObserver() observer already disabled");
1264 return 0;
1265 }
1266 _voiceEngineObserverPtr = NULL;
1267 return 0;
1268}
1269
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001270int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001271Channel::GetSendCodec(CodecInst& codec)
1272{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001273 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001274}
1275
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001276int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001277Channel::GetRecCodec(CodecInst& codec)
1278{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001279 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001280}
1281
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001282int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001283Channel::SetSendCodec(const CodecInst& codec)
1284{
1285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1286 "Channel::SetSendCodec()");
1287
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001288 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 {
1290 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1291 "SetSendCodec() failed to register codec to ACM");
1292 return -1;
1293 }
1294
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001295 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001297 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1298 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 {
1300 WEBRTC_TRACE(
1301 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1302 "SetSendCodec() failed to register codec to"
1303 " RTP/RTCP module");
1304 return -1;
1305 }
1306 }
1307
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001308 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 {
1310 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1311 "SetSendCodec() failed to set audio packet size");
1312 return -1;
1313 }
1314
1315 return 0;
1316}
1317
Ivo Creusenadf89b72015-04-29 16:03:33 +02001318void Channel::SetBitRate(int bitrate_bps) {
1319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1320 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1321 audio_coding_->SetBitRate(bitrate_bps);
1322}
1323
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001324void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001325 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001326 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1327
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001328 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001329 if (audio_coding_->SetPacketLossRate(
1330 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001331 assert(false); // This should not happen.
1332 }
1333}
1334
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001335int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001336Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1337{
1338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1339 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001340 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001341 // To disable VAD, DTX must be disabled too
1342 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001343 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001344 {
1345 _engineStatisticsPtr->SetLastError(
1346 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1347 "SetVADStatus() failed to set VAD");
1348 return -1;
1349 }
1350 return 0;
1351}
1352
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001353int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001354Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1355{
1356 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1357 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001358 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001359 {
1360 _engineStatisticsPtr->SetLastError(
1361 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1362 "GetVADStatus() failed to get VAD status");
1363 return -1;
1364 }
1365 disabledDTX = !disabledDTX;
1366 return 0;
1367}
1368
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001369int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001370Channel::SetRecPayloadType(const CodecInst& codec)
1371{
1372 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1373 "Channel::SetRecPayloadType()");
1374
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001375 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 {
1377 _engineStatisticsPtr->SetLastError(
1378 VE_ALREADY_PLAYING, kTraceError,
1379 "SetRecPayloadType() unable to set PT while playing");
1380 return -1;
1381 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001382 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 {
1384 _engineStatisticsPtr->SetLastError(
1385 VE_ALREADY_LISTENING, kTraceError,
1386 "SetRecPayloadType() unable to set PT while listening");
1387 return -1;
1388 }
1389
1390 if (codec.pltype == -1)
1391 {
1392 // De-register the selected codec (RTP/RTCP module and ACM)
1393
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001394 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 CodecInst rxCodec = codec;
1396
1397 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001398 rtp_payload_registry_->ReceivePayloadType(
1399 rxCodec.plname,
1400 rxCodec.plfreq,
1401 rxCodec.channels,
1402 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1403 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001404 rxCodec.pltype = pltype;
1405
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001406 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 {
1408 _engineStatisticsPtr->SetLastError(
1409 VE_RTP_RTCP_MODULE_ERROR,
1410 kTraceError,
1411 "SetRecPayloadType() RTP/RTCP-module deregistration "
1412 "failed");
1413 return -1;
1414 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001415 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 {
1417 _engineStatisticsPtr->SetLastError(
1418 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1419 "SetRecPayloadType() ACM deregistration failed - 1");
1420 return -1;
1421 }
1422 return 0;
1423 }
1424
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001425 if (rtp_receiver_->RegisterReceivePayload(
1426 codec.plname,
1427 codec.pltype,
1428 codec.plfreq,
1429 codec.channels,
1430 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 {
1432 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001433 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1434 if (rtp_receiver_->RegisterReceivePayload(
1435 codec.plname,
1436 codec.pltype,
1437 codec.plfreq,
1438 codec.channels,
1439 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 {
1441 _engineStatisticsPtr->SetLastError(
1442 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1443 "SetRecPayloadType() RTP/RTCP-module registration failed");
1444 return -1;
1445 }
1446 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001447 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001448 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001449 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1450 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001451 {
1452 _engineStatisticsPtr->SetLastError(
1453 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1454 "SetRecPayloadType() ACM registration failed - 1");
1455 return -1;
1456 }
1457 }
1458 return 0;
1459}
1460
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001461int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001462Channel::GetRecPayloadType(CodecInst& codec)
1463{
1464 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1465 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001466 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001467 if (rtp_payload_registry_->ReceivePayloadType(
1468 codec.plname,
1469 codec.plfreq,
1470 codec.channels,
1471 (codec.rate < 0) ? 0 : codec.rate,
1472 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 {
1474 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001475 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001476 "GetRecPayloadType() failed to retrieve RX payload type");
1477 return -1;
1478 }
1479 codec.pltype = payloadType;
1480 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001481 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 return 0;
1483}
1484
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001485int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001486Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1487{
1488 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1489 "Channel::SetSendCNPayloadType()");
1490
1491 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001492 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001493 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001494 if (frequency == kFreq32000Hz)
1495 samplingFreqHz = 32000;
1496 else if (frequency == kFreq16000Hz)
1497 samplingFreqHz = 16000;
1498
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001499 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 {
1501 _engineStatisticsPtr->SetLastError(
1502 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1503 "SetSendCNPayloadType() failed to retrieve default CN codec "
1504 "settings");
1505 return -1;
1506 }
1507
1508 // Modify the payload type (must be set to dynamic range)
1509 codec.pltype = type;
1510
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001511 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001512 {
1513 _engineStatisticsPtr->SetLastError(
1514 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1515 "SetSendCNPayloadType() failed to register CN to ACM");
1516 return -1;
1517 }
1518
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001519 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001520 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001521 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1522 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001523 {
1524 _engineStatisticsPtr->SetLastError(
1525 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1526 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1527 "module");
1528 return -1;
1529 }
1530 }
1531 return 0;
1532}
1533
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001534int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001535 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001536 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001537
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001538 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001539 _engineStatisticsPtr->SetLastError(
1540 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001541 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001542 return -1;
1543 }
1544 return 0;
1545}
1546
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001547int Channel::SetOpusDtx(bool enable_dtx) {
1548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1549 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001550 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001551 : audio_coding_->DisableOpusDtx();
1552 if (ret != 0) {
1553 _engineStatisticsPtr->SetLastError(
1554 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1555 return -1;
1556 }
1557 return 0;
1558}
1559
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001560int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001561{
1562 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1563 "Channel::RegisterExternalTransport()");
1564
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001565 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001566
niklase@google.com470e71d2011-07-07 08:21:25 +00001567 if (_externalTransport)
1568 {
1569 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1570 kTraceError,
1571 "RegisterExternalTransport() external transport already enabled");
1572 return -1;
1573 }
1574 _externalTransport = true;
1575 _transportPtr = &transport;
1576 return 0;
1577}
1578
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001579int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001580Channel::DeRegisterExternalTransport()
1581{
1582 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1583 "Channel::DeRegisterExternalTransport()");
1584
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001585 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001586
niklase@google.com470e71d2011-07-07 08:21:25 +00001587 if (!_transportPtr)
1588 {
1589 _engineStatisticsPtr->SetLastError(
1590 VE_INVALID_OPERATION, kTraceWarning,
1591 "DeRegisterExternalTransport() external transport already "
1592 "disabled");
1593 return 0;
1594 }
1595 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 _transportPtr = NULL;
1597 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1598 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001599 return 0;
1600}
1601
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001602int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001603 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001604 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1605 "Channel::ReceivedRTPPacket()");
1606
1607 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001608 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001609
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001610 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001611 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001612 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1613 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1614 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001615 return -1;
1616 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001617 header.payload_type_frequency =
1618 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001619 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001620 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001621 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001622 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001623 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001624 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001625
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001626 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001627}
1628
1629bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001630 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001631 const RTPHeader& header,
1632 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001633 if (rtp_payload_registry_->IsRtx(header)) {
1634 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001635 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001636 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001637 assert(packet_length >= header.headerLength);
1638 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001639 PayloadUnion payload_specific;
1640 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001641 &payload_specific)) {
1642 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001643 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001644 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1645 payload_specific, in_order);
1646}
1647
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001648bool Channel::HandleRtxPacket(const uint8_t* packet,
1649 size_t packet_length,
1650 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001651 if (!rtp_payload_registry_->IsRtx(header))
1652 return false;
1653
1654 // Remove the RTX header and parse the original RTP header.
1655 if (packet_length < header.headerLength)
1656 return false;
1657 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1658 return false;
1659 if (restored_packet_in_use_) {
1660 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1661 "Multiple RTX headers detected, dropping packet");
1662 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001663 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001664 uint8_t* restored_packet_ptr = restored_packet_;
1665 if (!rtp_payload_registry_->RestoreOriginalPacket(
1666 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1667 header)) {
1668 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1669 "Incoming RTX packet: invalid RTP header");
1670 return false;
1671 }
1672 restored_packet_in_use_ = true;
1673 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1674 restored_packet_in_use_ = false;
1675 return ret;
1676}
1677
1678bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1679 StreamStatistician* statistician =
1680 rtp_receive_statistics_->GetStatistician(header.ssrc);
1681 if (!statistician)
1682 return false;
1683 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001684}
1685
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001686bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1687 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001688 // Retransmissions are handled separately if RTX is enabled.
1689 if (rtp_payload_registry_->RtxEnabled())
1690 return false;
1691 StreamStatistician* statistician =
1692 rtp_receive_statistics_->GetStatistician(header.ssrc);
1693 if (!statistician)
1694 return false;
1695 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001696 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001697 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001698 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001699 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001700}
1701
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001702int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001703 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1704 "Channel::ReceivedRTCPPacket()");
1705 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001706 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001707
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001708 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001709 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001710 _engineStatisticsPtr->SetLastError(
1711 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1712 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1713 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001714
Minyue2013aec2015-05-13 14:14:42 +02001715 int64_t rtt = GetRTT(true);
1716 if (rtt == 0) {
1717 // Waiting for valid RTT.
1718 return 0;
1719 }
1720 uint32_t ntp_secs = 0;
1721 uint32_t ntp_frac = 0;
1722 uint32_t rtp_timestamp = 0;
1723 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1724 &rtp_timestamp)) {
1725 // Waiting for RTCP.
1726 return 0;
1727 }
1728
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001729 {
1730 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001731 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001732 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001733 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001734}
1735
niklase@google.com470e71d2011-07-07 08:21:25 +00001736int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001737 bool loop,
1738 FileFormats format,
1739 int startPosition,
1740 float volumeScaling,
1741 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001742 const CodecInst* codecInst)
1743{
1744 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1745 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1746 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1747 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1748 startPosition, stopPosition);
1749
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001750 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001751 {
1752 _engineStatisticsPtr->SetLastError(
1753 VE_ALREADY_PLAYING, kTraceError,
1754 "StartPlayingFileLocally() is already playing");
1755 return -1;
1756 }
1757
niklase@google.com470e71d2011-07-07 08:21:25 +00001758 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001759 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001760
1761 if (_outputFilePlayerPtr)
1762 {
1763 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1764 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1765 _outputFilePlayerPtr = NULL;
1766 }
1767
1768 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1769 _outputFilePlayerId, (const FileFormats)format);
1770
1771 if (_outputFilePlayerPtr == NULL)
1772 {
1773 _engineStatisticsPtr->SetLastError(
1774 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001775 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001776 return -1;
1777 }
1778
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001779 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001780
1781 if (_outputFilePlayerPtr->StartPlayingFile(
1782 fileName,
1783 loop,
1784 startPosition,
1785 volumeScaling,
1786 notificationTime,
1787 stopPosition,
1788 (const CodecInst*)codecInst) != 0)
1789 {
1790 _engineStatisticsPtr->SetLastError(
1791 VE_BAD_FILE, kTraceError,
1792 "StartPlayingFile() failed to start file playout");
1793 _outputFilePlayerPtr->StopPlayingFile();
1794 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1795 _outputFilePlayerPtr = NULL;
1796 return -1;
1797 }
1798 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001799 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001800 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001801
1802 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001803 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001804
1805 return 0;
1806}
1807
1808int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001809 FileFormats format,
1810 int startPosition,
1811 float volumeScaling,
1812 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001813 const CodecInst* codecInst)
1814{
1815 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1816 "Channel::StartPlayingFileLocally(format=%d,"
1817 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1818 format, volumeScaling, startPosition, stopPosition);
1819
1820 if(stream == NULL)
1821 {
1822 _engineStatisticsPtr->SetLastError(
1823 VE_BAD_FILE, kTraceError,
1824 "StartPlayingFileLocally() NULL as input stream");
1825 return -1;
1826 }
1827
1828
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001829 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001830 {
1831 _engineStatisticsPtr->SetLastError(
1832 VE_ALREADY_PLAYING, kTraceError,
1833 "StartPlayingFileLocally() is already playing");
1834 return -1;
1835 }
1836
niklase@google.com470e71d2011-07-07 08:21:25 +00001837 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001838 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001839
1840 // Destroy the old instance
1841 if (_outputFilePlayerPtr)
1842 {
1843 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1844 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1845 _outputFilePlayerPtr = NULL;
1846 }
1847
1848 // Create the instance
1849 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1850 _outputFilePlayerId,
1851 (const FileFormats)format);
1852
1853 if (_outputFilePlayerPtr == NULL)
1854 {
1855 _engineStatisticsPtr->SetLastError(
1856 VE_INVALID_ARGUMENT, kTraceError,
1857 "StartPlayingFileLocally() filePlayer format isnot correct");
1858 return -1;
1859 }
1860
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001861 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001862
1863 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1864 volumeScaling,
1865 notificationTime,
1866 stopPosition, codecInst) != 0)
1867 {
1868 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1869 "StartPlayingFile() failed to "
1870 "start file playout");
1871 _outputFilePlayerPtr->StopPlayingFile();
1872 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1873 _outputFilePlayerPtr = NULL;
1874 return -1;
1875 }
1876 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001877 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001878 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001879
1880 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001881 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001882
niklase@google.com470e71d2011-07-07 08:21:25 +00001883 return 0;
1884}
1885
1886int Channel::StopPlayingFileLocally()
1887{
1888 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1889 "Channel::StopPlayingFileLocally()");
1890
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001891 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001892 {
1893 _engineStatisticsPtr->SetLastError(
1894 VE_INVALID_OPERATION, kTraceWarning,
1895 "StopPlayingFileLocally() isnot playing");
1896 return 0;
1897 }
1898
niklase@google.com470e71d2011-07-07 08:21:25 +00001899 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001900 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001901
1902 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1903 {
1904 _engineStatisticsPtr->SetLastError(
1905 VE_STOP_RECORDING_FAILED, kTraceError,
1906 "StopPlayingFile() could not stop playing");
1907 return -1;
1908 }
1909 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1910 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1911 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001912 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001913 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001914 // _fileCritSect cannot be taken while calling
1915 // SetAnonymousMixibilityStatus. Refer to comments in
1916 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001917 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1918 {
1919 _engineStatisticsPtr->SetLastError(
1920 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001921 "StopPlayingFile() failed to stop participant from playing as"
1922 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001923 return -1;
1924 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001925
1926 return 0;
1927}
1928
1929int Channel::IsPlayingFileLocally() const
1930{
1931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1932 "Channel::IsPlayingFileLocally()");
1933
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001934 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001935}
1936
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001937int Channel::RegisterFilePlayingToMixer()
1938{
1939 // Return success for not registering for file playing to mixer if:
1940 // 1. playing file before playout is started on that channel.
1941 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001942 if (!channel_state_.Get().playing ||
1943 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001944 {
1945 return 0;
1946 }
1947
1948 // |_fileCritSect| cannot be taken while calling
1949 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1950 // frames can be pulled by the mixer. Since the frames are generated from
1951 // the file, _fileCritSect will be taken. This would result in a deadlock.
1952 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1953 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001954 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001955 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001956 _engineStatisticsPtr->SetLastError(
1957 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1958 "StartPlayingFile() failed to add participant as file to mixer");
1959 _outputFilePlayerPtr->StopPlayingFile();
1960 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1961 _outputFilePlayerPtr = NULL;
1962 return -1;
1963 }
1964
1965 return 0;
1966}
1967
niklase@google.com470e71d2011-07-07 08:21:25 +00001968int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001969 bool loop,
1970 FileFormats format,
1971 int startPosition,
1972 float volumeScaling,
1973 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001974 const CodecInst* codecInst)
1975{
1976 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1977 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1978 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1979 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1980 startPosition, stopPosition);
1981
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001982 CriticalSectionScoped cs(&_fileCritSect);
1983
1984 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001985 {
1986 _engineStatisticsPtr->SetLastError(
1987 VE_ALREADY_PLAYING, kTraceWarning,
1988 "StartPlayingFileAsMicrophone() filePlayer is playing");
1989 return 0;
1990 }
1991
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 // Destroy the old instance
1993 if (_inputFilePlayerPtr)
1994 {
1995 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1996 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1997 _inputFilePlayerPtr = NULL;
1998 }
1999
2000 // Create the instance
2001 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2002 _inputFilePlayerId, (const FileFormats)format);
2003
2004 if (_inputFilePlayerPtr == NULL)
2005 {
2006 _engineStatisticsPtr->SetLastError(
2007 VE_INVALID_ARGUMENT, kTraceError,
2008 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2009 return -1;
2010 }
2011
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002012 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002013
2014 if (_inputFilePlayerPtr->StartPlayingFile(
2015 fileName,
2016 loop,
2017 startPosition,
2018 volumeScaling,
2019 notificationTime,
2020 stopPosition,
2021 (const CodecInst*)codecInst) != 0)
2022 {
2023 _engineStatisticsPtr->SetLastError(
2024 VE_BAD_FILE, kTraceError,
2025 "StartPlayingFile() failed to start file playout");
2026 _inputFilePlayerPtr->StopPlayingFile();
2027 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2028 _inputFilePlayerPtr = NULL;
2029 return -1;
2030 }
2031 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002032 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002033
2034 return 0;
2035}
2036
2037int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002038 FileFormats format,
2039 int startPosition,
2040 float volumeScaling,
2041 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002042 const CodecInst* codecInst)
2043{
2044 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2045 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2046 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2047 format, volumeScaling, startPosition, stopPosition);
2048
2049 if(stream == NULL)
2050 {
2051 _engineStatisticsPtr->SetLastError(
2052 VE_BAD_FILE, kTraceError,
2053 "StartPlayingFileAsMicrophone NULL as input stream");
2054 return -1;
2055 }
2056
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002057 CriticalSectionScoped cs(&_fileCritSect);
2058
2059 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002060 {
2061 _engineStatisticsPtr->SetLastError(
2062 VE_ALREADY_PLAYING, kTraceWarning,
2063 "StartPlayingFileAsMicrophone() is playing");
2064 return 0;
2065 }
2066
niklase@google.com470e71d2011-07-07 08:21:25 +00002067 // Destroy the old instance
2068 if (_inputFilePlayerPtr)
2069 {
2070 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2071 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2072 _inputFilePlayerPtr = NULL;
2073 }
2074
2075 // Create the instance
2076 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2077 _inputFilePlayerId, (const FileFormats)format);
2078
2079 if (_inputFilePlayerPtr == NULL)
2080 {
2081 _engineStatisticsPtr->SetLastError(
2082 VE_INVALID_ARGUMENT, kTraceError,
2083 "StartPlayingInputFile() filePlayer format isnot correct");
2084 return -1;
2085 }
2086
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002087 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002088
2089 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2090 volumeScaling, notificationTime,
2091 stopPosition, codecInst) != 0)
2092 {
2093 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2094 "StartPlayingFile() failed to start "
2095 "file playout");
2096 _inputFilePlayerPtr->StopPlayingFile();
2097 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2098 _inputFilePlayerPtr = NULL;
2099 return -1;
2100 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002101
niklase@google.com470e71d2011-07-07 08:21:25 +00002102 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002103 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002104
2105 return 0;
2106}
2107
2108int Channel::StopPlayingFileAsMicrophone()
2109{
2110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2111 "Channel::StopPlayingFileAsMicrophone()");
2112
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002113 CriticalSectionScoped cs(&_fileCritSect);
2114
2115 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002116 {
2117 _engineStatisticsPtr->SetLastError(
2118 VE_INVALID_OPERATION, kTraceWarning,
2119 "StopPlayingFileAsMicrophone() isnot playing");
2120 return 0;
2121 }
2122
niklase@google.com470e71d2011-07-07 08:21:25 +00002123 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2124 {
2125 _engineStatisticsPtr->SetLastError(
2126 VE_STOP_RECORDING_FAILED, kTraceError,
2127 "StopPlayingFile() could not stop playing");
2128 return -1;
2129 }
2130 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2131 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2132 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002133 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002134
2135 return 0;
2136}
2137
2138int Channel::IsPlayingFileAsMicrophone() const
2139{
2140 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2141 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002142 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002143}
2144
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002145int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002146 const CodecInst* codecInst)
2147{
2148 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2149 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2150
2151 if (_outputFileRecording)
2152 {
2153 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2154 "StartRecordingPlayout() is already recording");
2155 return 0;
2156 }
2157
2158 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002159 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002160 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2161
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002162 if ((codecInst != NULL) &&
2163 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002164 {
2165 _engineStatisticsPtr->SetLastError(
2166 VE_BAD_ARGUMENT, kTraceError,
2167 "StartRecordingPlayout() invalid compression");
2168 return(-1);
2169 }
2170 if(codecInst == NULL)
2171 {
2172 format = kFileFormatPcm16kHzFile;
2173 codecInst=&dummyCodec;
2174 }
2175 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2176 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2177 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2178 {
2179 format = kFileFormatWavFile;
2180 }
2181 else
2182 {
2183 format = kFileFormatCompressedFile;
2184 }
2185
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002186 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002187
2188 // Destroy the old instance
2189 if (_outputFileRecorderPtr)
2190 {
2191 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2192 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2193 _outputFileRecorderPtr = NULL;
2194 }
2195
2196 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2197 _outputFileRecorderId, (const FileFormats)format);
2198 if (_outputFileRecorderPtr == NULL)
2199 {
2200 _engineStatisticsPtr->SetLastError(
2201 VE_INVALID_ARGUMENT, kTraceError,
2202 "StartRecordingPlayout() fileRecorder format isnot correct");
2203 return -1;
2204 }
2205
2206 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2207 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2208 {
2209 _engineStatisticsPtr->SetLastError(
2210 VE_BAD_FILE, kTraceError,
2211 "StartRecordingAudioFile() failed to start file recording");
2212 _outputFileRecorderPtr->StopRecording();
2213 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2214 _outputFileRecorderPtr = NULL;
2215 return -1;
2216 }
2217 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2218 _outputFileRecording = true;
2219
2220 return 0;
2221}
2222
2223int Channel::StartRecordingPlayout(OutStream* stream,
2224 const CodecInst* codecInst)
2225{
2226 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2227 "Channel::StartRecordingPlayout()");
2228
2229 if (_outputFileRecording)
2230 {
2231 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2232 "StartRecordingPlayout() is already recording");
2233 return 0;
2234 }
2235
2236 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002237 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002238 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2239
2240 if (codecInst != NULL && codecInst->channels != 1)
2241 {
2242 _engineStatisticsPtr->SetLastError(
2243 VE_BAD_ARGUMENT, kTraceError,
2244 "StartRecordingPlayout() invalid compression");
2245 return(-1);
2246 }
2247 if(codecInst == NULL)
2248 {
2249 format = kFileFormatPcm16kHzFile;
2250 codecInst=&dummyCodec;
2251 }
2252 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2253 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2254 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2255 {
2256 format = kFileFormatWavFile;
2257 }
2258 else
2259 {
2260 format = kFileFormatCompressedFile;
2261 }
2262
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002263 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002264
2265 // Destroy the old instance
2266 if (_outputFileRecorderPtr)
2267 {
2268 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2269 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2270 _outputFileRecorderPtr = NULL;
2271 }
2272
2273 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2274 _outputFileRecorderId, (const FileFormats)format);
2275 if (_outputFileRecorderPtr == NULL)
2276 {
2277 _engineStatisticsPtr->SetLastError(
2278 VE_INVALID_ARGUMENT, kTraceError,
2279 "StartRecordingPlayout() fileRecorder format isnot correct");
2280 return -1;
2281 }
2282
2283 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2284 notificationTime) != 0)
2285 {
2286 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2287 "StartRecordingPlayout() failed to "
2288 "start file recording");
2289 _outputFileRecorderPtr->StopRecording();
2290 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2291 _outputFileRecorderPtr = NULL;
2292 return -1;
2293 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002294
niklase@google.com470e71d2011-07-07 08:21:25 +00002295 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2296 _outputFileRecording = true;
2297
2298 return 0;
2299}
2300
2301int Channel::StopRecordingPlayout()
2302{
2303 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2304 "Channel::StopRecordingPlayout()");
2305
2306 if (!_outputFileRecording)
2307 {
2308 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2309 "StopRecordingPlayout() isnot recording");
2310 return -1;
2311 }
2312
2313
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002314 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002315
2316 if (_outputFileRecorderPtr->StopRecording() != 0)
2317 {
2318 _engineStatisticsPtr->SetLastError(
2319 VE_STOP_RECORDING_FAILED, kTraceError,
2320 "StopRecording() could not stop recording");
2321 return(-1);
2322 }
2323 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2324 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2325 _outputFileRecorderPtr = NULL;
2326 _outputFileRecording = false;
2327
2328 return 0;
2329}
2330
2331void
2332Channel::SetMixWithMicStatus(bool mix)
2333{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002334 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002335 _mixFileWithMicrophone=mix;
2336}
2337
2338int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002339Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002340{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002341 int8_t currentLevel = _outputAudioLevel.Level();
2342 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002343 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2344 VoEId(_instanceId,_channelId),
2345 "GetSpeechOutputLevel() => level=%u", level);
2346 return 0;
2347}
2348
2349int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002350Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002351{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002352 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2353 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002354 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2355 VoEId(_instanceId,_channelId),
2356 "GetSpeechOutputLevelFullRange() => level=%u", level);
2357 return 0;
2358}
2359
2360int
2361Channel::SetMute(bool enable)
2362{
wu@webrtc.org63420662013-10-17 18:28:55 +00002363 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002364 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2365 "Channel::SetMute(enable=%d)", enable);
2366 _mute = enable;
2367 return 0;
2368}
2369
2370bool
2371Channel::Mute() const
2372{
wu@webrtc.org63420662013-10-17 18:28:55 +00002373 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002374 return _mute;
2375}
2376
2377int
2378Channel::SetOutputVolumePan(float left, float right)
2379{
wu@webrtc.org63420662013-10-17 18:28:55 +00002380 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002381 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2382 "Channel::SetOutputVolumePan()");
2383 _panLeft = left;
2384 _panRight = right;
2385 return 0;
2386}
2387
2388int
2389Channel::GetOutputVolumePan(float& left, float& right) const
2390{
wu@webrtc.org63420662013-10-17 18:28:55 +00002391 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002392 left = _panLeft;
2393 right = _panRight;
2394 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2395 VoEId(_instanceId,_channelId),
2396 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2397 return 0;
2398}
2399
2400int
2401Channel::SetChannelOutputVolumeScaling(float scaling)
2402{
wu@webrtc.org63420662013-10-17 18:28:55 +00002403 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002404 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2405 "Channel::SetChannelOutputVolumeScaling()");
2406 _outputGain = scaling;
2407 return 0;
2408}
2409
2410int
2411Channel::GetChannelOutputVolumeScaling(float& scaling) const
2412{
wu@webrtc.org63420662013-10-17 18:28:55 +00002413 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002414 scaling = _outputGain;
2415 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2416 VoEId(_instanceId,_channelId),
2417 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2418 return 0;
2419}
2420
niklase@google.com470e71d2011-07-07 08:21:25 +00002421int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002422 int lengthMs, int attenuationDb,
2423 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002424{
2425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2426 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2427 playDtmfEvent);
2428
2429 _playOutbandDtmfEvent = playDtmfEvent;
2430
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002431 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002432 attenuationDb) != 0)
2433 {
2434 _engineStatisticsPtr->SetLastError(
2435 VE_SEND_DTMF_FAILED,
2436 kTraceWarning,
2437 "SendTelephoneEventOutband() failed to send event");
2438 return -1;
2439 }
2440 return 0;
2441}
2442
2443int Channel::SendTelephoneEventInband(unsigned char eventCode,
2444 int lengthMs,
2445 int attenuationDb,
2446 bool playDtmfEvent)
2447{
2448 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2449 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2450 playDtmfEvent);
2451
2452 _playInbandDtmfEvent = playDtmfEvent;
2453 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2454
2455 return 0;
2456}
2457
2458int
niklase@google.com470e71d2011-07-07 08:21:25 +00002459Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2460{
2461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2462 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002463 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002464 {
2465 _engineStatisticsPtr->SetLastError(
2466 VE_INVALID_ARGUMENT, kTraceError,
2467 "SetSendTelephoneEventPayloadType() invalid type");
2468 return -1;
2469 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002470 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002471 codec.plfreq = 8000;
2472 codec.pltype = type;
2473 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002474 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002475 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002476 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2477 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2478 _engineStatisticsPtr->SetLastError(
2479 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2480 "SetSendTelephoneEventPayloadType() failed to register send"
2481 "payload type");
2482 return -1;
2483 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002484 }
2485 _sendTelephoneEventPayloadType = type;
2486 return 0;
2487}
2488
2489int
2490Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2491{
2492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2493 "Channel::GetSendTelephoneEventPayloadType()");
2494 type = _sendTelephoneEventPayloadType;
2495 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2496 VoEId(_instanceId,_channelId),
2497 "GetSendTelephoneEventPayloadType() => type=%u", type);
2498 return 0;
2499}
2500
niklase@google.com470e71d2011-07-07 08:21:25 +00002501int
2502Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2503{
2504 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2505 "Channel::UpdateRxVadDetection()");
2506
2507 int vadDecision = 1;
2508
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002509 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002510
2511 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2512 {
2513 OnRxVadDetected(vadDecision);
2514 _oldVadDecision = vadDecision;
2515 }
2516
2517 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2518 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2519 vadDecision);
2520 return 0;
2521}
2522
2523int
2524Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2525{
2526 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2527 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002528 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002529
2530 if (_rxVadObserverPtr)
2531 {
2532 _engineStatisticsPtr->SetLastError(
2533 VE_INVALID_OPERATION, kTraceError,
2534 "RegisterRxVadObserver() observer already enabled");
2535 return -1;
2536 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002537 _rxVadObserverPtr = &observer;
2538 _RxVadDetection = true;
2539 return 0;
2540}
2541
2542int
2543Channel::DeRegisterRxVadObserver()
2544{
2545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2546 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002547 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002548
2549 if (!_rxVadObserverPtr)
2550 {
2551 _engineStatisticsPtr->SetLastError(
2552 VE_INVALID_OPERATION, kTraceWarning,
2553 "DeRegisterRxVadObserver() observer already disabled");
2554 return 0;
2555 }
2556 _rxVadObserverPtr = NULL;
2557 _RxVadDetection = false;
2558 return 0;
2559}
2560
2561int
2562Channel::VoiceActivityIndicator(int &activity)
2563{
2564 activity = _sendFrameType;
2565
2566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002567 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002568 return 0;
2569}
2570
2571#ifdef WEBRTC_VOICE_ENGINE_AGC
2572
2573int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002574Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002575{
2576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2577 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2578 (int)enable, (int)mode);
2579
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002580 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002581 switch (mode)
2582 {
2583 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002584 break;
2585 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002586 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002587 break;
2588 case kAgcFixedDigital:
2589 agcMode = GainControl::kFixedDigital;
2590 break;
2591 case kAgcAdaptiveDigital:
2592 agcMode =GainControl::kAdaptiveDigital;
2593 break;
2594 default:
2595 _engineStatisticsPtr->SetLastError(
2596 VE_INVALID_ARGUMENT, kTraceError,
2597 "SetRxAgcStatus() invalid Agc mode");
2598 return -1;
2599 }
2600
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002601 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002602 {
2603 _engineStatisticsPtr->SetLastError(
2604 VE_APM_ERROR, kTraceError,
2605 "SetRxAgcStatus() failed to set Agc mode");
2606 return -1;
2607 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002608 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002609 {
2610 _engineStatisticsPtr->SetLastError(
2611 VE_APM_ERROR, kTraceError,
2612 "SetRxAgcStatus() failed to set Agc state");
2613 return -1;
2614 }
2615
2616 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002617 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002618
2619 return 0;
2620}
2621
2622int
2623Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2624{
2625 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2626 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2627
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002628 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002629 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002630 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002631
2632 enabled = enable;
2633
2634 switch (agcMode)
2635 {
2636 case GainControl::kFixedDigital:
2637 mode = kAgcFixedDigital;
2638 break;
2639 case GainControl::kAdaptiveDigital:
2640 mode = kAgcAdaptiveDigital;
2641 break;
2642 default:
2643 _engineStatisticsPtr->SetLastError(
2644 VE_APM_ERROR, kTraceError,
2645 "GetRxAgcStatus() invalid Agc mode");
2646 return -1;
2647 }
2648
2649 return 0;
2650}
2651
2652int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002653Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002654{
2655 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2656 "Channel::SetRxAgcConfig()");
2657
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002658 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002659 config.targetLeveldBOv) != 0)
2660 {
2661 _engineStatisticsPtr->SetLastError(
2662 VE_APM_ERROR, kTraceError,
2663 "SetRxAgcConfig() failed to set target peak |level|"
2664 "(or envelope) of the Agc");
2665 return -1;
2666 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002667 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002668 config.digitalCompressionGaindB) != 0)
2669 {
2670 _engineStatisticsPtr->SetLastError(
2671 VE_APM_ERROR, kTraceError,
2672 "SetRxAgcConfig() failed to set the range in |gain| the"
2673 " digital compression stage may apply");
2674 return -1;
2675 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002676 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002677 config.limiterEnable) != 0)
2678 {
2679 _engineStatisticsPtr->SetLastError(
2680 VE_APM_ERROR, kTraceError,
2681 "SetRxAgcConfig() failed to set hard limiter to the signal");
2682 return -1;
2683 }
2684
2685 return 0;
2686}
2687
2688int
2689Channel::GetRxAgcConfig(AgcConfig& config)
2690{
2691 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2692 "Channel::GetRxAgcConfig(config=%?)");
2693
2694 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002695 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002696 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002697 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002698 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002699 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002700
2701 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2702 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2703 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2704 " limiterEnable=%d",
2705 config.targetLeveldBOv,
2706 config.digitalCompressionGaindB,
2707 config.limiterEnable);
2708
2709 return 0;
2710}
2711
2712#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2713
2714#ifdef WEBRTC_VOICE_ENGINE_NR
2715
2716int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002717Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002718{
2719 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2720 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2721 (int)enable, (int)mode);
2722
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002723 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002724 switch (mode)
2725 {
2726
2727 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 break;
2729 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002730 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002731 break;
2732 case kNsConference:
2733 nsLevel = NoiseSuppression::kHigh;
2734 break;
2735 case kNsLowSuppression:
2736 nsLevel = NoiseSuppression::kLow;
2737 break;
2738 case kNsModerateSuppression:
2739 nsLevel = NoiseSuppression::kModerate;
2740 break;
2741 case kNsHighSuppression:
2742 nsLevel = NoiseSuppression::kHigh;
2743 break;
2744 case kNsVeryHighSuppression:
2745 nsLevel = NoiseSuppression::kVeryHigh;
2746 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002747 }
2748
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002749 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002750 != 0)
2751 {
2752 _engineStatisticsPtr->SetLastError(
2753 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002754 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002755 return -1;
2756 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002757 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002758 {
2759 _engineStatisticsPtr->SetLastError(
2760 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002761 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 return -1;
2763 }
2764
2765 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002766 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002767
2768 return 0;
2769}
2770
2771int
2772Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2773{
2774 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2775 "Channel::GetRxNsStatus(enable=?, mode=?)");
2776
2777 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002778 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002779 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002780 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002781
2782 enabled = enable;
2783
2784 switch (ncLevel)
2785 {
2786 case NoiseSuppression::kLow:
2787 mode = kNsLowSuppression;
2788 break;
2789 case NoiseSuppression::kModerate:
2790 mode = kNsModerateSuppression;
2791 break;
2792 case NoiseSuppression::kHigh:
2793 mode = kNsHighSuppression;
2794 break;
2795 case NoiseSuppression::kVeryHigh:
2796 mode = kNsVeryHighSuppression;
2797 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002798 }
2799
2800 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2801 VoEId(_instanceId,_channelId),
2802 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2803 return 0;
2804}
2805
2806#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2807
2808int
niklase@google.com470e71d2011-07-07 08:21:25 +00002809Channel::SetLocalSSRC(unsigned int ssrc)
2810{
2811 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2812 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002813 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002814 {
2815 _engineStatisticsPtr->SetLastError(
2816 VE_ALREADY_SENDING, kTraceError,
2817 "SetLocalSSRC() already sending");
2818 return -1;
2819 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002820 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002821 return 0;
2822}
2823
2824int
2825Channel::GetLocalSSRC(unsigned int& ssrc)
2826{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002827 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002828 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2829 VoEId(_instanceId,_channelId),
2830 "GetLocalSSRC() => ssrc=%lu", ssrc);
2831 return 0;
2832}
2833
2834int
2835Channel::GetRemoteSSRC(unsigned int& ssrc)
2836{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002837 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002838 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2839 VoEId(_instanceId,_channelId),
2840 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2841 return 0;
2842}
2843
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002844int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002845 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002846 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002847}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002848
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002849int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2850 unsigned char id) {
2851 rtp_header_parser_->DeregisterRtpHeaderExtension(
2852 kRtpExtensionAudioLevel);
2853 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2854 kRtpExtensionAudioLevel, id)) {
2855 return -1;
2856 }
2857 return 0;
2858}
2859
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002860int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2861 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2862}
2863
2864int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2865 rtp_header_parser_->DeregisterRtpHeaderExtension(
2866 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002867 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2868 kRtpExtensionAbsoluteSendTime, id)) {
2869 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002870 }
2871 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002872}
2873
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002874void Channel::SetRTCPStatus(bool enable) {
2875 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2876 "Channel::SetRTCPStatus()");
2877 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002878}
2879
2880int
2881Channel::GetRTCPStatus(bool& enabled)
2882{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002883 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002884 enabled = (method != kRtcpOff);
2885 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2886 VoEId(_instanceId,_channelId),
2887 "GetRTCPStatus() => enabled=%d", enabled);
2888 return 0;
2889}
2890
2891int
2892Channel::SetRTCP_CNAME(const char cName[256])
2893{
2894 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2895 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002896 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002897 {
2898 _engineStatisticsPtr->SetLastError(
2899 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2900 "SetRTCP_CNAME() failed to set RTCP CNAME");
2901 return -1;
2902 }
2903 return 0;
2904}
2905
2906int
niklase@google.com470e71d2011-07-07 08:21:25 +00002907Channel::GetRemoteRTCP_CNAME(char cName[256])
2908{
2909 if (cName == NULL)
2910 {
2911 _engineStatisticsPtr->SetLastError(
2912 VE_INVALID_ARGUMENT, kTraceError,
2913 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2914 return -1;
2915 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002916 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002917 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002918 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002919 {
2920 _engineStatisticsPtr->SetLastError(
2921 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2922 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2923 return -1;
2924 }
2925 strcpy(cName, cname);
2926 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2927 VoEId(_instanceId, _channelId),
2928 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2929 return 0;
2930}
2931
2932int
2933Channel::GetRemoteRTCPData(
2934 unsigned int& NTPHigh,
2935 unsigned int& NTPLow,
2936 unsigned int& timestamp,
2937 unsigned int& playoutTimestamp,
2938 unsigned int* jitter,
2939 unsigned short* fractionLost)
2940{
2941 // --- Information from sender info in received Sender Reports
2942
2943 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002944 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002945 {
2946 _engineStatisticsPtr->SetLastError(
2947 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002948 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002949 "side");
2950 return -1;
2951 }
2952
2953 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2954 // and octet count)
2955 NTPHigh = senderInfo.NTPseconds;
2956 NTPLow = senderInfo.NTPfraction;
2957 timestamp = senderInfo.RTPtimeStamp;
2958
2959 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2960 VoEId(_instanceId, _channelId),
2961 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2962 "timestamp=%lu",
2963 NTPHigh, NTPLow, timestamp);
2964
2965 // --- Locally derived information
2966
2967 // This value is updated on each incoming RTCP packet (0 when no packet
2968 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002969 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002970
2971 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2972 VoEId(_instanceId, _channelId),
2973 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002974 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002975
2976 if (NULL != jitter || NULL != fractionLost)
2977 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002978 // Get all RTCP receiver report blocks that have been received on this
2979 // channel. If we receive RTP packets from a remote source we know the
2980 // remote SSRC and use the report block from him.
2981 // Otherwise use the first report block.
2982 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002983 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002984 remote_stats.empty()) {
2985 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2986 VoEId(_instanceId, _channelId),
2987 "GetRemoteRTCPData() failed to measure statistics due"
2988 " to lack of received RTP and/or RTCP packets");
2989 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002990 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002991
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002992 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002993 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2994 for (; it != remote_stats.end(); ++it) {
2995 if (it->remoteSSRC == remoteSSRC)
2996 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002997 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002998
2999 if (it == remote_stats.end()) {
3000 // If we have not received any RTCP packets from this SSRC it probably
3001 // means that we have not received any RTP packets.
3002 // Use the first received report block instead.
3003 it = remote_stats.begin();
3004 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003005 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003006
xians@webrtc.org79af7342012-01-31 12:22:14 +00003007 if (jitter) {
3008 *jitter = it->jitter;
3009 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3010 VoEId(_instanceId, _channelId),
3011 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3012 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003013
xians@webrtc.org79af7342012-01-31 12:22:14 +00003014 if (fractionLost) {
3015 *fractionLost = it->fractionLost;
3016 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3017 VoEId(_instanceId, _channelId),
3018 "GetRemoteRTCPData() => fractionLost = %lu",
3019 *fractionLost);
3020 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003021 }
3022 return 0;
3023}
3024
3025int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003026Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003027 unsigned int name,
3028 const char* data,
3029 unsigned short dataLengthInBytes)
3030{
3031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3032 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003033 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003034 {
3035 _engineStatisticsPtr->SetLastError(
3036 VE_NOT_SENDING, kTraceError,
3037 "SendApplicationDefinedRTCPPacket() not sending");
3038 return -1;
3039 }
3040 if (NULL == data)
3041 {
3042 _engineStatisticsPtr->SetLastError(
3043 VE_INVALID_ARGUMENT, kTraceError,
3044 "SendApplicationDefinedRTCPPacket() invalid data value");
3045 return -1;
3046 }
3047 if (dataLengthInBytes % 4 != 0)
3048 {
3049 _engineStatisticsPtr->SetLastError(
3050 VE_INVALID_ARGUMENT, kTraceError,
3051 "SendApplicationDefinedRTCPPacket() invalid length value");
3052 return -1;
3053 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003054 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003055 if (status == kRtcpOff)
3056 {
3057 _engineStatisticsPtr->SetLastError(
3058 VE_RTCP_ERROR, kTraceError,
3059 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3060 return -1;
3061 }
3062
3063 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003064 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003065 subType,
3066 name,
3067 (const unsigned char*) data,
3068 dataLengthInBytes) != 0)
3069 {
3070 _engineStatisticsPtr->SetLastError(
3071 VE_SEND_ERROR, kTraceError,
3072 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3073 return -1;
3074 }
3075 return 0;
3076}
3077
3078int
3079Channel::GetRTPStatistics(
3080 unsigned int& averageJitterMs,
3081 unsigned int& maxJitterMs,
3082 unsigned int& discardedPackets)
3083{
niklase@google.com470e71d2011-07-07 08:21:25 +00003084 // The jitter statistics is updated for each received RTP packet and is
3085 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003086 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3087 // If RTCP is off, there is no timed thread in the RTCP module regularly
3088 // generating new stats, trigger the update manually here instead.
3089 StreamStatistician* statistician =
3090 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3091 if (statistician) {
3092 // Don't use returned statistics, use data from proxy instead so that
3093 // max jitter can be fetched atomically.
3094 RtcpStatistics s;
3095 statistician->GetStatistics(&s, true);
3096 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003097 }
3098
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003099 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003100 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003101 if (playoutFrequency > 0) {
3102 // Scale RTP statistics given the current playout frequency
3103 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3104 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003105 }
3106
3107 discardedPackets = _numberOfDiscardedPackets;
3108
3109 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3110 VoEId(_instanceId, _channelId),
3111 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003112 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003113 averageJitterMs, maxJitterMs, discardedPackets);
3114 return 0;
3115}
3116
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003117int Channel::GetRemoteRTCPReportBlocks(
3118 std::vector<ReportBlock>* report_blocks) {
3119 if (report_blocks == NULL) {
3120 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3121 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3122 return -1;
3123 }
3124
3125 // Get the report blocks from the latest received RTCP Sender or Receiver
3126 // Report. Each element in the vector contains the sender's SSRC and a
3127 // report block according to RFC 3550.
3128 std::vector<RTCPReportBlock> rtcp_report_blocks;
3129 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3130 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3131 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3132 return -1;
3133 }
3134
3135 if (rtcp_report_blocks.empty())
3136 return 0;
3137
3138 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3139 for (; it != rtcp_report_blocks.end(); ++it) {
3140 ReportBlock report_block;
3141 report_block.sender_SSRC = it->remoteSSRC;
3142 report_block.source_SSRC = it->sourceSSRC;
3143 report_block.fraction_lost = it->fractionLost;
3144 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3145 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3146 report_block.interarrival_jitter = it->jitter;
3147 report_block.last_SR_timestamp = it->lastSR;
3148 report_block.delay_since_last_SR = it->delaySinceLastSR;
3149 report_blocks->push_back(report_block);
3150 }
3151 return 0;
3152}
3153
niklase@google.com470e71d2011-07-07 08:21:25 +00003154int
3155Channel::GetRTPStatistics(CallStatistics& stats)
3156{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003157 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003158
3159 // The jitter statistics is updated for each received RTP packet and is
3160 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003161 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003162 StreamStatistician* statistician =
3163 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3164 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003165 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3166 _engineStatisticsPtr->SetLastError(
3167 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3168 "GetRTPStatistics() failed to read RTP statistics from the "
3169 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003170 }
3171
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003172 stats.fractionLost = statistics.fraction_lost;
3173 stats.cumulativeLost = statistics.cumulative_lost;
3174 stats.extendedMax = statistics.extended_max_sequence_number;
3175 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003176
3177 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3178 VoEId(_instanceId, _channelId),
3179 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003180 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003181 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3182 stats.jitterSamples);
3183
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003184 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003185 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003186 if (stats.rttMs == 0) {
3187 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3188 "GetRTPStatistics() failed to get RTT");
3189 } else {
3190 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003191 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003192 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003193
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003194 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003195
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003196 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003197 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003198 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003199 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003200
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003201 if (statistician) {
3202 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3203 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003204
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003205 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003206 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003207 {
3208 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3209 VoEId(_instanceId, _channelId),
3210 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003211 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003212 }
3213
3214 stats.bytesSent = bytesSent;
3215 stats.packetsSent = packetsSent;
3216 stats.bytesReceived = bytesReceived;
3217 stats.packetsReceived = packetsReceived;
3218
3219 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3220 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003221 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3222 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003223 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3224 stats.packetsReceived);
3225
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003226 // --- Timestamps
3227 {
3228 CriticalSectionScoped lock(ts_stats_lock_.get());
3229 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3230 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003231 return 0;
3232}
3233
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003234int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003236 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003237
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003238 if (enable) {
3239 if (redPayloadtype < 0 || redPayloadtype > 127) {
3240 _engineStatisticsPtr->SetLastError(
3241 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003242 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003243 return -1;
3244 }
3245
3246 if (SetRedPayloadType(redPayloadtype) < 0) {
3247 _engineStatisticsPtr->SetLastError(
3248 VE_CODEC_ERROR, kTraceError,
3249 "SetSecondarySendCodec() Failed to register RED ACM");
3250 return -1;
3251 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003252 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003253
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003254 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003255 _engineStatisticsPtr->SetLastError(
3256 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003257 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003258 return -1;
3259 }
3260 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003261}
3262
3263int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003264Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003265{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003266 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003267 if (enabled)
3268 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003269 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003270 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003271 {
3272 _engineStatisticsPtr->SetLastError(
3273 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003274 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003275 "module");
3276 return -1;
3277 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003278 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003279 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3280 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003281 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003282 enabled, redPayloadtype);
3283 return 0;
3284 }
3285 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3286 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003287 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 return 0;
3289}
3290
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003291int Channel::SetCodecFECStatus(bool enable) {
3292 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3293 "Channel::SetCodecFECStatus()");
3294
3295 if (audio_coding_->SetCodecFEC(enable) != 0) {
3296 _engineStatisticsPtr->SetLastError(
3297 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3298 "SetCodecFECStatus() failed to set FEC state");
3299 return -1;
3300 }
3301 return 0;
3302}
3303
3304bool Channel::GetCodecFECStatus() {
3305 bool enabled = audio_coding_->CodecFEC();
3306 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3307 VoEId(_instanceId, _channelId),
3308 "GetCodecFECStatus() => enabled=%d", enabled);
3309 return enabled;
3310}
3311
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003312void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3313 // None of these functions can fail.
3314 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003315 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3316 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003317 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003318 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003319 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003320 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003321}
3322
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003323// Called when we are missing one or more packets.
3324int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003325 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3326}
3327
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003328uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003329Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003330{
3331 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003332 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003333 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003334 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003335 return 0;
3336}
3337
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003338void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003339 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003340 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003341 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003342 CodecInst codec;
3343 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003344
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003345 if (!mono_recording_audio_.get()) {
3346 // Temporary space for DownConvertToCodecFormat.
3347 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003348 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003349 DownConvertToCodecFormat(audio_data,
3350 number_of_frames,
3351 number_of_channels,
3352 sample_rate,
3353 codec.channels,
3354 codec.plfreq,
3355 mono_recording_audio_.get(),
3356 &input_resampler_,
3357 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003358}
3359
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003360uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003361Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003362{
3363 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3364 "Channel::PrepareEncodeAndSend()");
3365
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003366 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003367 {
3368 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3369 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003370 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003371 }
3372
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003373 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003374 {
3375 MixOrReplaceAudioWithFile(mixingFrequency);
3376 }
3377
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003378 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3379 if (is_muted) {
3380 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003381 }
3382
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003383 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003384 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003385 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003386 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003387 if (_inputExternalMediaCallbackPtr)
3388 {
3389 _inputExternalMediaCallbackPtr->Process(
3390 _channelId,
3391 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003392 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003393 _audioFrame.samples_per_channel_,
3394 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003395 isStereo);
3396 }
3397 }
3398
3399 InsertInbandDtmfTone();
3400
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003401 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003402 size_t length =
3403 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003404 if (is_muted) {
3405 rms_level_.ProcessMuted(length);
3406 } else {
3407 rms_level_.Process(_audioFrame.data_, length);
3408 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003409 }
3410
niklase@google.com470e71d2011-07-07 08:21:25 +00003411 return 0;
3412}
3413
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003414uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003415Channel::EncodeAndSend()
3416{
3417 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3418 "Channel::EncodeAndSend()");
3419
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003420 assert(_audioFrame.num_channels_ <= 2);
3421 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003422 {
3423 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3424 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003425 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003426 }
3427
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003428 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003429
3430 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3431
3432 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003433 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003434 // This call will trigger AudioPacketizationCallback::SendData if encoding
3435 // is done and payload is ready for packetization and transmission.
3436 // Otherwise, it will return without invoking the callback.
3437 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003438 {
3439 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3440 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003441 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003442 }
3443
Peter Kastingb7e50542015-06-11 12:55:50 -07003444 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003445 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003446}
3447
Minyue2013aec2015-05-13 14:14:42 +02003448void Channel::DisassociateSendChannel(int channel_id) {
3449 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3450 Channel* channel = associate_send_channel_.channel();
3451 if (channel && channel->ChannelId() == channel_id) {
3452 // If this channel is associated with a send channel of the specified
3453 // Channel ID, disassociate with it.
3454 ChannelOwner ref(NULL);
3455 associate_send_channel_ = ref;
3456 }
3457}
3458
niklase@google.com470e71d2011-07-07 08:21:25 +00003459int Channel::RegisterExternalMediaProcessing(
3460 ProcessingTypes type,
3461 VoEMediaProcess& processObject)
3462{
3463 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3464 "Channel::RegisterExternalMediaProcessing()");
3465
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003466 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003467
3468 if (kPlaybackPerChannel == type)
3469 {
3470 if (_outputExternalMediaCallbackPtr)
3471 {
3472 _engineStatisticsPtr->SetLastError(
3473 VE_INVALID_OPERATION, kTraceError,
3474 "Channel::RegisterExternalMediaProcessing() "
3475 "output external media already enabled");
3476 return -1;
3477 }
3478 _outputExternalMediaCallbackPtr = &processObject;
3479 _outputExternalMedia = true;
3480 }
3481 else if (kRecordingPerChannel == type)
3482 {
3483 if (_inputExternalMediaCallbackPtr)
3484 {
3485 _engineStatisticsPtr->SetLastError(
3486 VE_INVALID_OPERATION, kTraceError,
3487 "Channel::RegisterExternalMediaProcessing() "
3488 "output external media already enabled");
3489 return -1;
3490 }
3491 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003492 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003493 }
3494 return 0;
3495}
3496
3497int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3498{
3499 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3500 "Channel::DeRegisterExternalMediaProcessing()");
3501
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003502 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003503
3504 if (kPlaybackPerChannel == type)
3505 {
3506 if (!_outputExternalMediaCallbackPtr)
3507 {
3508 _engineStatisticsPtr->SetLastError(
3509 VE_INVALID_OPERATION, kTraceWarning,
3510 "Channel::DeRegisterExternalMediaProcessing() "
3511 "output external media already disabled");
3512 return 0;
3513 }
3514 _outputExternalMedia = false;
3515 _outputExternalMediaCallbackPtr = NULL;
3516 }
3517 else if (kRecordingPerChannel == type)
3518 {
3519 if (!_inputExternalMediaCallbackPtr)
3520 {
3521 _engineStatisticsPtr->SetLastError(
3522 VE_INVALID_OPERATION, kTraceWarning,
3523 "Channel::DeRegisterExternalMediaProcessing() "
3524 "input external media already disabled");
3525 return 0;
3526 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003527 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003528 _inputExternalMediaCallbackPtr = NULL;
3529 }
3530
3531 return 0;
3532}
3533
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003534int Channel::SetExternalMixing(bool enabled) {
3535 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3536 "Channel::SetExternalMixing(enabled=%d)", enabled);
3537
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003538 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003539 {
3540 _engineStatisticsPtr->SetLastError(
3541 VE_INVALID_OPERATION, kTraceError,
3542 "Channel::SetExternalMixing() "
3543 "external mixing cannot be changed while playing.");
3544 return -1;
3545 }
3546
3547 _externalMixing = enabled;
3548
3549 return 0;
3550}
3551
niklase@google.com470e71d2011-07-07 08:21:25 +00003552int
niklase@google.com470e71d2011-07-07 08:21:25 +00003553Channel::GetNetworkStatistics(NetworkStatistics& stats)
3554{
3555 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3556 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003557 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003558}
3559
wu@webrtc.org24301a62013-12-13 19:17:43 +00003560void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3561 audio_coding_->GetDecodingCallStatistics(stats);
3562}
3563
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003564bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3565 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003566 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003567 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003569 "Channel::GetDelayEstimate() no valid estimate.");
3570 return false;
3571 }
3572 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3573 _recPacketDelayMs;
3574 *playout_buffer_delay_ms = playout_delay_ms_;
3575 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3576 "Channel::GetDelayEstimate()");
3577 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003578}
3579
deadbeef74375882015-08-13 12:09:10 -07003580int Channel::LeastRequiredDelayMs() const {
3581 return audio_coding_->LeastRequiredDelayMs();
3582}
3583
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003584int Channel::SetInitialPlayoutDelay(int delay_ms)
3585{
3586 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3587 "Channel::SetInitialPlayoutDelay()");
3588 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3589 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3590 {
3591 _engineStatisticsPtr->SetLastError(
3592 VE_INVALID_ARGUMENT, kTraceError,
3593 "SetInitialPlayoutDelay() invalid min delay");
3594 return -1;
3595 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003596 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003597 {
3598 _engineStatisticsPtr->SetLastError(
3599 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3600 "SetInitialPlayoutDelay() failed to set min playout delay");
3601 return -1;
3602 }
3603 return 0;
3604}
3605
3606
niklase@google.com470e71d2011-07-07 08:21:25 +00003607int
3608Channel::SetMinimumPlayoutDelay(int delayMs)
3609{
3610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3611 "Channel::SetMinimumPlayoutDelay()");
3612 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3613 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3614 {
3615 _engineStatisticsPtr->SetLastError(
3616 VE_INVALID_ARGUMENT, kTraceError,
3617 "SetMinimumPlayoutDelay() invalid min delay");
3618 return -1;
3619 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003620 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003621 {
3622 _engineStatisticsPtr->SetLastError(
3623 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3624 "SetMinimumPlayoutDelay() failed to set min playout delay");
3625 return -1;
3626 }
3627 return 0;
3628}
3629
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003630int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3632 "Channel::GetPlayoutTimestamp()");
deadbeef74375882015-08-13 12:09:10 -07003633 uint32_t playout_timestamp_rtp = 0;
3634 {
3635 CriticalSectionScoped cs(video_sync_lock_.get());
3636 playout_timestamp_rtp = playout_timestamp_rtp_;
3637 }
3638 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003639 _engineStatisticsPtr->SetLastError(
3640 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3641 "GetPlayoutTimestamp() failed to retrieve timestamp");
3642 return -1;
3643 }
deadbeef74375882015-08-13 12:09:10 -07003644 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003645 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3646 VoEId(_instanceId,_channelId),
3647 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3648 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003649}
3650
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003651int Channel::SetInitTimestamp(unsigned int timestamp) {
3652 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003653 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003654 if (channel_state_.Get().sending) {
3655 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3656 "SetInitTimestamp() already sending");
3657 return -1;
3658 }
3659 _rtpRtcpModule->SetStartTimestamp(timestamp);
3660 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003661}
3662
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003663int Channel::SetInitSequenceNumber(short sequenceNumber) {
3664 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3665 "Channel::SetInitSequenceNumber()");
3666 if (channel_state_.Get().sending) {
3667 _engineStatisticsPtr->SetLastError(
3668 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3669 return -1;
3670 }
3671 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3672 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003673}
3674
3675int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003676Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003677{
3678 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3679 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003680 *rtpRtcpModule = _rtpRtcpModule.get();
3681 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003682 return 0;
3683}
3684
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003685// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3686// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003687int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003688Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003689{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003690 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003691 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003692
3693 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003694 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003695
3696 if (_inputFilePlayerPtr == NULL)
3697 {
3698 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3699 VoEId(_instanceId, _channelId),
3700 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3701 " doesnt exist");
3702 return -1;
3703 }
3704
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003705 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003706 fileSamples,
3707 mixingFrequency) == -1)
3708 {
3709 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3710 VoEId(_instanceId, _channelId),
3711 "Channel::MixOrReplaceAudioWithFile() file mixing "
3712 "failed");
3713 return -1;
3714 }
3715 if (fileSamples == 0)
3716 {
3717 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3718 VoEId(_instanceId, _channelId),
3719 "Channel::MixOrReplaceAudioWithFile() file is ended");
3720 return 0;
3721 }
3722 }
3723
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003724 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003725
3726 if (_mixFileWithMicrophone)
3727 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003728 // Currently file stream is always mono.
3729 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003730 MixWithSat(_audioFrame.data_,
3731 _audioFrame.num_channels_,
3732 fileBuffer.get(),
3733 1,
3734 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003735 }
3736 else
3737 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003738 // Replace ACM audio with file.
3739 // Currently file stream is always mono.
3740 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003741 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003742 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003743 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003744 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 mixingFrequency,
3746 AudioFrame::kNormalSpeech,
3747 AudioFrame::kVadUnknown,
3748 1);
3749
3750 }
3751 return 0;
3752}
3753
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003754int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003755Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003756 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003757{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003758 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003759
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003760 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003761 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003762
3763 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003764 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003765
3766 if (_outputFilePlayerPtr == NULL)
3767 {
3768 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3769 VoEId(_instanceId, _channelId),
3770 "Channel::MixAudioWithFile() file mixing failed");
3771 return -1;
3772 }
3773
3774 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003775 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 fileSamples,
3777 mixingFrequency) == -1)
3778 {
3779 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3780 VoEId(_instanceId, _channelId),
3781 "Channel::MixAudioWithFile() file mixing failed");
3782 return -1;
3783 }
3784 }
3785
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003786 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003787 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003788 // Currently file stream is always mono.
3789 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003790 MixWithSat(audioFrame.data_,
3791 audioFrame.num_channels_,
3792 fileBuffer.get(),
3793 1,
3794 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003795 }
3796 else
3797 {
3798 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003799 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3800 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003801 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003802 return -1;
3803 }
3804
3805 return 0;
3806}
3807
3808int
3809Channel::InsertInbandDtmfTone()
3810{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003811 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003812 if (_inbandDtmfQueue.PendingDtmf() &&
3813 !_inbandDtmfGenerator.IsAddingTone() &&
3814 _inbandDtmfGenerator.DelaySinceLastTone() >
3815 kMinTelephoneEventSeparationMs)
3816 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003817 int8_t eventCode(0);
3818 uint16_t lengthMs(0);
3819 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003820
3821 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3822 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3823 if (_playInbandDtmfEvent)
3824 {
3825 // Add tone to output mixer using a reduced length to minimize
3826 // risk of echo.
3827 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3828 attenuationDb);
3829 }
3830 }
3831
3832 if (_inbandDtmfGenerator.IsAddingTone())
3833 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003834 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003835 _inbandDtmfGenerator.GetSampleRate(frequency);
3836
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003837 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003838 {
3839 // Update sample rate of Dtmf tone since the mixing frequency
3840 // has changed.
3841 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003842 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003843 // Reset the tone to be added taking the new sample rate into
3844 // account.
3845 _inbandDtmfGenerator.ResetTone();
3846 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003847
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003848 int16_t toneBuffer[320];
3849 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003850 // Get 10ms tone segment and set time since last tone to zero
3851 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3852 {
3853 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3854 VoEId(_instanceId, _channelId),
3855 "Channel::EncodeAndSend() inserting Dtmf failed");
3856 return -1;
3857 }
3858
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003859 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003860 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003861 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003862 sample++)
3863 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003864 for (int channel = 0;
3865 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003866 channel++)
3867 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003868 const size_t index =
3869 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003870 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003871 }
3872 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003873
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003874 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003875 } else
3876 {
3877 // Add 10ms to "delay-since-last-tone" counter
3878 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3879 }
3880 return 0;
3881}
3882
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003883int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003884Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003885{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003886 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003887 if (_transportPtr == NULL)
3888 {
3889 return -1;
3890 }
3891 if (!RTCP)
3892 {
3893 return _transportPtr->SendPacket(_channelId, data, len);
3894 }
3895 else
3896 {
3897 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3898 }
3899}
3900
deadbeef74375882015-08-13 12:09:10 -07003901void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3902 uint32_t playout_timestamp = 0;
3903
3904 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3905 // This can happen if this channel has not been received any RTP packet. In
3906 // this case, NetEq is not capable of computing playout timestamp.
3907 return;
3908 }
3909
3910 uint16_t delay_ms = 0;
3911 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3912 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3913 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3914 " delay from the ADM");
3915 _engineStatisticsPtr->SetLastError(
3916 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3917 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3918 return;
3919 }
3920
3921 jitter_buffer_playout_timestamp_ = playout_timestamp;
3922
3923 // Remove the playout delay.
3924 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3925
3926 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3927 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3928 playout_timestamp);
3929
3930 {
3931 CriticalSectionScoped cs(video_sync_lock_.get());
3932 if (rtcp) {
3933 playout_timestamp_rtcp_ = playout_timestamp;
3934 } else {
3935 playout_timestamp_rtp_ = playout_timestamp;
3936 }
3937 playout_delay_ms_ = delay_ms;
3938 }
3939}
3940
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003941// Called for incoming RTP packets after successful RTP header parsing.
3942void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3943 uint16_t sequence_number) {
3944 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3945 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3946 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003947
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003948 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003949 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003950
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003951 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3952 // every incoming packet.
3953 uint32_t timestamp_diff_ms = (rtp_timestamp -
3954 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003955 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3956 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3957 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3958 // timestamp, the resulting difference is negative, but is set to zero.
3959 // This can happen when a network glitch causes a packet to arrive late,
3960 // and during long comfort noise periods with clock drift.
3961 timestamp_diff_ms = 0;
3962 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003963
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003964 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3965 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003966
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003967 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003968
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003969 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003970
deadbeef74375882015-08-13 12:09:10 -07003971 {
3972 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003973
deadbeef74375882015-08-13 12:09:10 -07003974 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3975 _recPacketDelayMs = packet_delay_ms;
3976 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003977
deadbeef74375882015-08-13 12:09:10 -07003978 if (_average_jitter_buffer_delay_us == 0) {
3979 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3980 return;
3981 }
3982
3983 // Filter average delay value using exponential filter (alpha is
3984 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3985 // risk of rounding error) and compensate for it in GetDelayEstimate()
3986 // later.
3987 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3988 1000 * timestamp_diff_ms + 500) / 8;
3989 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003990}
3991
3992void
3993Channel::RegisterReceiveCodecsToRTPModule()
3994{
3995 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3996 "Channel::RegisterReceiveCodecsToRTPModule()");
3997
3998
3999 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004000 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004001
4002 for (int idx = 0; idx < nSupportedCodecs; idx++)
4003 {
4004 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004005 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004006 (rtp_receiver_->RegisterReceivePayload(
4007 codec.plname,
4008 codec.pltype,
4009 codec.plfreq,
4010 codec.channels,
4011 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004012 {
4013 WEBRTC_TRACE(
4014 kTraceWarning,
4015 kTraceVoice,
4016 VoEId(_instanceId, _channelId),
4017 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4018 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4019 codec.plname, codec.pltype, codec.plfreq,
4020 codec.channels, codec.rate);
4021 }
4022 else
4023 {
4024 WEBRTC_TRACE(
4025 kTraceInfo,
4026 kTraceVoice,
4027 VoEId(_instanceId, _channelId),
4028 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004029 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004030 "receiver",
4031 codec.plname, codec.pltype, codec.plfreq,
4032 codec.channels, codec.rate);
4033 }
4034 }
4035}
4036
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004037// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004038int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004039 CodecInst codec;
4040 bool found_red = false;
4041
4042 // Get default RED settings from the ACM database
4043 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4044 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004045 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004046 if (!STR_CASE_CMP(codec.plname, "RED")) {
4047 found_red = true;
4048 break;
4049 }
4050 }
4051
4052 if (!found_red) {
4053 _engineStatisticsPtr->SetLastError(
4054 VE_CODEC_ERROR, kTraceError,
4055 "SetRedPayloadType() RED is not supported");
4056 return -1;
4057 }
4058
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004059 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004060 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004061 _engineStatisticsPtr->SetLastError(
4062 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4063 "SetRedPayloadType() RED registration in ACM module failed");
4064 return -1;
4065 }
4066
4067 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4068 _engineStatisticsPtr->SetLastError(
4069 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4070 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4071 return -1;
4072 }
4073 return 0;
4074}
4075
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004076int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4077 unsigned char id) {
4078 int error = 0;
4079 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4080 if (enable) {
4081 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4082 }
4083 return error;
4084}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004085
wu@webrtc.org94454b72014-06-05 20:34:08 +00004086int32_t Channel::GetPlayoutFrequency() {
4087 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4088 CodecInst current_recive_codec;
4089 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4090 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4091 // Even though the actual sampling rate for G.722 audio is
4092 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4093 // 8,000 Hz because that value was erroneously assigned in
4094 // RFC 1890 and must remain unchanged for backward compatibility.
4095 playout_frequency = 8000;
4096 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4097 // We are resampling Opus internally to 32,000 Hz until all our
4098 // DSP routines can operate at 48,000 Hz, but the RTP clock
4099 // rate for the Opus payload format is standardized to 48,000 Hz,
4100 // because that is the maximum supported decoding sampling rate.
4101 playout_frequency = 48000;
4102 }
4103 }
4104 return playout_frequency;
4105}
4106
Minyue2013aec2015-05-13 14:14:42 +02004107int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004108 RTCPMethod method = _rtpRtcpModule->RTCP();
4109 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004110 return 0;
4111 }
4112 std::vector<RTCPReportBlock> report_blocks;
4113 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004114
4115 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004116 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004117 if (allow_associate_channel) {
4118 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4119 Channel* channel = associate_send_channel_.channel();
4120 // Tries to get RTT from an associated channel. This is important for
4121 // receive-only channels.
4122 if (channel) {
4123 // To prevent infinite recursion and deadlock, calling GetRTT of
4124 // associate channel should always use "false" for argument:
4125 // |allow_associate_channel|.
4126 rtt = channel->GetRTT(false);
4127 }
4128 }
4129 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004130 }
4131
4132 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4133 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4134 for (; it != report_blocks.end(); ++it) {
4135 if (it->remoteSSRC == remoteSSRC)
4136 break;
4137 }
4138 if (it == report_blocks.end()) {
4139 // We have not received packets with SSRC matching the report blocks.
4140 // To calculate RTT we try with the SSRC of the first report block.
4141 // This is very important for send-only channels where we don't know
4142 // the SSRC of the other end.
4143 remoteSSRC = report_blocks[0].remoteSSRC;
4144 }
Minyue2013aec2015-05-13 14:14:42 +02004145
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004146 int64_t avg_rtt = 0;
4147 int64_t max_rtt= 0;
4148 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004149 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4150 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004151 return 0;
4152 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004153 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004154}
4155
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004156} // namespace voe
4157} // namespace webrtc