blob: 7f315dff75048e5f802efff69c185d788c330df1 [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
Ivo Creusenae856f22015-09-17 16:30:16 +020015#include "webrtc/base/checks.h"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000016#include "webrtc/base/format_macros.h"
wu@webrtc.org94454b72014-06-05 20:34:08 +000017#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000018#include "webrtc/common.h"
Henrik Lundin64dad832015-05-11 12:44:23 +020019#include "webrtc/config.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/audio_device/include/audio_device.h"
21#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000022#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000023#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
24#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
25#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
26#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000027#include "webrtc/modules/utility/interface/audio_frame_operations.h"
28#include "webrtc/modules/utility/interface/process_thread.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000029#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
30#include "webrtc/system_wrappers/interface/logging.h"
31#include "webrtc/system_wrappers/interface/trace.h"
32#include "webrtc/voice_engine/include/voe_base.h"
33#include "webrtc/voice_engine/include/voe_external_media.h"
34#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
35#include "webrtc/voice_engine/output_mixer.h"
36#include "webrtc/voice_engine/statistics.h"
37#include "webrtc/voice_engine/transmit_mixer.h"
38#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000039
40#if defined(_WIN32)
41#include <Qos.h>
42#endif
43
andrew@webrtc.org50419b02012-11-14 19:07:54 +000044namespace webrtc {
45namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000046
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000047// Extend the default RTCP statistics struct with max_jitter, defined as the
48// maximum jitter value seen in an RTCP report block.
49struct ChannelStatistics : public RtcpStatistics {
50 ChannelStatistics() : rtcp(), max_jitter(0) {}
51
52 RtcpStatistics rtcp;
53 uint32_t max_jitter;
54};
55
56// Statistics callback, called at each generation of a new RTCP report block.
57class StatisticsProxy : public RtcpStatisticsCallback {
58 public:
59 StatisticsProxy(uint32_t ssrc)
60 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
61 ssrc_(ssrc) {}
62 virtual ~StatisticsProxy() {}
63
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000064 void StatisticsUpdated(const RtcpStatistics& statistics,
65 uint32_t ssrc) override {
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000066 if (ssrc != ssrc_)
67 return;
68
69 CriticalSectionScoped cs(stats_lock_.get());
70 stats_.rtcp = statistics;
71 if (statistics.jitter > stats_.max_jitter) {
72 stats_.max_jitter = statistics.jitter;
73 }
74 }
75
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +000076 void CNameChanged(const char* cname, uint32_t ssrc) override {}
pbos@webrtc.orgce4e9a32014-12-18 13:50:16 +000077
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000078 ChannelStatistics GetStats() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 return stats_;
81 }
82
83 private:
84 // StatisticsUpdated calls are triggered from threads in the RTP module,
85 // while GetStats calls can be triggered from the public voice engine API,
86 // hence synchronization is needed.
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +000087 rtc::scoped_ptr<CriticalSectionWrapper> stats_lock_;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000088 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000092class VoERtcpObserver : public RtcpBandwidthObserver {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000093 public:
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000094 explicit VoERtcpObserver(Channel* owner) : owner_(owner) {}
95 virtual ~VoERtcpObserver() {}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000096
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +000097 void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
98 // Not used for Voice Engine.
99 }
100
kjellander@webrtc.org14665ff2015-03-04 12:58:35 +0000101 void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
102 int64_t rtt,
103 int64_t now_ms) override {
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000104 // TODO(mflodman): Do we need to aggregate reports here or can we jut send
105 // what we get? I.e. do we ever get multiple reports bundled into one RTCP
106 // report for VoiceEngine?
107 if (report_blocks.empty())
108 return;
109
110 int fraction_lost_aggregate = 0;
111 int total_number_of_packets = 0;
112
113 // If receiving multiple report blocks, calculate the weighted average based
114 // on the number of packets a report refers to.
115 for (ReportBlockList::const_iterator block_it = report_blocks.begin();
116 block_it != report_blocks.end(); ++block_it) {
117 // Find the previous extended high sequence number for this remote SSRC,
118 // to calculate the number of RTP packets this report refers to. Ignore if
119 // we haven't seen this SSRC before.
120 std::map<uint32_t, uint32_t>::iterator seq_num_it =
121 extended_max_sequence_number_.find(block_it->sourceSSRC);
122 int number_of_packets = 0;
123 if (seq_num_it != extended_max_sequence_number_.end()) {
124 number_of_packets = block_it->extendedHighSeqNum - seq_num_it->second;
125 }
126 fraction_lost_aggregate += number_of_packets * block_it->fractionLost;
127 total_number_of_packets += number_of_packets;
128
129 extended_max_sequence_number_[block_it->sourceSSRC] =
130 block_it->extendedHighSeqNum;
131 }
132 int weighted_fraction_lost = 0;
133 if (total_number_of_packets > 0) {
134 weighted_fraction_lost = (fraction_lost_aggregate +
135 total_number_of_packets / 2) / total_number_of_packets;
136 }
137 owner_->OnIncomingFractionLoss(weighted_fraction_lost);
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000138 }
139
140 private:
141 Channel* owner_;
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000142 // Maps remote side ssrc to extended highest sequence number received.
143 std::map<uint32_t, uint32_t> extended_max_sequence_number_;
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000144};
145
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000146int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000147Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000148 uint8_t payloadType,
149 uint32_t timeStamp,
150 const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000151 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 const RTPFragmentationHeader* fragmentation)
153{
154 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
155 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000156 " payloadSize=%" PRIuS ", fragmentation=0x%x)",
157 frameType, payloadType, timeStamp,
158 payloadSize, fragmentation);
niklase@google.com470e71d2011-07-07 08:21:25 +0000159
160 if (_includeAudioLevelIndication)
161 {
162 // Store current audio level in the RTP/RTCP module.
163 // The level will be used in combination with voice-activity state
164 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000165 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 }
167
168 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
169 // packetization.
170 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000171 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000172 payloadType,
173 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000174 // Leaving the time when this frame was
175 // received from the capture device as
176 // undefined for voice for now.
177 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000178 payloadData,
179 payloadSize,
180 fragmentation) == -1)
181 {
182 _engineStatisticsPtr->SetLastError(
183 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
184 "Channel::SendData() failed to send data to RTP/RTCP module");
185 return -1;
186 }
187
188 _lastLocalTimeStamp = timeStamp;
189 _lastPayloadType = payloadType;
190
191 return 0;
192}
193
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000194int32_t
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000195Channel::InFrameType(FrameType frame_type)
niklase@google.com470e71d2011-07-07 08:21:25 +0000196{
197 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000198 "Channel::InFrameType(frame_type=%d)", frame_type);
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000200 CriticalSectionScoped cs(&_callbackCritSect);
henrik.lundin@webrtc.orge9217b42015-03-06 07:50:34 +0000201 _sendFrameType = (frame_type == kAudioFrameSpeech);
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 return 0;
203}
204
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000205int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000206Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000207{
208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
209 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
210
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000211 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000212 if (_rxVadObserverPtr)
213 {
214 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
215 }
216
217 return 0;
218}
219
220int
Peter Boströmac547a62015-09-17 23:03:57 +0200221Channel::SendPacket(const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000222{
niklase@google.com470e71d2011-07-07 08:21:25 +0000223 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200224 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000225
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000226 CriticalSectionScoped cs(&_callbackCritSect);
227
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 if (_transportPtr == NULL)
229 {
230 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
231 "Channel::SendPacket() failed to send RTP packet due to"
232 " invalid transport object");
233 return -1;
234 }
235
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000236 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000237 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000238
Peter Boströmac547a62015-09-17 23:03:57 +0200239 int n = _transportPtr->SendPacket(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000240 if (n < 0) {
241 std::string transport_name =
242 _externalTransport ? "external transport" : "WebRtc sockets";
243 WEBRTC_TRACE(kTraceError, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendPacket() RTP transmission using %s failed",
246 transport_name.c_str());
247 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000249 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250}
251
252int
Peter Boströmac547a62015-09-17 23:03:57 +0200253Channel::SendRTCPPacket(const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000254{
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200256 "Channel::SendRTCPPacket(len=%" PRIuS ")", len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 CriticalSectionScoped cs(&_callbackCritSect);
259 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000261 WEBRTC_TRACE(kTraceError, kTraceVoice,
262 VoEId(_instanceId,_channelId),
263 "Channel::SendRTCPPacket() failed to send RTCP packet"
264 " due to invalid transport object");
265 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266 }
267
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000268 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000269 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000270
Peter Boströmac547a62015-09-17 23:03:57 +0200271 int n = _transportPtr->SendRTCPPacket(bufferToSendPtr, bufferLength);
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000272 if (n < 0) {
273 std::string transport_name =
274 _externalTransport ? "external transport" : "WebRtc sockets";
275 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
276 VoEId(_instanceId,_channelId),
277 "Channel::SendRTCPPacket() transmission using %s failed",
278 transport_name.c_str());
279 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000280 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000281 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000282}
283
Peter Boströmac547a62015-09-17 23:03:57 +0200284void Channel::OnPlayTelephoneEvent(uint8_t event,
285 uint16_t lengthMs,
286 uint8_t volume) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200288 "Channel::OnPlayTelephoneEvent(event=%u, lengthMs=%u,"
289 " volume=%u)", event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
291 if (!_playOutbandDtmfEvent || (event > 15))
292 {
293 // Ignore callback since feedback is disabled or event is not a
294 // Dtmf tone event.
295 return;
296 }
297
298 assert(_outputMixerPtr != NULL);
299
300 // Start playing out the Dtmf tone (if playout is enabled).
301 // Reduce length of tone with 80ms to the reduce risk of echo.
302 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
303}
304
305void
Peter Boströmac547a62015-09-17 23:03:57 +0200306Channel::OnIncomingSSRCChanged(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000307{
308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200309 "Channel::OnIncomingSSRCChanged(SSRC=%d)", ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000311 // Update ssrc so that NTP for AV sync can be updated.
312 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000313}
314
Peter Boströmac547a62015-09-17 23:03:57 +0200315void Channel::OnIncomingCSRCChanged(uint32_t CSRC, bool added) {
316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
317 "Channel::OnIncomingCSRCChanged(CSRC=%d, added=%d)", CSRC,
318 added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000319}
320
Peter Boströmac547a62015-09-17 23:03:57 +0200321int32_t Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000322 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000323 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000324 int frequency,
325 uint8_t channels,
Peter Boströmac547a62015-09-17 23:03:57 +0200326 uint32_t rate) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000327 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Boströmac547a62015-09-17 23:03:57 +0200328 "Channel::OnInitializeDecoder(payloadType=%d, "
niklase@google.com470e71d2011-07-07 08:21:25 +0000329 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
Peter Boströmac547a62015-09-17 23:03:57 +0200330 payloadType, payloadName, frequency, channels, rate);
niklase@google.com470e71d2011-07-07 08:21:25 +0000331
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000332 CodecInst receiveCodec = {0};
333 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000334
335 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000336 receiveCodec.plfreq = frequency;
337 receiveCodec.channels = channels;
338 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000339 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000340
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000341 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000342 receiveCodec.pacsize = dummyCodec.pacsize;
343
344 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000345 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000346 {
347 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000348 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000349 "Channel::OnInitializeDecoder() invalid codec ("
350 "pt=%d, name=%s) received - 1", payloadType, payloadName);
351 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
352 return -1;
353 }
354
355 return 0;
356}
357
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000358int32_t
359Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000360 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000361 const WebRtcRTPHeader* rtpHeader)
362{
363 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000364 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 " payloadType=%u, audioChannel=%u)",
366 payloadSize,
367 rtpHeader->header.payloadType,
368 rtpHeader->type.Audio.channel);
369
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000370 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000371 {
372 // Avoid inserting into NetEQ when we are not playing. Count the
373 // packet as discarded.
374 WEBRTC_TRACE(kTraceStream, kTraceVoice,
375 VoEId(_instanceId, _channelId),
376 "received packet is discarded since playing is not"
377 " activated");
378 _numberOfDiscardedPackets++;
379 return 0;
380 }
381
382 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000383 if (audio_coding_->IncomingPacket(payloadData,
384 payloadSize,
385 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 {
387 _engineStatisticsPtr->SetLastError(
388 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
389 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
390 return -1;
391 }
392
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000393 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 UpdatePacketDelay(rtpHeader->header.timestamp,
395 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000396
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000397 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000398 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
399 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000400
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000401 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000402 round_trip_time);
403 if (!nack_list.empty()) {
404 // Can't use nack_list.data() since it's not supported by all
405 // compilers.
406 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000407 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 return 0;
409}
410
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000411bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000412 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000413 RTPHeader header;
414 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
415 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
416 "IncomingPacket invalid RTP header");
417 return false;
418 }
419 header.payload_type_frequency =
420 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
421 if (header.payload_type_frequency < 0)
422 return false;
423 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
424}
425
minyuel0f4b3732015-08-31 16:04:32 +0200426int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000427{
428 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
429 "Channel::GetAudioFrame(id=%d)", id);
430
Ivo Creusenae856f22015-09-17 16:30:16 +0200431 if (event_log_) {
432 unsigned int ssrc;
433 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
434 event_log_->LogAudioPlayout(ssrc);
435 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000436 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200437 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
438 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 {
440 WEBRTC_TRACE(kTraceError, kTraceVoice,
441 VoEId(_instanceId,_channelId),
442 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000443 // In all likelihood, the audio in this frame is garbage. We return an
444 // error so that the audio mixer module doesn't add it to the mix. As
445 // a result, it won't be played out and the actions skipped here are
446 // irrelevant.
447 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 }
449
450 if (_RxVadDetection)
451 {
minyuel0f4b3732015-08-31 16:04:32 +0200452 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 }
454
455 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200456 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200458 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000459
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000460 ChannelState::State state = channel_state_.Get();
461
462 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200463 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000464 if (err) {
465 LOG(LS_ERROR) << "ProcessStream() error: " << err;
466 assert(false);
467 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 }
469
wu@webrtc.org63420662013-10-17 18:28:55 +0000470 float output_gain = 1.0f;
471 float left_pan = 1.0f;
472 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000473 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000474 CriticalSectionScoped cs(&volume_settings_critsect_);
475 output_gain = _outputGain;
476 left_pan = _panLeft;
477 right_pan= _panRight;
478 }
479
480 // Output volume scaling
481 if (output_gain < 0.99f || output_gain > 1.01f)
482 {
minyuel0f4b3732015-08-31 16:04:32 +0200483 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000484 }
485
486 // Scale left and/or right channel(s) if stereo and master balance is
487 // active
488
wu@webrtc.org63420662013-10-17 18:28:55 +0000489 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000490 {
minyuel0f4b3732015-08-31 16:04:32 +0200491 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 {
493 // Emulate stereo mode since panning is active.
494 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200495 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 }
497 // For true stereo mode (when we are receiving a stereo signal), no
498 // action is needed.
499
500 // Do the panning operation (the audio frame contains stereo at this
501 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200502 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 }
504
505 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000506 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 {
minyuel0f4b3732015-08-31 16:04:32 +0200508 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 }
510
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 // External media
512 if (_outputExternalMedia)
513 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000514 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200515 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000516 if (_outputExternalMediaCallbackPtr)
517 {
518 _outputExternalMediaCallbackPtr->Process(
519 _channelId,
520 kPlaybackPerChannel,
minyuel0f4b3732015-08-31 16:04:32 +0200521 (int16_t*)audioFrame->data_,
522 audioFrame->samples_per_channel_,
523 audioFrame->sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000524 isStereo);
525 }
526 }
527
528 // Record playout if enabled
529 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000530 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000531
532 if (_outputFileRecording && _outputFileRecorderPtr)
533 {
minyuel0f4b3732015-08-31 16:04:32 +0200534 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000535 }
536 }
537
538 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200539 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000540
minyuel0f4b3732015-08-31 16:04:32 +0200541 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000542 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200543 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000544 }
545
546 if (capture_start_rtp_time_stamp_ >= 0) {
547 // audioFrame.timestamp_ should be valid from now on.
548
549 // Compute elapsed time.
550 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200551 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
552 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000553 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
554 (GetPlayoutFrequency() / 1000);
555
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000556 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000557 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000558 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200559 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
560 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000561 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200562 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000563 // Compute |capture_start_ntp_time_ms_| so that
564 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
565 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200566 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000567 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000568 }
569 }
570
niklase@google.com470e71d2011-07-07 08:21:25 +0000571 return 0;
572}
573
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000574int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200575Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000576{
577 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
578 "Channel::NeededFrequency(id=%d)", id);
579
580 int highestNeeded = 0;
581
582 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000583 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
585 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000586 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000588 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 }
590 else
591 {
592 highestNeeded = receiveFrequency;
593 }
594
595 // Special case, if we're playing a file on the playout side
596 // we take that frequency into consideration as well
597 // This is not needed on sending side, since the codec will
598 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000599 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000601 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000602 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 {
604 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
605 {
606 highestNeeded=_outputFilePlayerPtr->Frequency();
607 }
608 }
609 }
610
611 return(highestNeeded);
612}
613
ivocb04965c2015-09-09 00:09:43 -0700614int32_t Channel::CreateChannel(Channel*& channel,
615 int32_t channelId,
616 uint32_t instanceId,
617 RtcEventLog* const event_log,
618 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
620 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
621 channelId, instanceId);
622
ivocb04965c2015-09-09 00:09:43 -0700623 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000624 if (channel == NULL)
625 {
626 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
627 VoEId(instanceId,channelId),
628 "Channel::CreateChannel() unable to allocate memory for"
629 " channel");
630 return -1;
631 }
632 return 0;
633}
634
635void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000636Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000637{
638 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
639 "Channel::PlayNotification(id=%d, durationMs=%d)",
640 id, durationMs);
641
642 // Not implement yet
643}
644
645void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000646Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647{
648 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
649 "Channel::RecordNotification(id=%d, durationMs=%d)",
650 id, durationMs);
651
652 // Not implement yet
653}
654
655void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000656Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000657{
658 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
659 "Channel::PlayFileEnded(id=%d)", id);
660
661 if (id == _inputFilePlayerId)
662 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000663 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
665 VoEId(_instanceId,_channelId),
666 "Channel::PlayFileEnded() => input file player module is"
667 " shutdown");
668 }
669 else if (id == _outputFilePlayerId)
670 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000671 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000672 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
673 VoEId(_instanceId,_channelId),
674 "Channel::PlayFileEnded() => output file player module is"
675 " shutdown");
676 }
677}
678
679void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000680Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000681{
682 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
683 "Channel::RecordFileEnded(id=%d)", id);
684
685 assert(id == _outputFileRecorderId);
686
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000687 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000688
689 _outputFileRecording = false;
690 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
691 VoEId(_instanceId,_channelId),
692 "Channel::RecordFileEnded() => output file recorder module is"
693 " shutdown");
694}
695
pbos@webrtc.org92135212013-05-14 08:31:39 +0000696Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000697 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700698 RtcEventLog* const event_log,
699 const Config& config)
700 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000701 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000702 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000703 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000704 _channelId(channelId),
Ivo Creusenae856f22015-09-17 16:30:16 +0200705 event_log_(event_log),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000706 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000707 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000708 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
ivocb04965c2015-09-09 00:09:43 -0700709 rtp_receive_statistics_(
710 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
711 rtp_receiver_(
Peter Boströmac547a62015-09-17 23:03:57 +0200712 RtpReceiver::CreateAudioReceiver(Clock::GetRealTimeClock(),
ivocb04965c2015-09-09 00:09:43 -0700713 this,
714 this,
715 this,
716 rtp_payload_registry_.get())),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000717 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000719 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 _inputFilePlayerPtr(NULL),
721 _outputFilePlayerPtr(NULL),
722 _outputFileRecorderPtr(NULL),
723 // Avoid conflict with other channels by adding 1024 - 1026,
724 // won't use as much as 1024 channels.
725 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
726 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
727 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000728 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000729 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
730 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000731 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 _inputExternalMediaCallbackPtr(NULL),
733 _outputExternalMediaCallbackPtr(NULL),
ivocb04965c2015-09-09 00:09:43 -0700734 _timeStamp(0), // This is just an offset, RTP module will add it's own
735 // random offset
xians@google.com22963ab2011-08-03 12:40:23 +0000736 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000737 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000738 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000739 playout_timestamp_rtp_(0),
740 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000741 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000742 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000743 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000744 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000745 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
746 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000747 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000748 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000749 _outputMixerPtr(NULL),
750 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000751 _moduleProcessThreadPtr(NULL),
752 _audioDeviceModulePtr(NULL),
753 _voiceEngineObserverPtr(NULL),
754 _callbackCritSectPtr(NULL),
755 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000756 _rxVadObserverPtr(NULL),
757 _oldVadDecision(-1),
758 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000759 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000760 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 _mute(false),
762 _panLeft(1.0f),
763 _panRight(1.0f),
764 _outputGain(1.0f),
765 _playOutbandDtmfEvent(false),
766 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000767 _lastLocalTimeStamp(0),
768 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000769 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 _outputSpeechType(AudioFrame::kNormalSpeech),
deadbeef74375882015-08-13 12:09:10 -0700771 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000772 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000773 _previousTimestamp(0),
774 _recPacketDelayMs(20),
775 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000776 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000777 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000778 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000779 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200780 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
781 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
ivocb04965c2015-09-09 00:09:43 -0700782 associate_send_channel_(ChannelOwner(nullptr)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
784 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200785 AudioCodingModule::Config acm_config;
786 acm_config.id = VoEModuleId(instanceId, channelId);
787 if (config.Get<NetEqCapacityConfig>().enabled) {
788 // Clamping the buffer capacity at 20 packets. While going lower will
789 // probably work, it makes little sense.
790 acm_config.neteq_config.max_packets_in_buffer =
791 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
792 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200793 acm_config.neteq_config.enable_fast_accelerate =
794 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200795 audio_coding_.reset(AudioCodingModule::Create(acm_config));
796
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 _inbandDtmfQueue.ResetDtmf();
798 _inbandDtmfGenerator.Init();
799 _outputAudioLevel.Clear();
800
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000801 RtpRtcp::Configuration configuration;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000802 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000803 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000804 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000805 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000806 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000807
808 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000809
810 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
811 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
812 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000813
814 Config audioproc_config;
815 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
816 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000817}
818
819Channel::~Channel()
820{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000821 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000822 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
823 "Channel::~Channel() - dtor");
824
825 if (_outputExternalMedia)
826 {
827 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
828 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000829 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000830 {
831 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
832 }
833 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000834 StopPlayout();
835
836 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000837 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000838 if (_inputFilePlayerPtr)
839 {
840 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
841 _inputFilePlayerPtr->StopPlayingFile();
842 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
843 _inputFilePlayerPtr = NULL;
844 }
845 if (_outputFilePlayerPtr)
846 {
847 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
848 _outputFilePlayerPtr->StopPlayingFile();
849 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
850 _outputFilePlayerPtr = NULL;
851 }
852 if (_outputFileRecorderPtr)
853 {
854 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
855 _outputFileRecorderPtr->StopRecording();
856 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
857 _outputFileRecorderPtr = NULL;
858 }
859 }
860
861 // The order to safely shutdown modules in a channel is:
862 // 1. De-register callbacks in modules
863 // 2. De-register modules in process thread
864 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000865 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 {
867 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
868 VoEId(_instanceId,_channelId),
869 "~Channel() failed to de-register transport callback"
870 " (Audio coding module)");
871 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000872 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 {
874 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
875 VoEId(_instanceId,_channelId),
876 "~Channel() failed to de-register VAD callback"
877 " (Audio coding module)");
878 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000880 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
881
niklase@google.com470e71d2011-07-07 08:21:25 +0000882 // End of modules shutdown
883
884 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000887 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000888}
889
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000890int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000891Channel::Init()
892{
893 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
894 "Channel::Init()");
895
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000896 channel_state_.Reset();
897
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 // --- Initial sanity
899
900 if ((_engineStatisticsPtr == NULL) ||
901 (_moduleProcessThreadPtr == NULL))
902 {
903 WEBRTC_TRACE(kTraceError, kTraceVoice,
904 VoEId(_instanceId,_channelId),
905 "Channel::Init() must call SetEngineInformation() first");
906 return -1;
907 }
908
909 // --- Add modules to process thread (for periodic schedulation)
910
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000911 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
912
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000913 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000914
Henrik Lundin45c64492015-03-30 19:00:44 +0200915 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 // out-of-band Dtmf tones are played out by default
kwiberg1f9baab2015-09-16 19:29:43 -0700917 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _engineStatisticsPtr->SetLastError(
919 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
920 "Channel::Init() unable to initialize the ACM - 1");
921 return -1;
922 }
923
924 // --- RTP/RTCP module initialization
925
926 // Ensure that RTCP is enabled by default for the created channel.
927 // Note that, the module will keep generating RTCP until it is explicitly
928 // disabled by the user.
929 // After StopListen (when no sockets exists), RTCP packets will no longer
930 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000931 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
932 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000933 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
934 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000936 (audio_coding_->RegisterTransportCallback(this) == -1) ||
937 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000938
939 if (fail)
940 {
941 _engineStatisticsPtr->SetLastError(
942 VE_CANNOT_INIT_CHANNEL, kTraceError,
943 "Channel::Init() callbacks not registered");
944 return -1;
945 }
946
947 // --- Register all supported codecs to the receiving side of the
948 // RTP/RTCP module
949
950 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000951 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000952
953 for (int idx = 0; idx < nSupportedCodecs; idx++)
954 {
955 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000956 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000957 (rtp_receiver_->RegisterReceivePayload(
958 codec.plname,
959 codec.pltype,
960 codec.plfreq,
961 codec.channels,
962 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000963 {
964 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
965 VoEId(_instanceId,_channelId),
966 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
967 "to RTP/RTCP receiver",
968 codec.plname, codec.pltype, codec.plfreq,
969 codec.channels, codec.rate);
970 }
971 else
972 {
973 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
974 VoEId(_instanceId,_channelId),
975 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
976 "the RTP/RTCP receiver",
977 codec.plname, codec.pltype, codec.plfreq,
978 codec.channels, codec.rate);
979 }
980
981 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +0000982 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 {
984 SetSendCodec(codec);
985 }
986
987 // Register default PT for outband 'telephone-event'
988 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
989 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000990 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000991 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
993 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
994 VoEId(_instanceId,_channelId),
995 "Channel::Init() failed to register outband "
996 "'telephone-event' (%d/%d) correctly",
997 codec.pltype, codec.plfreq);
998 }
999 }
1000
1001 if (!STR_CASE_CMP(codec.plname, "CN"))
1002 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001003 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1004 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001005 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 {
1007 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1008 VoEId(_instanceId,_channelId),
1009 "Channel::Init() failed to register CN (%d/%d) "
1010 "correctly - 1",
1011 codec.pltype, codec.plfreq);
1012 }
1013 }
1014#ifdef WEBRTC_CODEC_RED
1015 // Register RED to the receiving side of the ACM.
1016 // We will not receive an OnInitializeDecoder() callback for RED.
1017 if (!STR_CASE_CMP(codec.plname, "RED"))
1018 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001019 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001020 {
1021 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1022 VoEId(_instanceId,_channelId),
1023 "Channel::Init() failed to register RED (%d/%d) "
1024 "correctly",
1025 codec.pltype, codec.plfreq);
1026 }
1027 }
1028#endif
1029 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001030
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001031 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1032 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1033 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001035 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1036 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1037 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 }
1039
1040 return 0;
1041}
1042
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001043int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001044Channel::SetEngineInformation(Statistics& engineStatistics,
1045 OutputMixer& outputMixer,
1046 voe::TransmitMixer& transmitMixer,
1047 ProcessThread& moduleProcessThread,
1048 AudioDeviceModule& audioDeviceModule,
1049 VoiceEngineObserver* voiceEngineObserver,
1050 CriticalSectionWrapper* callbackCritSect)
1051{
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1053 "Channel::SetEngineInformation()");
1054 _engineStatisticsPtr = &engineStatistics;
1055 _outputMixerPtr = &outputMixer;
1056 _transmitMixerPtr = &transmitMixer,
1057 _moduleProcessThreadPtr = &moduleProcessThread;
1058 _audioDeviceModulePtr = &audioDeviceModule;
1059 _voiceEngineObserverPtr = voiceEngineObserver;
1060 _callbackCritSectPtr = callbackCritSect;
1061 return 0;
1062}
1063
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001064int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001065Channel::UpdateLocalTimeStamp()
1066{
1067
Peter Kastingb7e50542015-06-11 12:55:50 -07001068 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 return 0;
1070}
1071
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001072int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001073Channel::StartPlayout()
1074{
1075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1076 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001077 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001078 {
1079 return 0;
1080 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001081
1082 if (!_externalMixing) {
1083 // Add participant as candidates for mixing.
1084 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1085 {
1086 _engineStatisticsPtr->SetLastError(
1087 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1088 "StartPlayout() failed to add participant to mixer");
1089 return -1;
1090 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 }
1092
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001093 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001094 if (RegisterFilePlayingToMixer() != 0)
1095 return -1;
1096
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 return 0;
1098}
1099
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001100int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001101Channel::StopPlayout()
1102{
1103 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1104 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001105 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 {
1107 return 0;
1108 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001109
1110 if (!_externalMixing) {
1111 // Remove participant as candidates for mixing
1112 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1113 {
1114 _engineStatisticsPtr->SetLastError(
1115 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1116 "StopPlayout() failed to remove participant from mixer");
1117 return -1;
1118 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001119 }
1120
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001121 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 _outputAudioLevel.Clear();
1123
1124 return 0;
1125}
1126
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001127int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001128Channel::StartSend()
1129{
1130 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1131 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001132 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001133 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001134 if (send_sequence_number_)
1135 SetInitSequenceNumber(send_sequence_number_);
1136
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001137 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001139 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001141 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001142
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001143 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 {
1145 _engineStatisticsPtr->SetLastError(
1146 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1147 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001148 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001149 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 return -1;
1151 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001152
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 return 0;
1154}
1155
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001156int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001157Channel::StopSend()
1158{
1159 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1160 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001161 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001163 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001164 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001165 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001166
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001167 // Store the sequence number to be able to pick up the same sequence for
1168 // the next StartSend(). This is needed for restarting device, otherwise
1169 // it might cause libSRTP to complain about packets being replayed.
1170 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1171 // CL is landed. See issue
1172 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1173 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1174
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 // Reset sending SSRC and sequence number and triggers direct transmission
1176 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001177 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 {
1179 _engineStatisticsPtr->SetLastError(
1180 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1181 "StartSend() RTP/RTCP failed to stop sending");
1182 }
1183
niklase@google.com470e71d2011-07-07 08:21:25 +00001184 return 0;
1185}
1186
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001187int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001188Channel::StartReceiving()
1189{
1190 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1191 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001192 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 {
1194 return 0;
1195 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001196 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001197 _numberOfDiscardedPackets = 0;
1198 return 0;
1199}
1200
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001201int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001202Channel::StopReceiving()
1203{
1204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1205 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001206 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001207 {
1208 return 0;
1209 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001210
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001211 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 return 0;
1213}
1214
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001215int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001216Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1217{
1218 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1219 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001220 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001221
1222 if (_voiceEngineObserverPtr)
1223 {
1224 _engineStatisticsPtr->SetLastError(
1225 VE_INVALID_OPERATION, kTraceError,
1226 "RegisterVoiceEngineObserver() observer already enabled");
1227 return -1;
1228 }
1229 _voiceEngineObserverPtr = &observer;
1230 return 0;
1231}
1232
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001233int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001234Channel::DeRegisterVoiceEngineObserver()
1235{
1236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1237 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001238 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001239
1240 if (!_voiceEngineObserverPtr)
1241 {
1242 _engineStatisticsPtr->SetLastError(
1243 VE_INVALID_OPERATION, kTraceWarning,
1244 "DeRegisterVoiceEngineObserver() observer already disabled");
1245 return 0;
1246 }
1247 _voiceEngineObserverPtr = NULL;
1248 return 0;
1249}
1250
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001251int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001252Channel::GetSendCodec(CodecInst& codec)
1253{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001254 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001255}
1256
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001257int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001258Channel::GetRecCodec(CodecInst& codec)
1259{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001260 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001261}
1262
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001263int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001264Channel::SetSendCodec(const CodecInst& codec)
1265{
1266 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1267 "Channel::SetSendCodec()");
1268
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001269 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001270 {
1271 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1272 "SetSendCodec() failed to register codec to ACM");
1273 return -1;
1274 }
1275
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001276 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001278 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1279 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 {
1281 WEBRTC_TRACE(
1282 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1283 "SetSendCodec() failed to register codec to"
1284 " RTP/RTCP module");
1285 return -1;
1286 }
1287 }
1288
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001289 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001290 {
1291 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1292 "SetSendCodec() failed to set audio packet size");
1293 return -1;
1294 }
1295
1296 return 0;
1297}
1298
Ivo Creusenadf89b72015-04-29 16:03:33 +02001299void Channel::SetBitRate(int bitrate_bps) {
1300 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1301 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1302 audio_coding_->SetBitRate(bitrate_bps);
1303}
1304
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001305void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001306 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001307 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1308
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001309 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001310 if (audio_coding_->SetPacketLossRate(
1311 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001312 assert(false); // This should not happen.
1313 }
1314}
1315
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001316int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001317Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1318{
1319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1320 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001321 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001322 // To disable VAD, DTX must be disabled too
1323 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001324 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 {
1326 _engineStatisticsPtr->SetLastError(
1327 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1328 "SetVADStatus() failed to set VAD");
1329 return -1;
1330 }
1331 return 0;
1332}
1333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001334int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001335Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001339 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 {
1341 _engineStatisticsPtr->SetLastError(
1342 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1343 "GetVADStatus() failed to get VAD status");
1344 return -1;
1345 }
1346 disabledDTX = !disabledDTX;
1347 return 0;
1348}
1349
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001350int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001351Channel::SetRecPayloadType(const CodecInst& codec)
1352{
1353 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1354 "Channel::SetRecPayloadType()");
1355
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001356 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001357 {
1358 _engineStatisticsPtr->SetLastError(
1359 VE_ALREADY_PLAYING, kTraceError,
1360 "SetRecPayloadType() unable to set PT while playing");
1361 return -1;
1362 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001363 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001364 {
1365 _engineStatisticsPtr->SetLastError(
1366 VE_ALREADY_LISTENING, kTraceError,
1367 "SetRecPayloadType() unable to set PT while listening");
1368 return -1;
1369 }
1370
1371 if (codec.pltype == -1)
1372 {
1373 // De-register the selected codec (RTP/RTCP module and ACM)
1374
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001375 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 CodecInst rxCodec = codec;
1377
1378 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001379 rtp_payload_registry_->ReceivePayloadType(
1380 rxCodec.plname,
1381 rxCodec.plfreq,
1382 rxCodec.channels,
1383 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1384 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001385 rxCodec.pltype = pltype;
1386
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001387 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 {
1389 _engineStatisticsPtr->SetLastError(
1390 VE_RTP_RTCP_MODULE_ERROR,
1391 kTraceError,
1392 "SetRecPayloadType() RTP/RTCP-module deregistration "
1393 "failed");
1394 return -1;
1395 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001396 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001397 {
1398 _engineStatisticsPtr->SetLastError(
1399 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1400 "SetRecPayloadType() ACM deregistration failed - 1");
1401 return -1;
1402 }
1403 return 0;
1404 }
1405
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001406 if (rtp_receiver_->RegisterReceivePayload(
1407 codec.plname,
1408 codec.pltype,
1409 codec.plfreq,
1410 codec.channels,
1411 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001412 {
1413 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001414 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1415 if (rtp_receiver_->RegisterReceivePayload(
1416 codec.plname,
1417 codec.pltype,
1418 codec.plfreq,
1419 codec.channels,
1420 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001421 {
1422 _engineStatisticsPtr->SetLastError(
1423 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1424 "SetRecPayloadType() RTP/RTCP-module registration failed");
1425 return -1;
1426 }
1427 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001428 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001430 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1431 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001432 {
1433 _engineStatisticsPtr->SetLastError(
1434 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1435 "SetRecPayloadType() ACM registration failed - 1");
1436 return -1;
1437 }
1438 }
1439 return 0;
1440}
1441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001442int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001443Channel::GetRecPayloadType(CodecInst& codec)
1444{
1445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001447 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001448 if (rtp_payload_registry_->ReceivePayloadType(
1449 codec.plname,
1450 codec.plfreq,
1451 codec.channels,
1452 (codec.rate < 0) ? 0 : codec.rate,
1453 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001454 {
1455 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001456 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001457 "GetRecPayloadType() failed to retrieve RX payload type");
1458 return -1;
1459 }
1460 codec.pltype = payloadType;
1461 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001462 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001463 return 0;
1464}
1465
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001466int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001467Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1468{
1469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1470 "Channel::SetSendCNPayloadType()");
1471
1472 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001473 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001474 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 if (frequency == kFreq32000Hz)
1476 samplingFreqHz = 32000;
1477 else if (frequency == kFreq16000Hz)
1478 samplingFreqHz = 16000;
1479
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001480 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001481 {
1482 _engineStatisticsPtr->SetLastError(
1483 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1484 "SetSendCNPayloadType() failed to retrieve default CN codec "
1485 "settings");
1486 return -1;
1487 }
1488
1489 // Modify the payload type (must be set to dynamic range)
1490 codec.pltype = type;
1491
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001492 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001493 {
1494 _engineStatisticsPtr->SetLastError(
1495 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1496 "SetSendCNPayloadType() failed to register CN to ACM");
1497 return -1;
1498 }
1499
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001500 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001502 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1503 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 {
1505 _engineStatisticsPtr->SetLastError(
1506 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1507 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1508 "module");
1509 return -1;
1510 }
1511 }
1512 return 0;
1513}
1514
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001515int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001516 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001517 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001518
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001519 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001520 _engineStatisticsPtr->SetLastError(
1521 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001522 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001523 return -1;
1524 }
1525 return 0;
1526}
1527
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001528int Channel::SetOpusDtx(bool enable_dtx) {
1529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1530 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001531 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001532 : audio_coding_->DisableOpusDtx();
1533 if (ret != 0) {
1534 _engineStatisticsPtr->SetLastError(
1535 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1536 return -1;
1537 }
1538 return 0;
1539}
1540
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001541int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001542{
1543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1544 "Channel::RegisterExternalTransport()");
1545
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001546 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001547
niklase@google.com470e71d2011-07-07 08:21:25 +00001548 if (_externalTransport)
1549 {
1550 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1551 kTraceError,
1552 "RegisterExternalTransport() external transport already enabled");
1553 return -1;
1554 }
1555 _externalTransport = true;
1556 _transportPtr = &transport;
1557 return 0;
1558}
1559
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001560int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001561Channel::DeRegisterExternalTransport()
1562{
1563 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1564 "Channel::DeRegisterExternalTransport()");
1565
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001566 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001567
niklase@google.com470e71d2011-07-07 08:21:25 +00001568 if (!_transportPtr)
1569 {
1570 _engineStatisticsPtr->SetLastError(
1571 VE_INVALID_OPERATION, kTraceWarning,
1572 "DeRegisterExternalTransport() external transport already "
1573 "disabled");
1574 return 0;
1575 }
1576 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001577 _transportPtr = NULL;
1578 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1579 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001580 return 0;
1581}
1582
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001583int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001584 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001585 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1586 "Channel::ReceivedRTPPacket()");
1587
1588 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001589 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001590
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001591 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001592 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001593 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1594 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1595 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001596 return -1;
1597 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001598 header.payload_type_frequency =
1599 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001600 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001601 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001602 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001603 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001604 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001605 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001606
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001607 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001608}
1609
1610bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001611 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001612 const RTPHeader& header,
1613 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001614 if (rtp_payload_registry_->IsRtx(header)) {
1615 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001616 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001617 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001618 assert(packet_length >= header.headerLength);
1619 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001620 PayloadUnion payload_specific;
1621 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001622 &payload_specific)) {
1623 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001624 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001625 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1626 payload_specific, in_order);
1627}
1628
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001629bool Channel::HandleRtxPacket(const uint8_t* packet,
1630 size_t packet_length,
1631 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001632 if (!rtp_payload_registry_->IsRtx(header))
1633 return false;
1634
1635 // Remove the RTX header and parse the original RTP header.
1636 if (packet_length < header.headerLength)
1637 return false;
1638 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1639 return false;
1640 if (restored_packet_in_use_) {
1641 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1642 "Multiple RTX headers detected, dropping packet");
1643 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001644 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001645 uint8_t* restored_packet_ptr = restored_packet_;
1646 if (!rtp_payload_registry_->RestoreOriginalPacket(
1647 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1648 header)) {
1649 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1650 "Incoming RTX packet: invalid RTP header");
1651 return false;
1652 }
1653 restored_packet_in_use_ = true;
1654 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1655 restored_packet_in_use_ = false;
1656 return ret;
1657}
1658
1659bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1660 StreamStatistician* statistician =
1661 rtp_receive_statistics_->GetStatistician(header.ssrc);
1662 if (!statistician)
1663 return false;
1664 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001665}
1666
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001667bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1668 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001669 // Retransmissions are handled separately if RTX is enabled.
1670 if (rtp_payload_registry_->RtxEnabled())
1671 return false;
1672 StreamStatistician* statistician =
1673 rtp_receive_statistics_->GetStatistician(header.ssrc);
1674 if (!statistician)
1675 return false;
1676 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001677 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001678 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001679 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001680 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001681}
1682
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001683int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001684 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::ReceivedRTCPPacket()");
1686 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001687 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001688
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001689 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001690 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001691 _engineStatisticsPtr->SetLastError(
1692 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1693 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1694 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001695
Minyue2013aec2015-05-13 14:14:42 +02001696 int64_t rtt = GetRTT(true);
1697 if (rtt == 0) {
1698 // Waiting for valid RTT.
1699 return 0;
1700 }
1701 uint32_t ntp_secs = 0;
1702 uint32_t ntp_frac = 0;
1703 uint32_t rtp_timestamp = 0;
1704 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1705 &rtp_timestamp)) {
1706 // Waiting for RTCP.
1707 return 0;
1708 }
1709
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001710 {
1711 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001712 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001713 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001714 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001715}
1716
niklase@google.com470e71d2011-07-07 08:21:25 +00001717int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001718 bool loop,
1719 FileFormats format,
1720 int startPosition,
1721 float volumeScaling,
1722 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001723 const CodecInst* codecInst)
1724{
1725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1727 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1728 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1729 startPosition, stopPosition);
1730
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001731 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001732 {
1733 _engineStatisticsPtr->SetLastError(
1734 VE_ALREADY_PLAYING, kTraceError,
1735 "StartPlayingFileLocally() is already playing");
1736 return -1;
1737 }
1738
niklase@google.com470e71d2011-07-07 08:21:25 +00001739 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001740 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001741
1742 if (_outputFilePlayerPtr)
1743 {
1744 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1745 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1746 _outputFilePlayerPtr = NULL;
1747 }
1748
1749 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1750 _outputFilePlayerId, (const FileFormats)format);
1751
1752 if (_outputFilePlayerPtr == NULL)
1753 {
1754 _engineStatisticsPtr->SetLastError(
1755 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001756 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001757 return -1;
1758 }
1759
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001760 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001761
1762 if (_outputFilePlayerPtr->StartPlayingFile(
1763 fileName,
1764 loop,
1765 startPosition,
1766 volumeScaling,
1767 notificationTime,
1768 stopPosition,
1769 (const CodecInst*)codecInst) != 0)
1770 {
1771 _engineStatisticsPtr->SetLastError(
1772 VE_BAD_FILE, kTraceError,
1773 "StartPlayingFile() failed to start file playout");
1774 _outputFilePlayerPtr->StopPlayingFile();
1775 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1776 _outputFilePlayerPtr = NULL;
1777 return -1;
1778 }
1779 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001780 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001782
1783 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001784 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001785
1786 return 0;
1787}
1788
1789int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001790 FileFormats format,
1791 int startPosition,
1792 float volumeScaling,
1793 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001794 const CodecInst* codecInst)
1795{
1796 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1797 "Channel::StartPlayingFileLocally(format=%d,"
1798 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1799 format, volumeScaling, startPosition, stopPosition);
1800
1801 if(stream == NULL)
1802 {
1803 _engineStatisticsPtr->SetLastError(
1804 VE_BAD_FILE, kTraceError,
1805 "StartPlayingFileLocally() NULL as input stream");
1806 return -1;
1807 }
1808
1809
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001810 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001811 {
1812 _engineStatisticsPtr->SetLastError(
1813 VE_ALREADY_PLAYING, kTraceError,
1814 "StartPlayingFileLocally() is already playing");
1815 return -1;
1816 }
1817
niklase@google.com470e71d2011-07-07 08:21:25 +00001818 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001819 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001820
1821 // Destroy the old instance
1822 if (_outputFilePlayerPtr)
1823 {
1824 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1825 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1826 _outputFilePlayerPtr = NULL;
1827 }
1828
1829 // Create the instance
1830 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1831 _outputFilePlayerId,
1832 (const FileFormats)format);
1833
1834 if (_outputFilePlayerPtr == NULL)
1835 {
1836 _engineStatisticsPtr->SetLastError(
1837 VE_INVALID_ARGUMENT, kTraceError,
1838 "StartPlayingFileLocally() filePlayer format isnot correct");
1839 return -1;
1840 }
1841
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001842 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001843
1844 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1845 volumeScaling,
1846 notificationTime,
1847 stopPosition, codecInst) != 0)
1848 {
1849 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1850 "StartPlayingFile() failed to "
1851 "start file playout");
1852 _outputFilePlayerPtr->StopPlayingFile();
1853 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1854 _outputFilePlayerPtr = NULL;
1855 return -1;
1856 }
1857 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001858 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001859 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001860
1861 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001862 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001863
niklase@google.com470e71d2011-07-07 08:21:25 +00001864 return 0;
1865}
1866
1867int Channel::StopPlayingFileLocally()
1868{
1869 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1870 "Channel::StopPlayingFileLocally()");
1871
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001872 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_INVALID_OPERATION, kTraceWarning,
1876 "StopPlayingFileLocally() isnot playing");
1877 return 0;
1878 }
1879
niklase@google.com470e71d2011-07-07 08:21:25 +00001880 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001881 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001882
1883 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1884 {
1885 _engineStatisticsPtr->SetLastError(
1886 VE_STOP_RECORDING_FAILED, kTraceError,
1887 "StopPlayingFile() could not stop playing");
1888 return -1;
1889 }
1890 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1891 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1892 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001893 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001894 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001895 // _fileCritSect cannot be taken while calling
1896 // SetAnonymousMixibilityStatus. Refer to comments in
1897 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001898 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1899 {
1900 _engineStatisticsPtr->SetLastError(
1901 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001902 "StopPlayingFile() failed to stop participant from playing as"
1903 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001904 return -1;
1905 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001906
1907 return 0;
1908}
1909
1910int Channel::IsPlayingFileLocally() const
1911{
1912 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1913 "Channel::IsPlayingFileLocally()");
1914
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001915 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001916}
1917
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001918int Channel::RegisterFilePlayingToMixer()
1919{
1920 // Return success for not registering for file playing to mixer if:
1921 // 1. playing file before playout is started on that channel.
1922 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001923 if (!channel_state_.Get().playing ||
1924 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001925 {
1926 return 0;
1927 }
1928
1929 // |_fileCritSect| cannot be taken while calling
1930 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1931 // frames can be pulled by the mixer. Since the frames are generated from
1932 // the file, _fileCritSect will be taken. This would result in a deadlock.
1933 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1934 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001935 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001936 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001937 _engineStatisticsPtr->SetLastError(
1938 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1939 "StartPlayingFile() failed to add participant as file to mixer");
1940 _outputFilePlayerPtr->StopPlayingFile();
1941 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1942 _outputFilePlayerPtr = NULL;
1943 return -1;
1944 }
1945
1946 return 0;
1947}
1948
niklase@google.com470e71d2011-07-07 08:21:25 +00001949int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001950 bool loop,
1951 FileFormats format,
1952 int startPosition,
1953 float volumeScaling,
1954 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001955 const CodecInst* codecInst)
1956{
1957 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1958 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1959 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1960 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1961 startPosition, stopPosition);
1962
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001963 CriticalSectionScoped cs(&_fileCritSect);
1964
1965 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001966 {
1967 _engineStatisticsPtr->SetLastError(
1968 VE_ALREADY_PLAYING, kTraceWarning,
1969 "StartPlayingFileAsMicrophone() filePlayer is playing");
1970 return 0;
1971 }
1972
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 // Destroy the old instance
1974 if (_inputFilePlayerPtr)
1975 {
1976 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1977 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1978 _inputFilePlayerPtr = NULL;
1979 }
1980
1981 // Create the instance
1982 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1983 _inputFilePlayerId, (const FileFormats)format);
1984
1985 if (_inputFilePlayerPtr == NULL)
1986 {
1987 _engineStatisticsPtr->SetLastError(
1988 VE_INVALID_ARGUMENT, kTraceError,
1989 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
1990 return -1;
1991 }
1992
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001993 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001994
1995 if (_inputFilePlayerPtr->StartPlayingFile(
1996 fileName,
1997 loop,
1998 startPosition,
1999 volumeScaling,
2000 notificationTime,
2001 stopPosition,
2002 (const CodecInst*)codecInst) != 0)
2003 {
2004 _engineStatisticsPtr->SetLastError(
2005 VE_BAD_FILE, kTraceError,
2006 "StartPlayingFile() failed to start file playout");
2007 _inputFilePlayerPtr->StopPlayingFile();
2008 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2009 _inputFilePlayerPtr = NULL;
2010 return -1;
2011 }
2012 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002013 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002014
2015 return 0;
2016}
2017
2018int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002019 FileFormats format,
2020 int startPosition,
2021 float volumeScaling,
2022 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002023 const CodecInst* codecInst)
2024{
2025 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2026 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2027 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2028 format, volumeScaling, startPosition, stopPosition);
2029
2030 if(stream == NULL)
2031 {
2032 _engineStatisticsPtr->SetLastError(
2033 VE_BAD_FILE, kTraceError,
2034 "StartPlayingFileAsMicrophone NULL as input stream");
2035 return -1;
2036 }
2037
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002038 CriticalSectionScoped cs(&_fileCritSect);
2039
2040 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002041 {
2042 _engineStatisticsPtr->SetLastError(
2043 VE_ALREADY_PLAYING, kTraceWarning,
2044 "StartPlayingFileAsMicrophone() is playing");
2045 return 0;
2046 }
2047
niklase@google.com470e71d2011-07-07 08:21:25 +00002048 // Destroy the old instance
2049 if (_inputFilePlayerPtr)
2050 {
2051 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2052 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2053 _inputFilePlayerPtr = NULL;
2054 }
2055
2056 // Create the instance
2057 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2058 _inputFilePlayerId, (const FileFormats)format);
2059
2060 if (_inputFilePlayerPtr == NULL)
2061 {
2062 _engineStatisticsPtr->SetLastError(
2063 VE_INVALID_ARGUMENT, kTraceError,
2064 "StartPlayingInputFile() filePlayer format isnot correct");
2065 return -1;
2066 }
2067
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002068 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002069
2070 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2071 volumeScaling, notificationTime,
2072 stopPosition, codecInst) != 0)
2073 {
2074 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2075 "StartPlayingFile() failed to start "
2076 "file playout");
2077 _inputFilePlayerPtr->StopPlayingFile();
2078 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2079 _inputFilePlayerPtr = NULL;
2080 return -1;
2081 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002082
niklase@google.com470e71d2011-07-07 08:21:25 +00002083 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002084 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002085
2086 return 0;
2087}
2088
2089int Channel::StopPlayingFileAsMicrophone()
2090{
2091 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2092 "Channel::StopPlayingFileAsMicrophone()");
2093
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002094 CriticalSectionScoped cs(&_fileCritSect);
2095
2096 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002097 {
2098 _engineStatisticsPtr->SetLastError(
2099 VE_INVALID_OPERATION, kTraceWarning,
2100 "StopPlayingFileAsMicrophone() isnot playing");
2101 return 0;
2102 }
2103
niklase@google.com470e71d2011-07-07 08:21:25 +00002104 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2105 {
2106 _engineStatisticsPtr->SetLastError(
2107 VE_STOP_RECORDING_FAILED, kTraceError,
2108 "StopPlayingFile() could not stop playing");
2109 return -1;
2110 }
2111 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2112 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2113 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002114 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002115
2116 return 0;
2117}
2118
2119int Channel::IsPlayingFileAsMicrophone() const
2120{
2121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2122 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002123 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002124}
2125
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002126int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002127 const CodecInst* codecInst)
2128{
2129 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2130 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2131
2132 if (_outputFileRecording)
2133 {
2134 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2135 "StartRecordingPlayout() is already recording");
2136 return 0;
2137 }
2138
2139 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002140 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002141 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2142
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002143 if ((codecInst != NULL) &&
2144 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002145 {
2146 _engineStatisticsPtr->SetLastError(
2147 VE_BAD_ARGUMENT, kTraceError,
2148 "StartRecordingPlayout() invalid compression");
2149 return(-1);
2150 }
2151 if(codecInst == NULL)
2152 {
2153 format = kFileFormatPcm16kHzFile;
2154 codecInst=&dummyCodec;
2155 }
2156 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2157 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2158 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2159 {
2160 format = kFileFormatWavFile;
2161 }
2162 else
2163 {
2164 format = kFileFormatCompressedFile;
2165 }
2166
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002167 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002168
2169 // Destroy the old instance
2170 if (_outputFileRecorderPtr)
2171 {
2172 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2173 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2174 _outputFileRecorderPtr = NULL;
2175 }
2176
2177 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2178 _outputFileRecorderId, (const FileFormats)format);
2179 if (_outputFileRecorderPtr == NULL)
2180 {
2181 _engineStatisticsPtr->SetLastError(
2182 VE_INVALID_ARGUMENT, kTraceError,
2183 "StartRecordingPlayout() fileRecorder format isnot correct");
2184 return -1;
2185 }
2186
2187 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2188 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2189 {
2190 _engineStatisticsPtr->SetLastError(
2191 VE_BAD_FILE, kTraceError,
2192 "StartRecordingAudioFile() failed to start file recording");
2193 _outputFileRecorderPtr->StopRecording();
2194 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2195 _outputFileRecorderPtr = NULL;
2196 return -1;
2197 }
2198 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2199 _outputFileRecording = true;
2200
2201 return 0;
2202}
2203
2204int Channel::StartRecordingPlayout(OutStream* stream,
2205 const CodecInst* codecInst)
2206{
2207 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2208 "Channel::StartRecordingPlayout()");
2209
2210 if (_outputFileRecording)
2211 {
2212 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2213 "StartRecordingPlayout() is already recording");
2214 return 0;
2215 }
2216
2217 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002218 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002219 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2220
2221 if (codecInst != NULL && codecInst->channels != 1)
2222 {
2223 _engineStatisticsPtr->SetLastError(
2224 VE_BAD_ARGUMENT, kTraceError,
2225 "StartRecordingPlayout() invalid compression");
2226 return(-1);
2227 }
2228 if(codecInst == NULL)
2229 {
2230 format = kFileFormatPcm16kHzFile;
2231 codecInst=&dummyCodec;
2232 }
2233 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2234 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2235 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2236 {
2237 format = kFileFormatWavFile;
2238 }
2239 else
2240 {
2241 format = kFileFormatCompressedFile;
2242 }
2243
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002244 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002245
2246 // Destroy the old instance
2247 if (_outputFileRecorderPtr)
2248 {
2249 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2250 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2251 _outputFileRecorderPtr = NULL;
2252 }
2253
2254 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2255 _outputFileRecorderId, (const FileFormats)format);
2256 if (_outputFileRecorderPtr == NULL)
2257 {
2258 _engineStatisticsPtr->SetLastError(
2259 VE_INVALID_ARGUMENT, kTraceError,
2260 "StartRecordingPlayout() fileRecorder format isnot correct");
2261 return -1;
2262 }
2263
2264 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2265 notificationTime) != 0)
2266 {
2267 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2268 "StartRecordingPlayout() failed to "
2269 "start file recording");
2270 _outputFileRecorderPtr->StopRecording();
2271 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2272 _outputFileRecorderPtr = NULL;
2273 return -1;
2274 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002275
niklase@google.com470e71d2011-07-07 08:21:25 +00002276 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2277 _outputFileRecording = true;
2278
2279 return 0;
2280}
2281
2282int Channel::StopRecordingPlayout()
2283{
2284 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2285 "Channel::StopRecordingPlayout()");
2286
2287 if (!_outputFileRecording)
2288 {
2289 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2290 "StopRecordingPlayout() isnot recording");
2291 return -1;
2292 }
2293
2294
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002295 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002296
2297 if (_outputFileRecorderPtr->StopRecording() != 0)
2298 {
2299 _engineStatisticsPtr->SetLastError(
2300 VE_STOP_RECORDING_FAILED, kTraceError,
2301 "StopRecording() could not stop recording");
2302 return(-1);
2303 }
2304 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2305 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2306 _outputFileRecorderPtr = NULL;
2307 _outputFileRecording = false;
2308
2309 return 0;
2310}
2311
2312void
2313Channel::SetMixWithMicStatus(bool mix)
2314{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002315 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002316 _mixFileWithMicrophone=mix;
2317}
2318
2319int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002320Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002321{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002322 int8_t currentLevel = _outputAudioLevel.Level();
2323 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002324 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2325 VoEId(_instanceId,_channelId),
2326 "GetSpeechOutputLevel() => level=%u", level);
2327 return 0;
2328}
2329
2330int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002331Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002332{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002333 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2334 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002335 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2336 VoEId(_instanceId,_channelId),
2337 "GetSpeechOutputLevelFullRange() => level=%u", level);
2338 return 0;
2339}
2340
2341int
2342Channel::SetMute(bool enable)
2343{
wu@webrtc.org63420662013-10-17 18:28:55 +00002344 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002345 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2346 "Channel::SetMute(enable=%d)", enable);
2347 _mute = enable;
2348 return 0;
2349}
2350
2351bool
2352Channel::Mute() const
2353{
wu@webrtc.org63420662013-10-17 18:28:55 +00002354 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002355 return _mute;
2356}
2357
2358int
2359Channel::SetOutputVolumePan(float left, float right)
2360{
wu@webrtc.org63420662013-10-17 18:28:55 +00002361 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2363 "Channel::SetOutputVolumePan()");
2364 _panLeft = left;
2365 _panRight = right;
2366 return 0;
2367}
2368
2369int
2370Channel::GetOutputVolumePan(float& left, float& right) const
2371{
wu@webrtc.org63420662013-10-17 18:28:55 +00002372 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002373 left = _panLeft;
2374 right = _panRight;
2375 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2376 VoEId(_instanceId,_channelId),
2377 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2378 return 0;
2379}
2380
2381int
2382Channel::SetChannelOutputVolumeScaling(float scaling)
2383{
wu@webrtc.org63420662013-10-17 18:28:55 +00002384 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002385 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2386 "Channel::SetChannelOutputVolumeScaling()");
2387 _outputGain = scaling;
2388 return 0;
2389}
2390
2391int
2392Channel::GetChannelOutputVolumeScaling(float& scaling) const
2393{
wu@webrtc.org63420662013-10-17 18:28:55 +00002394 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002395 scaling = _outputGain;
2396 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2397 VoEId(_instanceId,_channelId),
2398 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2399 return 0;
2400}
2401
niklase@google.com470e71d2011-07-07 08:21:25 +00002402int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002403 int lengthMs, int attenuationDb,
2404 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002405{
2406 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2407 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2408 playDtmfEvent);
2409
2410 _playOutbandDtmfEvent = playDtmfEvent;
2411
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002412 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002413 attenuationDb) != 0)
2414 {
2415 _engineStatisticsPtr->SetLastError(
2416 VE_SEND_DTMF_FAILED,
2417 kTraceWarning,
2418 "SendTelephoneEventOutband() failed to send event");
2419 return -1;
2420 }
2421 return 0;
2422}
2423
2424int Channel::SendTelephoneEventInband(unsigned char eventCode,
2425 int lengthMs,
2426 int attenuationDb,
2427 bool playDtmfEvent)
2428{
2429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2430 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2431 playDtmfEvent);
2432
2433 _playInbandDtmfEvent = playDtmfEvent;
2434 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2435
2436 return 0;
2437}
2438
2439int
niklase@google.com470e71d2011-07-07 08:21:25 +00002440Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2441{
2442 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2443 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002444 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002445 {
2446 _engineStatisticsPtr->SetLastError(
2447 VE_INVALID_ARGUMENT, kTraceError,
2448 "SetSendTelephoneEventPayloadType() invalid type");
2449 return -1;
2450 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002451 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002452 codec.plfreq = 8000;
2453 codec.pltype = type;
2454 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002455 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002456 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002457 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2458 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2459 _engineStatisticsPtr->SetLastError(
2460 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2461 "SetSendTelephoneEventPayloadType() failed to register send"
2462 "payload type");
2463 return -1;
2464 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002465 }
2466 _sendTelephoneEventPayloadType = type;
2467 return 0;
2468}
2469
2470int
2471Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2472{
2473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2474 "Channel::GetSendTelephoneEventPayloadType()");
2475 type = _sendTelephoneEventPayloadType;
2476 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2477 VoEId(_instanceId,_channelId),
2478 "GetSendTelephoneEventPayloadType() => type=%u", type);
2479 return 0;
2480}
2481
niklase@google.com470e71d2011-07-07 08:21:25 +00002482int
2483Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2484{
2485 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2486 "Channel::UpdateRxVadDetection()");
2487
2488 int vadDecision = 1;
2489
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002490 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002491
2492 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2493 {
2494 OnRxVadDetected(vadDecision);
2495 _oldVadDecision = vadDecision;
2496 }
2497
2498 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2499 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2500 vadDecision);
2501 return 0;
2502}
2503
2504int
2505Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2506{
2507 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2508 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002509 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002510
2511 if (_rxVadObserverPtr)
2512 {
2513 _engineStatisticsPtr->SetLastError(
2514 VE_INVALID_OPERATION, kTraceError,
2515 "RegisterRxVadObserver() observer already enabled");
2516 return -1;
2517 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002518 _rxVadObserverPtr = &observer;
2519 _RxVadDetection = true;
2520 return 0;
2521}
2522
2523int
2524Channel::DeRegisterRxVadObserver()
2525{
2526 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2527 "Channel::DeRegisterRxVadObserver()");
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, kTraceWarning,
2534 "DeRegisterRxVadObserver() observer already disabled");
2535 return 0;
2536 }
2537 _rxVadObserverPtr = NULL;
2538 _RxVadDetection = false;
2539 return 0;
2540}
2541
2542int
2543Channel::VoiceActivityIndicator(int &activity)
2544{
2545 activity = _sendFrameType;
2546
2547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002548 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002549 return 0;
2550}
2551
2552#ifdef WEBRTC_VOICE_ENGINE_AGC
2553
2554int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002555Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002556{
2557 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2558 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2559 (int)enable, (int)mode);
2560
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002561 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002562 switch (mode)
2563 {
2564 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002565 break;
2566 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002567 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002568 break;
2569 case kAgcFixedDigital:
2570 agcMode = GainControl::kFixedDigital;
2571 break;
2572 case kAgcAdaptiveDigital:
2573 agcMode =GainControl::kAdaptiveDigital;
2574 break;
2575 default:
2576 _engineStatisticsPtr->SetLastError(
2577 VE_INVALID_ARGUMENT, kTraceError,
2578 "SetRxAgcStatus() invalid Agc mode");
2579 return -1;
2580 }
2581
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002582 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002583 {
2584 _engineStatisticsPtr->SetLastError(
2585 VE_APM_ERROR, kTraceError,
2586 "SetRxAgcStatus() failed to set Agc mode");
2587 return -1;
2588 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002589 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002590 {
2591 _engineStatisticsPtr->SetLastError(
2592 VE_APM_ERROR, kTraceError,
2593 "SetRxAgcStatus() failed to set Agc state");
2594 return -1;
2595 }
2596
2597 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002598 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002599
2600 return 0;
2601}
2602
2603int
2604Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2605{
2606 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2607 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2608
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002609 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002610 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002611 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002612
2613 enabled = enable;
2614
2615 switch (agcMode)
2616 {
2617 case GainControl::kFixedDigital:
2618 mode = kAgcFixedDigital;
2619 break;
2620 case GainControl::kAdaptiveDigital:
2621 mode = kAgcAdaptiveDigital;
2622 break;
2623 default:
2624 _engineStatisticsPtr->SetLastError(
2625 VE_APM_ERROR, kTraceError,
2626 "GetRxAgcStatus() invalid Agc mode");
2627 return -1;
2628 }
2629
2630 return 0;
2631}
2632
2633int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002634Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002635{
2636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2637 "Channel::SetRxAgcConfig()");
2638
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002639 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002640 config.targetLeveldBOv) != 0)
2641 {
2642 _engineStatisticsPtr->SetLastError(
2643 VE_APM_ERROR, kTraceError,
2644 "SetRxAgcConfig() failed to set target peak |level|"
2645 "(or envelope) of the Agc");
2646 return -1;
2647 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002648 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002649 config.digitalCompressionGaindB) != 0)
2650 {
2651 _engineStatisticsPtr->SetLastError(
2652 VE_APM_ERROR, kTraceError,
2653 "SetRxAgcConfig() failed to set the range in |gain| the"
2654 " digital compression stage may apply");
2655 return -1;
2656 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002657 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002658 config.limiterEnable) != 0)
2659 {
2660 _engineStatisticsPtr->SetLastError(
2661 VE_APM_ERROR, kTraceError,
2662 "SetRxAgcConfig() failed to set hard limiter to the signal");
2663 return -1;
2664 }
2665
2666 return 0;
2667}
2668
2669int
2670Channel::GetRxAgcConfig(AgcConfig& config)
2671{
2672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2673 "Channel::GetRxAgcConfig(config=%?)");
2674
2675 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002676 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002677 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002678 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002679 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002680 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002681
2682 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2683 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2684 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2685 " limiterEnable=%d",
2686 config.targetLeveldBOv,
2687 config.digitalCompressionGaindB,
2688 config.limiterEnable);
2689
2690 return 0;
2691}
2692
2693#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2694
2695#ifdef WEBRTC_VOICE_ENGINE_NR
2696
2697int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002698Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002699{
2700 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2701 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2702 (int)enable, (int)mode);
2703
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002704 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002705 switch (mode)
2706 {
2707
2708 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002709 break;
2710 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002711 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002712 break;
2713 case kNsConference:
2714 nsLevel = NoiseSuppression::kHigh;
2715 break;
2716 case kNsLowSuppression:
2717 nsLevel = NoiseSuppression::kLow;
2718 break;
2719 case kNsModerateSuppression:
2720 nsLevel = NoiseSuppression::kModerate;
2721 break;
2722 case kNsHighSuppression:
2723 nsLevel = NoiseSuppression::kHigh;
2724 break;
2725 case kNsVeryHighSuppression:
2726 nsLevel = NoiseSuppression::kVeryHigh;
2727 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002728 }
2729
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002730 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002731 != 0)
2732 {
2733 _engineStatisticsPtr->SetLastError(
2734 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002735 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002736 return -1;
2737 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002738 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002739 {
2740 _engineStatisticsPtr->SetLastError(
2741 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002742 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002743 return -1;
2744 }
2745
2746 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002747 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002748
2749 return 0;
2750}
2751
2752int
2753Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2754{
2755 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2756 "Channel::GetRxNsStatus(enable=?, mode=?)");
2757
2758 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002759 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002760 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002761 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002762
2763 enabled = enable;
2764
2765 switch (ncLevel)
2766 {
2767 case NoiseSuppression::kLow:
2768 mode = kNsLowSuppression;
2769 break;
2770 case NoiseSuppression::kModerate:
2771 mode = kNsModerateSuppression;
2772 break;
2773 case NoiseSuppression::kHigh:
2774 mode = kNsHighSuppression;
2775 break;
2776 case NoiseSuppression::kVeryHigh:
2777 mode = kNsVeryHighSuppression;
2778 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002779 }
2780
2781 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2782 VoEId(_instanceId,_channelId),
2783 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2784 return 0;
2785}
2786
2787#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2788
2789int
niklase@google.com470e71d2011-07-07 08:21:25 +00002790Channel::SetLocalSSRC(unsigned int ssrc)
2791{
2792 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2793 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002794 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002795 {
2796 _engineStatisticsPtr->SetLastError(
2797 VE_ALREADY_SENDING, kTraceError,
2798 "SetLocalSSRC() already sending");
2799 return -1;
2800 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002801 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 return 0;
2803}
2804
2805int
2806Channel::GetLocalSSRC(unsigned int& ssrc)
2807{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002808 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002809 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2810 VoEId(_instanceId,_channelId),
2811 "GetLocalSSRC() => ssrc=%lu", ssrc);
2812 return 0;
2813}
2814
2815int
2816Channel::GetRemoteSSRC(unsigned int& ssrc)
2817{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002818 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002819 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2820 VoEId(_instanceId,_channelId),
2821 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2822 return 0;
2823}
2824
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002825int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002826 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002827 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002828}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002829
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002830int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2831 unsigned char id) {
2832 rtp_header_parser_->DeregisterRtpHeaderExtension(
2833 kRtpExtensionAudioLevel);
2834 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2835 kRtpExtensionAudioLevel, id)) {
2836 return -1;
2837 }
2838 return 0;
2839}
2840
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002841int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2842 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2843}
2844
2845int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2846 rtp_header_parser_->DeregisterRtpHeaderExtension(
2847 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002848 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2849 kRtpExtensionAbsoluteSendTime, id)) {
2850 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002851 }
2852 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002853}
2854
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002855void Channel::SetRTCPStatus(bool enable) {
2856 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2857 "Channel::SetRTCPStatus()");
2858 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002859}
2860
2861int
2862Channel::GetRTCPStatus(bool& enabled)
2863{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002864 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002865 enabled = (method != kRtcpOff);
2866 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2867 VoEId(_instanceId,_channelId),
2868 "GetRTCPStatus() => enabled=%d", enabled);
2869 return 0;
2870}
2871
2872int
2873Channel::SetRTCP_CNAME(const char cName[256])
2874{
2875 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2876 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002877 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002878 {
2879 _engineStatisticsPtr->SetLastError(
2880 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2881 "SetRTCP_CNAME() failed to set RTCP CNAME");
2882 return -1;
2883 }
2884 return 0;
2885}
2886
2887int
niklase@google.com470e71d2011-07-07 08:21:25 +00002888Channel::GetRemoteRTCP_CNAME(char cName[256])
2889{
2890 if (cName == NULL)
2891 {
2892 _engineStatisticsPtr->SetLastError(
2893 VE_INVALID_ARGUMENT, kTraceError,
2894 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2895 return -1;
2896 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002897 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002898 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002899 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002900 {
2901 _engineStatisticsPtr->SetLastError(
2902 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2903 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2904 return -1;
2905 }
2906 strcpy(cName, cname);
2907 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2908 VoEId(_instanceId, _channelId),
2909 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2910 return 0;
2911}
2912
2913int
2914Channel::GetRemoteRTCPData(
2915 unsigned int& NTPHigh,
2916 unsigned int& NTPLow,
2917 unsigned int& timestamp,
2918 unsigned int& playoutTimestamp,
2919 unsigned int* jitter,
2920 unsigned short* fractionLost)
2921{
2922 // --- Information from sender info in received Sender Reports
2923
2924 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002925 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002926 {
2927 _engineStatisticsPtr->SetLastError(
2928 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002929 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002930 "side");
2931 return -1;
2932 }
2933
2934 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2935 // and octet count)
2936 NTPHigh = senderInfo.NTPseconds;
2937 NTPLow = senderInfo.NTPfraction;
2938 timestamp = senderInfo.RTPtimeStamp;
2939
2940 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2941 VoEId(_instanceId, _channelId),
2942 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2943 "timestamp=%lu",
2944 NTPHigh, NTPLow, timestamp);
2945
2946 // --- Locally derived information
2947
2948 // This value is updated on each incoming RTCP packet (0 when no packet
2949 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002950 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002951
2952 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2953 VoEId(_instanceId, _channelId),
2954 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002955 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002956
2957 if (NULL != jitter || NULL != fractionLost)
2958 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002959 // Get all RTCP receiver report blocks that have been received on this
2960 // channel. If we receive RTP packets from a remote source we know the
2961 // remote SSRC and use the report block from him.
2962 // Otherwise use the first report block.
2963 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002964 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002965 remote_stats.empty()) {
2966 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2967 VoEId(_instanceId, _channelId),
2968 "GetRemoteRTCPData() failed to measure statistics due"
2969 " to lack of received RTP and/or RTCP packets");
2970 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002971 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002972
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002973 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002974 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
2975 for (; it != remote_stats.end(); ++it) {
2976 if (it->remoteSSRC == remoteSSRC)
2977 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002978 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002979
2980 if (it == remote_stats.end()) {
2981 // If we have not received any RTCP packets from this SSRC it probably
2982 // means that we have not received any RTP packets.
2983 // Use the first received report block instead.
2984 it = remote_stats.begin();
2985 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00002986 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002987
xians@webrtc.org79af7342012-01-31 12:22:14 +00002988 if (jitter) {
2989 *jitter = it->jitter;
2990 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2991 VoEId(_instanceId, _channelId),
2992 "GetRemoteRTCPData() => jitter = %lu", *jitter);
2993 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002994
xians@webrtc.org79af7342012-01-31 12:22:14 +00002995 if (fractionLost) {
2996 *fractionLost = it->fractionLost;
2997 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2998 VoEId(_instanceId, _channelId),
2999 "GetRemoteRTCPData() => fractionLost = %lu",
3000 *fractionLost);
3001 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003002 }
3003 return 0;
3004}
3005
3006int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003007Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003008 unsigned int name,
3009 const char* data,
3010 unsigned short dataLengthInBytes)
3011{
3012 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3013 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003014 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003015 {
3016 _engineStatisticsPtr->SetLastError(
3017 VE_NOT_SENDING, kTraceError,
3018 "SendApplicationDefinedRTCPPacket() not sending");
3019 return -1;
3020 }
3021 if (NULL == data)
3022 {
3023 _engineStatisticsPtr->SetLastError(
3024 VE_INVALID_ARGUMENT, kTraceError,
3025 "SendApplicationDefinedRTCPPacket() invalid data value");
3026 return -1;
3027 }
3028 if (dataLengthInBytes % 4 != 0)
3029 {
3030 _engineStatisticsPtr->SetLastError(
3031 VE_INVALID_ARGUMENT, kTraceError,
3032 "SendApplicationDefinedRTCPPacket() invalid length value");
3033 return -1;
3034 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003035 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003036 if (status == kRtcpOff)
3037 {
3038 _engineStatisticsPtr->SetLastError(
3039 VE_RTCP_ERROR, kTraceError,
3040 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3041 return -1;
3042 }
3043
3044 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003045 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003046 subType,
3047 name,
3048 (const unsigned char*) data,
3049 dataLengthInBytes) != 0)
3050 {
3051 _engineStatisticsPtr->SetLastError(
3052 VE_SEND_ERROR, kTraceError,
3053 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3054 return -1;
3055 }
3056 return 0;
3057}
3058
3059int
3060Channel::GetRTPStatistics(
3061 unsigned int& averageJitterMs,
3062 unsigned int& maxJitterMs,
3063 unsigned int& discardedPackets)
3064{
niklase@google.com470e71d2011-07-07 08:21:25 +00003065 // The jitter statistics is updated for each received RTP packet and is
3066 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003067 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3068 // If RTCP is off, there is no timed thread in the RTCP module regularly
3069 // generating new stats, trigger the update manually here instead.
3070 StreamStatistician* statistician =
3071 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3072 if (statistician) {
3073 // Don't use returned statistics, use data from proxy instead so that
3074 // max jitter can be fetched atomically.
3075 RtcpStatistics s;
3076 statistician->GetStatistics(&s, true);
3077 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003078 }
3079
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003080 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003081 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003082 if (playoutFrequency > 0) {
3083 // Scale RTP statistics given the current playout frequency
3084 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3085 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003086 }
3087
3088 discardedPackets = _numberOfDiscardedPackets;
3089
3090 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3091 VoEId(_instanceId, _channelId),
3092 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003093 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003094 averageJitterMs, maxJitterMs, discardedPackets);
3095 return 0;
3096}
3097
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003098int Channel::GetRemoteRTCPReportBlocks(
3099 std::vector<ReportBlock>* report_blocks) {
3100 if (report_blocks == NULL) {
3101 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3102 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3103 return -1;
3104 }
3105
3106 // Get the report blocks from the latest received RTCP Sender or Receiver
3107 // Report. Each element in the vector contains the sender's SSRC and a
3108 // report block according to RFC 3550.
3109 std::vector<RTCPReportBlock> rtcp_report_blocks;
3110 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3111 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3112 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3113 return -1;
3114 }
3115
3116 if (rtcp_report_blocks.empty())
3117 return 0;
3118
3119 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3120 for (; it != rtcp_report_blocks.end(); ++it) {
3121 ReportBlock report_block;
3122 report_block.sender_SSRC = it->remoteSSRC;
3123 report_block.source_SSRC = it->sourceSSRC;
3124 report_block.fraction_lost = it->fractionLost;
3125 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3126 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3127 report_block.interarrival_jitter = it->jitter;
3128 report_block.last_SR_timestamp = it->lastSR;
3129 report_block.delay_since_last_SR = it->delaySinceLastSR;
3130 report_blocks->push_back(report_block);
3131 }
3132 return 0;
3133}
3134
niklase@google.com470e71d2011-07-07 08:21:25 +00003135int
3136Channel::GetRTPStatistics(CallStatistics& stats)
3137{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003138 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003139
3140 // The jitter statistics is updated for each received RTP packet and is
3141 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003142 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003143 StreamStatistician* statistician =
3144 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3145 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003146 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3147 _engineStatisticsPtr->SetLastError(
3148 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3149 "GetRTPStatistics() failed to read RTP statistics from the "
3150 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003151 }
3152
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003153 stats.fractionLost = statistics.fraction_lost;
3154 stats.cumulativeLost = statistics.cumulative_lost;
3155 stats.extendedMax = statistics.extended_max_sequence_number;
3156 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003157
3158 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3159 VoEId(_instanceId, _channelId),
3160 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003161 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003162 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3163 stats.jitterSamples);
3164
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003165 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003166 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003167 if (stats.rttMs == 0) {
3168 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3169 "GetRTPStatistics() failed to get RTT");
3170 } else {
3171 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003172 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003173 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003174
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003175 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003176
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003177 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003178 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003179 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003180 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003181
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003182 if (statistician) {
3183 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3184 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003185
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003186 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003187 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003188 {
3189 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3190 VoEId(_instanceId, _channelId),
3191 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003192 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003193 }
3194
3195 stats.bytesSent = bytesSent;
3196 stats.packetsSent = packetsSent;
3197 stats.bytesReceived = bytesReceived;
3198 stats.packetsReceived = packetsReceived;
3199
3200 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3201 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003202 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3203 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003204 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3205 stats.packetsReceived);
3206
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003207 // --- Timestamps
3208 {
3209 CriticalSectionScoped lock(ts_stats_lock_.get());
3210 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3211 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003212 return 0;
3213}
3214
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003215int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003216 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003217 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003218
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003219 if (enable) {
3220 if (redPayloadtype < 0 || redPayloadtype > 127) {
3221 _engineStatisticsPtr->SetLastError(
3222 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003223 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003224 return -1;
3225 }
3226
3227 if (SetRedPayloadType(redPayloadtype) < 0) {
3228 _engineStatisticsPtr->SetLastError(
3229 VE_CODEC_ERROR, kTraceError,
3230 "SetSecondarySendCodec() Failed to register RED ACM");
3231 return -1;
3232 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003233 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003234
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003235 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003236 _engineStatisticsPtr->SetLastError(
3237 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003238 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003239 return -1;
3240 }
3241 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003242}
3243
3244int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003245Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003246{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003247 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003248 if (enabled)
3249 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003250 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003251 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003252 {
3253 _engineStatisticsPtr->SetLastError(
3254 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003255 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003256 "module");
3257 return -1;
3258 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003259 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003260 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3261 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003262 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003263 enabled, redPayloadtype);
3264 return 0;
3265 }
3266 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3267 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003268 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 return 0;
3270}
3271
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003272int Channel::SetCodecFECStatus(bool enable) {
3273 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3274 "Channel::SetCodecFECStatus()");
3275
3276 if (audio_coding_->SetCodecFEC(enable) != 0) {
3277 _engineStatisticsPtr->SetLastError(
3278 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3279 "SetCodecFECStatus() failed to set FEC state");
3280 return -1;
3281 }
3282 return 0;
3283}
3284
3285bool Channel::GetCodecFECStatus() {
3286 bool enabled = audio_coding_->CodecFEC();
3287 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3288 VoEId(_instanceId, _channelId),
3289 "GetCodecFECStatus() => enabled=%d", enabled);
3290 return enabled;
3291}
3292
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003293void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3294 // None of these functions can fail.
3295 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003296 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3297 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003298 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003299 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003300 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003301 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003302}
3303
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003304// Called when we are missing one or more packets.
3305int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003306 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3307}
3308
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003309uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003310Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003311{
3312 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003313 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003314 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003315 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003316 return 0;
3317}
3318
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003319void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003320 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003321 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003322 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003323 CodecInst codec;
3324 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003325
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003326 if (!mono_recording_audio_.get()) {
3327 // Temporary space for DownConvertToCodecFormat.
3328 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003329 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003330 DownConvertToCodecFormat(audio_data,
3331 number_of_frames,
3332 number_of_channels,
3333 sample_rate,
3334 codec.channels,
3335 codec.plfreq,
3336 mono_recording_audio_.get(),
3337 &input_resampler_,
3338 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003339}
3340
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003341uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003342Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003343{
3344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3345 "Channel::PrepareEncodeAndSend()");
3346
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003347 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003348 {
3349 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3350 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003351 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003352 }
3353
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003354 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003355 {
3356 MixOrReplaceAudioWithFile(mixingFrequency);
3357 }
3358
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003359 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3360 if (is_muted) {
3361 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003362 }
3363
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003364 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003365 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003366 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003367 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003368 if (_inputExternalMediaCallbackPtr)
3369 {
3370 _inputExternalMediaCallbackPtr->Process(
3371 _channelId,
3372 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003373 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003374 _audioFrame.samples_per_channel_,
3375 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003376 isStereo);
3377 }
3378 }
3379
3380 InsertInbandDtmfTone();
3381
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003382 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003383 size_t length =
3384 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003385 if (is_muted) {
3386 rms_level_.ProcessMuted(length);
3387 } else {
3388 rms_level_.Process(_audioFrame.data_, length);
3389 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003390 }
3391
niklase@google.com470e71d2011-07-07 08:21:25 +00003392 return 0;
3393}
3394
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003395uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003396Channel::EncodeAndSend()
3397{
3398 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3399 "Channel::EncodeAndSend()");
3400
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003401 assert(_audioFrame.num_channels_ <= 2);
3402 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003403 {
3404 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3405 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003406 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003407 }
3408
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003409 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003410
3411 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3412
3413 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003414 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003415 // This call will trigger AudioPacketizationCallback::SendData if encoding
3416 // is done and payload is ready for packetization and transmission.
3417 // Otherwise, it will return without invoking the callback.
3418 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003419 {
3420 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3421 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003422 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003423 }
3424
Peter Kastingb7e50542015-06-11 12:55:50 -07003425 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003426 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003427}
3428
Minyue2013aec2015-05-13 14:14:42 +02003429void Channel::DisassociateSendChannel(int channel_id) {
3430 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3431 Channel* channel = associate_send_channel_.channel();
3432 if (channel && channel->ChannelId() == channel_id) {
3433 // If this channel is associated with a send channel of the specified
3434 // Channel ID, disassociate with it.
3435 ChannelOwner ref(NULL);
3436 associate_send_channel_ = ref;
3437 }
3438}
3439
niklase@google.com470e71d2011-07-07 08:21:25 +00003440int Channel::RegisterExternalMediaProcessing(
3441 ProcessingTypes type,
3442 VoEMediaProcess& processObject)
3443{
3444 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3445 "Channel::RegisterExternalMediaProcessing()");
3446
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003447 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003448
3449 if (kPlaybackPerChannel == type)
3450 {
3451 if (_outputExternalMediaCallbackPtr)
3452 {
3453 _engineStatisticsPtr->SetLastError(
3454 VE_INVALID_OPERATION, kTraceError,
3455 "Channel::RegisterExternalMediaProcessing() "
3456 "output external media already enabled");
3457 return -1;
3458 }
3459 _outputExternalMediaCallbackPtr = &processObject;
3460 _outputExternalMedia = true;
3461 }
3462 else if (kRecordingPerChannel == type)
3463 {
3464 if (_inputExternalMediaCallbackPtr)
3465 {
3466 _engineStatisticsPtr->SetLastError(
3467 VE_INVALID_OPERATION, kTraceError,
3468 "Channel::RegisterExternalMediaProcessing() "
3469 "output external media already enabled");
3470 return -1;
3471 }
3472 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003473 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003474 }
3475 return 0;
3476}
3477
3478int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3479{
3480 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3481 "Channel::DeRegisterExternalMediaProcessing()");
3482
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003483 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003484
3485 if (kPlaybackPerChannel == type)
3486 {
3487 if (!_outputExternalMediaCallbackPtr)
3488 {
3489 _engineStatisticsPtr->SetLastError(
3490 VE_INVALID_OPERATION, kTraceWarning,
3491 "Channel::DeRegisterExternalMediaProcessing() "
3492 "output external media already disabled");
3493 return 0;
3494 }
3495 _outputExternalMedia = false;
3496 _outputExternalMediaCallbackPtr = NULL;
3497 }
3498 else if (kRecordingPerChannel == type)
3499 {
3500 if (!_inputExternalMediaCallbackPtr)
3501 {
3502 _engineStatisticsPtr->SetLastError(
3503 VE_INVALID_OPERATION, kTraceWarning,
3504 "Channel::DeRegisterExternalMediaProcessing() "
3505 "input external media already disabled");
3506 return 0;
3507 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003508 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003509 _inputExternalMediaCallbackPtr = NULL;
3510 }
3511
3512 return 0;
3513}
3514
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003515int Channel::SetExternalMixing(bool enabled) {
3516 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3517 "Channel::SetExternalMixing(enabled=%d)", enabled);
3518
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003519 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003520 {
3521 _engineStatisticsPtr->SetLastError(
3522 VE_INVALID_OPERATION, kTraceError,
3523 "Channel::SetExternalMixing() "
3524 "external mixing cannot be changed while playing.");
3525 return -1;
3526 }
3527
3528 _externalMixing = enabled;
3529
3530 return 0;
3531}
3532
niklase@google.com470e71d2011-07-07 08:21:25 +00003533int
niklase@google.com470e71d2011-07-07 08:21:25 +00003534Channel::GetNetworkStatistics(NetworkStatistics& stats)
3535{
3536 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3537 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003538 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003539}
3540
wu@webrtc.org24301a62013-12-13 19:17:43 +00003541void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3542 audio_coding_->GetDecodingCallStatistics(stats);
3543}
3544
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003545bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3546 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003547 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003548 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003550 "Channel::GetDelayEstimate() no valid estimate.");
3551 return false;
3552 }
3553 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3554 _recPacketDelayMs;
3555 *playout_buffer_delay_ms = playout_delay_ms_;
3556 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3557 "Channel::GetDelayEstimate()");
3558 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003559}
3560
deadbeef74375882015-08-13 12:09:10 -07003561int Channel::LeastRequiredDelayMs() const {
3562 return audio_coding_->LeastRequiredDelayMs();
3563}
3564
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003565int Channel::SetInitialPlayoutDelay(int delay_ms)
3566{
3567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3568 "Channel::SetInitialPlayoutDelay()");
3569 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3570 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3571 {
3572 _engineStatisticsPtr->SetLastError(
3573 VE_INVALID_ARGUMENT, kTraceError,
3574 "SetInitialPlayoutDelay() invalid min delay");
3575 return -1;
3576 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003577 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003578 {
3579 _engineStatisticsPtr->SetLastError(
3580 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3581 "SetInitialPlayoutDelay() failed to set min playout delay");
3582 return -1;
3583 }
3584 return 0;
3585}
3586
3587
niklase@google.com470e71d2011-07-07 08:21:25 +00003588int
3589Channel::SetMinimumPlayoutDelay(int delayMs)
3590{
3591 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3592 "Channel::SetMinimumPlayoutDelay()");
3593 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3594 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3595 {
3596 _engineStatisticsPtr->SetLastError(
3597 VE_INVALID_ARGUMENT, kTraceError,
3598 "SetMinimumPlayoutDelay() invalid min delay");
3599 return -1;
3600 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003601 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003602 {
3603 _engineStatisticsPtr->SetLastError(
3604 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3605 "SetMinimumPlayoutDelay() failed to set min playout delay");
3606 return -1;
3607 }
3608 return 0;
3609}
3610
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003611int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3612 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3613 "Channel::GetPlayoutTimestamp()");
deadbeef74375882015-08-13 12:09:10 -07003614 uint32_t playout_timestamp_rtp = 0;
3615 {
3616 CriticalSectionScoped cs(video_sync_lock_.get());
3617 playout_timestamp_rtp = playout_timestamp_rtp_;
3618 }
3619 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003620 _engineStatisticsPtr->SetLastError(
3621 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3622 "GetPlayoutTimestamp() failed to retrieve timestamp");
3623 return -1;
3624 }
deadbeef74375882015-08-13 12:09:10 -07003625 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003626 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3627 VoEId(_instanceId,_channelId),
3628 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3629 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003630}
3631
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003632int Channel::SetInitTimestamp(unsigned int timestamp) {
3633 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003634 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003635 if (channel_state_.Get().sending) {
3636 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3637 "SetInitTimestamp() already sending");
3638 return -1;
3639 }
3640 _rtpRtcpModule->SetStartTimestamp(timestamp);
3641 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003642}
3643
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003644int Channel::SetInitSequenceNumber(short sequenceNumber) {
3645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3646 "Channel::SetInitSequenceNumber()");
3647 if (channel_state_.Get().sending) {
3648 _engineStatisticsPtr->SetLastError(
3649 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3650 return -1;
3651 }
3652 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3653 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003654}
3655
3656int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003657Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003658{
3659 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3660 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003661 *rtpRtcpModule = _rtpRtcpModule.get();
3662 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003663 return 0;
3664}
3665
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003666// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3667// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003668int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003669Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003670{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003671 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003672 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003673
3674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003675 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003676
3677 if (_inputFilePlayerPtr == NULL)
3678 {
3679 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3680 VoEId(_instanceId, _channelId),
3681 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3682 " doesnt exist");
3683 return -1;
3684 }
3685
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003686 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003687 fileSamples,
3688 mixingFrequency) == -1)
3689 {
3690 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3691 VoEId(_instanceId, _channelId),
3692 "Channel::MixOrReplaceAudioWithFile() file mixing "
3693 "failed");
3694 return -1;
3695 }
3696 if (fileSamples == 0)
3697 {
3698 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3699 VoEId(_instanceId, _channelId),
3700 "Channel::MixOrReplaceAudioWithFile() file is ended");
3701 return 0;
3702 }
3703 }
3704
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003705 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003706
3707 if (_mixFileWithMicrophone)
3708 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003709 // Currently file stream is always mono.
3710 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003711 MixWithSat(_audioFrame.data_,
3712 _audioFrame.num_channels_,
3713 fileBuffer.get(),
3714 1,
3715 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003716 }
3717 else
3718 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003719 // Replace ACM audio with file.
3720 // Currently file stream is always mono.
3721 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003723 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003724 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003725 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003726 mixingFrequency,
3727 AudioFrame::kNormalSpeech,
3728 AudioFrame::kVadUnknown,
3729 1);
3730
3731 }
3732 return 0;
3733}
3734
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003735int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003736Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003737 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003738{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003739 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003740
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003741 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003742 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003743
3744 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003745 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003746
3747 if (_outputFilePlayerPtr == NULL)
3748 {
3749 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3750 VoEId(_instanceId, _channelId),
3751 "Channel::MixAudioWithFile() file mixing failed");
3752 return -1;
3753 }
3754
3755 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003756 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 fileSamples,
3758 mixingFrequency) == -1)
3759 {
3760 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3761 VoEId(_instanceId, _channelId),
3762 "Channel::MixAudioWithFile() file mixing failed");
3763 return -1;
3764 }
3765 }
3766
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003767 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003768 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003769 // Currently file stream is always mono.
3770 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003771 MixWithSat(audioFrame.data_,
3772 audioFrame.num_channels_,
3773 fileBuffer.get(),
3774 1,
3775 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 }
3777 else
3778 {
3779 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003780 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3781 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003782 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003783 return -1;
3784 }
3785
3786 return 0;
3787}
3788
3789int
3790Channel::InsertInbandDtmfTone()
3791{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003792 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003793 if (_inbandDtmfQueue.PendingDtmf() &&
3794 !_inbandDtmfGenerator.IsAddingTone() &&
3795 _inbandDtmfGenerator.DelaySinceLastTone() >
3796 kMinTelephoneEventSeparationMs)
3797 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003798 int8_t eventCode(0);
3799 uint16_t lengthMs(0);
3800 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003801
3802 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3803 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3804 if (_playInbandDtmfEvent)
3805 {
3806 // Add tone to output mixer using a reduced length to minimize
3807 // risk of echo.
3808 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3809 attenuationDb);
3810 }
3811 }
3812
3813 if (_inbandDtmfGenerator.IsAddingTone())
3814 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003815 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003816 _inbandDtmfGenerator.GetSampleRate(frequency);
3817
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003818 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003819 {
3820 // Update sample rate of Dtmf tone since the mixing frequency
3821 // has changed.
3822 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003823 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003824 // Reset the tone to be added taking the new sample rate into
3825 // account.
3826 _inbandDtmfGenerator.ResetTone();
3827 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003828
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003829 int16_t toneBuffer[320];
3830 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003831 // Get 10ms tone segment and set time since last tone to zero
3832 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3833 {
3834 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3835 VoEId(_instanceId, _channelId),
3836 "Channel::EncodeAndSend() inserting Dtmf failed");
3837 return -1;
3838 }
3839
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003840 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003841 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003842 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003843 sample++)
3844 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003845 for (int channel = 0;
3846 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003847 channel++)
3848 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003849 const size_t index =
3850 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003851 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003852 }
3853 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003854
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003855 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003856 } else
3857 {
3858 // Add 10ms to "delay-since-last-tone" counter
3859 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3860 }
3861 return 0;
3862}
3863
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003864int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003865Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003866{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003867 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003868 if (_transportPtr == NULL)
3869 {
3870 return -1;
3871 }
3872 if (!RTCP)
3873 {
Peter Boströmac547a62015-09-17 23:03:57 +02003874 return _transportPtr->SendPacket(data, len);
niklase@google.com470e71d2011-07-07 08:21:25 +00003875 }
3876 else
3877 {
Peter Boströmac547a62015-09-17 23:03:57 +02003878 return _transportPtr->SendRTCPPacket(data, len);
niklase@google.com470e71d2011-07-07 08:21:25 +00003879 }
3880}
3881
deadbeef74375882015-08-13 12:09:10 -07003882void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3883 uint32_t playout_timestamp = 0;
3884
3885 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3886 // This can happen if this channel has not been received any RTP packet. In
3887 // this case, NetEq is not capable of computing playout timestamp.
3888 return;
3889 }
3890
3891 uint16_t delay_ms = 0;
3892 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3893 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3894 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3895 " delay from the ADM");
3896 _engineStatisticsPtr->SetLastError(
3897 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3898 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3899 return;
3900 }
3901
3902 jitter_buffer_playout_timestamp_ = playout_timestamp;
3903
3904 // Remove the playout delay.
3905 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3906
3907 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3908 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3909 playout_timestamp);
3910
3911 {
3912 CriticalSectionScoped cs(video_sync_lock_.get());
3913 if (rtcp) {
3914 playout_timestamp_rtcp_ = playout_timestamp;
3915 } else {
3916 playout_timestamp_rtp_ = playout_timestamp;
3917 }
3918 playout_delay_ms_ = delay_ms;
3919 }
3920}
3921
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003922// Called for incoming RTP packets after successful RTP header parsing.
3923void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3924 uint16_t sequence_number) {
3925 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3926 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3927 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003928
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003929 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003930 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003931
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003932 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3933 // every incoming packet.
3934 uint32_t timestamp_diff_ms = (rtp_timestamp -
3935 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003936 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3937 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3938 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3939 // timestamp, the resulting difference is negative, but is set to zero.
3940 // This can happen when a network glitch causes a packet to arrive late,
3941 // and during long comfort noise periods with clock drift.
3942 timestamp_diff_ms = 0;
3943 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003944
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003945 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3946 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003947
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003948 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003949
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003950 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003951
deadbeef74375882015-08-13 12:09:10 -07003952 {
3953 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003954
deadbeef74375882015-08-13 12:09:10 -07003955 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3956 _recPacketDelayMs = packet_delay_ms;
3957 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003958
deadbeef74375882015-08-13 12:09:10 -07003959 if (_average_jitter_buffer_delay_us == 0) {
3960 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3961 return;
3962 }
3963
3964 // Filter average delay value using exponential filter (alpha is
3965 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3966 // risk of rounding error) and compensate for it in GetDelayEstimate()
3967 // later.
3968 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3969 1000 * timestamp_diff_ms + 500) / 8;
3970 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003971}
3972
3973void
3974Channel::RegisterReceiveCodecsToRTPModule()
3975{
3976 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3977 "Channel::RegisterReceiveCodecsToRTPModule()");
3978
3979
3980 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003981 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003982
3983 for (int idx = 0; idx < nSupportedCodecs; idx++)
3984 {
3985 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003986 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003987 (rtp_receiver_->RegisterReceivePayload(
3988 codec.plname,
3989 codec.pltype,
3990 codec.plfreq,
3991 codec.channels,
3992 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00003993 {
3994 WEBRTC_TRACE(
3995 kTraceWarning,
3996 kTraceVoice,
3997 VoEId(_instanceId, _channelId),
3998 "Channel::RegisterReceiveCodecsToRTPModule() unable"
3999 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4000 codec.plname, codec.pltype, codec.plfreq,
4001 codec.channels, codec.rate);
4002 }
4003 else
4004 {
4005 WEBRTC_TRACE(
4006 kTraceInfo,
4007 kTraceVoice,
4008 VoEId(_instanceId, _channelId),
4009 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004010 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004011 "receiver",
4012 codec.plname, codec.pltype, codec.plfreq,
4013 codec.channels, codec.rate);
4014 }
4015 }
4016}
4017
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004018// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004019int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004020 CodecInst codec;
4021 bool found_red = false;
4022
4023 // Get default RED settings from the ACM database
4024 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4025 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004026 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004027 if (!STR_CASE_CMP(codec.plname, "RED")) {
4028 found_red = true;
4029 break;
4030 }
4031 }
4032
4033 if (!found_red) {
4034 _engineStatisticsPtr->SetLastError(
4035 VE_CODEC_ERROR, kTraceError,
4036 "SetRedPayloadType() RED is not supported");
4037 return -1;
4038 }
4039
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004040 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004041 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004042 _engineStatisticsPtr->SetLastError(
4043 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4044 "SetRedPayloadType() RED registration in ACM module failed");
4045 return -1;
4046 }
4047
4048 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4049 _engineStatisticsPtr->SetLastError(
4050 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4051 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4052 return -1;
4053 }
4054 return 0;
4055}
4056
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004057int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4058 unsigned char id) {
4059 int error = 0;
4060 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4061 if (enable) {
4062 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4063 }
4064 return error;
4065}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004066
wu@webrtc.org94454b72014-06-05 20:34:08 +00004067int32_t Channel::GetPlayoutFrequency() {
4068 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4069 CodecInst current_recive_codec;
4070 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4071 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4072 // Even though the actual sampling rate for G.722 audio is
4073 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4074 // 8,000 Hz because that value was erroneously assigned in
4075 // RFC 1890 and must remain unchanged for backward compatibility.
4076 playout_frequency = 8000;
4077 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4078 // We are resampling Opus internally to 32,000 Hz until all our
4079 // DSP routines can operate at 48,000 Hz, but the RTP clock
4080 // rate for the Opus payload format is standardized to 48,000 Hz,
4081 // because that is the maximum supported decoding sampling rate.
4082 playout_frequency = 48000;
4083 }
4084 }
4085 return playout_frequency;
4086}
4087
Minyue2013aec2015-05-13 14:14:42 +02004088int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004089 RTCPMethod method = _rtpRtcpModule->RTCP();
4090 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004091 return 0;
4092 }
4093 std::vector<RTCPReportBlock> report_blocks;
4094 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004095
4096 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004097 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004098 if (allow_associate_channel) {
4099 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4100 Channel* channel = associate_send_channel_.channel();
4101 // Tries to get RTT from an associated channel. This is important for
4102 // receive-only channels.
4103 if (channel) {
4104 // To prevent infinite recursion and deadlock, calling GetRTT of
4105 // associate channel should always use "false" for argument:
4106 // |allow_associate_channel|.
4107 rtt = channel->GetRTT(false);
4108 }
4109 }
4110 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004111 }
4112
4113 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4114 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4115 for (; it != report_blocks.end(); ++it) {
4116 if (it->remoteSSRC == remoteSSRC)
4117 break;
4118 }
4119 if (it == report_blocks.end()) {
4120 // We have not received packets with SSRC matching the report blocks.
4121 // To calculate RTT we try with the SSRC of the first report block.
4122 // This is very important for send-only channels where we don't know
4123 // the SSRC of the other end.
4124 remoteSSRC = report_blocks[0].remoteSSRC;
4125 }
Minyue2013aec2015-05-13 14:14:42 +02004126
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004127 int64_t avg_rtt = 0;
4128 int64_t max_rtt= 0;
4129 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004130 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4131 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004132 return 0;
4133 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004134 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004135}
4136
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004137} // namespace voe
4138} // namespace webrtc