blob: a8fb1790d730ddbe30e47abd6843a1614a0652e4 [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
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000221Channel::SendPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000222{
223 channel = VoEChannelId(channel);
224 assert(channel == _channelId);
225
226 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000227 "Channel::SendPacket(channel=%d, len=%" PRIuS ")", channel,
228 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000229
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000230 CriticalSectionScoped cs(&_callbackCritSect);
231
niklase@google.com470e71d2011-07-07 08:21:25 +0000232 if (_transportPtr == NULL)
233 {
234 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
235 "Channel::SendPacket() failed to send RTP packet due to"
236 " invalid transport object");
237 return -1;
238 }
239
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000240 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000241 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000242
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000243 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
244 bufferLength);
245 if (n < 0) {
246 std::string transport_name =
247 _externalTransport ? "external transport" : "WebRtc sockets";
248 WEBRTC_TRACE(kTraceError, kTraceVoice,
249 VoEId(_instanceId,_channelId),
250 "Channel::SendPacket() RTP transmission using %s failed",
251 transport_name.c_str());
252 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000254 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000255}
256
257int
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000258Channel::SendRTCPPacket(int channel, const void *data, size_t len)
niklase@google.com470e71d2011-07-07 08:21:25 +0000259{
260 channel = VoEChannelId(channel);
261 assert(channel == _channelId);
262
263 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000264 "Channel::SendRTCPPacket(channel=%d, len=%" PRIuS ")", channel,
265 len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000267 CriticalSectionScoped cs(&_callbackCritSect);
268 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000270 WEBRTC_TRACE(kTraceError, kTraceVoice,
271 VoEId(_instanceId,_channelId),
272 "Channel::SendRTCPPacket() failed to send RTCP packet"
273 " due to invalid transport object");
274 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 }
276
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000277 uint8_t* bufferToSendPtr = (uint8_t*)data;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000278 size_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000279
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000280 int n = _transportPtr->SendRTCPPacket(channel,
281 bufferToSendPtr,
282 bufferLength);
283 if (n < 0) {
284 std::string transport_name =
285 _externalTransport ? "external transport" : "WebRtc sockets";
286 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
287 VoEId(_instanceId,_channelId),
288 "Channel::SendRTCPPacket() transmission using %s failed",
289 transport_name.c_str());
290 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000292 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293}
294
295void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000296Channel::OnPlayTelephoneEvent(int32_t id,
297 uint8_t event,
298 uint16_t lengthMs,
299 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000300{
301 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
302 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000303 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
305 if (!_playOutbandDtmfEvent || (event > 15))
306 {
307 // Ignore callback since feedback is disabled or event is not a
308 // Dtmf tone event.
309 return;
310 }
311
312 assert(_outputMixerPtr != NULL);
313
314 // Start playing out the Dtmf tone (if playout is enabled).
315 // Reduce length of tone with 80ms to the reduce risk of echo.
316 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
317}
318
319void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000320Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000321{
322 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
323 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000324 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000325
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000326 // Update ssrc so that NTP for AV sync can be updated.
327 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000328}
329
pbos@webrtc.org92135212013-05-14 08:31:39 +0000330void Channel::OnIncomingCSRCChanged(int32_t id,
331 uint32_t CSRC,
332 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000333{
334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
335 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
336 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000337}
338
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000339int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000340Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000341 int32_t id,
342 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000343 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000344 int frequency,
345 uint8_t channels,
346 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000347{
348 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
349 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
350 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
351 id, payloadType, payloadName, frequency, channels, rate);
352
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000353 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000354
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000355 CodecInst receiveCodec = {0};
356 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000357
358 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000359 receiveCodec.plfreq = frequency;
360 receiveCodec.channels = channels;
361 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000362 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000363
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000364 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365 receiveCodec.pacsize = dummyCodec.pacsize;
366
367 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000368 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000369 {
370 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000371 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 "Channel::OnInitializeDecoder() invalid codec ("
373 "pt=%d, name=%s) received - 1", payloadType, payloadName);
374 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
375 return -1;
376 }
377
378 return 0;
379}
380
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000381int32_t
382Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000383 size_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 const WebRtcRTPHeader* rtpHeader)
385{
386 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000387 "Channel::OnReceivedPayloadData(payloadSize=%" PRIuS ","
niklase@google.com470e71d2011-07-07 08:21:25 +0000388 " payloadType=%u, audioChannel=%u)",
389 payloadSize,
390 rtpHeader->header.payloadType,
391 rtpHeader->type.Audio.channel);
392
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000393 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 {
395 // Avoid inserting into NetEQ when we are not playing. Count the
396 // packet as discarded.
397 WEBRTC_TRACE(kTraceStream, kTraceVoice,
398 VoEId(_instanceId, _channelId),
399 "received packet is discarded since playing is not"
400 " activated");
401 _numberOfDiscardedPackets++;
402 return 0;
403 }
404
405 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000406 if (audio_coding_->IncomingPacket(payloadData,
407 payloadSize,
408 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 {
410 _engineStatisticsPtr->SetLastError(
411 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
412 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
413 return -1;
414 }
415
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000416 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 UpdatePacketDelay(rtpHeader->header.timestamp,
418 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000419
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000420 int64_t round_trip_time = 0;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000421 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
422 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000423
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000424 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000425 round_trip_time);
426 if (!nack_list.empty()) {
427 // Can't use nack_list.data() since it's not supported by all
428 // compilers.
429 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000430 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000431 return 0;
432}
433
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000434bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000435 size_t rtp_packet_length) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000436 RTPHeader header;
437 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
438 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
439 "IncomingPacket invalid RTP header");
440 return false;
441 }
442 header.payload_type_frequency =
443 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
444 if (header.payload_type_frequency < 0)
445 return false;
446 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
447}
448
minyuel0f4b3732015-08-31 16:04:32 +0200449int32_t Channel::GetAudioFrame(int32_t id, AudioFrame* audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000450{
451 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
452 "Channel::GetAudioFrame(id=%d)", id);
453
Ivo Creusenae856f22015-09-17 16:30:16 +0200454 if (event_log_) {
455 unsigned int ssrc;
456 RTC_CHECK_EQ(GetLocalSSRC(ssrc), 0);
457 event_log_->LogAudioPlayout(ssrc);
458 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
minyuel0f4b3732015-08-31 16:04:32 +0200460 if (audio_coding_->PlayoutData10Ms(audioFrame->sample_rate_hz_,
461 audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000462 {
463 WEBRTC_TRACE(kTraceError, kTraceVoice,
464 VoEId(_instanceId,_channelId),
465 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000466 // In all likelihood, the audio in this frame is garbage. We return an
467 // error so that the audio mixer module doesn't add it to the mix. As
468 // a result, it won't be played out and the actions skipped here are
469 // irrelevant.
470 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 }
472
473 if (_RxVadDetection)
474 {
minyuel0f4b3732015-08-31 16:04:32 +0200475 UpdateRxVadDetection(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000476 }
477
478 // Convert module ID to internal VoE channel ID
minyuel0f4b3732015-08-31 16:04:32 +0200479 audioFrame->id_ = VoEChannelId(audioFrame->id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 // Store speech type for dead-or-alive detection
minyuel0f4b3732015-08-31 16:04:32 +0200481 _outputSpeechType = audioFrame->speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000482
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000483 ChannelState::State state = channel_state_.Get();
484
485 if (state.rx_apm_is_enabled) {
minyuel0f4b3732015-08-31 16:04:32 +0200486 int err = rx_audioproc_->ProcessStream(audioFrame);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000487 if (err) {
488 LOG(LS_ERROR) << "ProcessStream() error: " << err;
489 assert(false);
490 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000491 }
492
wu@webrtc.org63420662013-10-17 18:28:55 +0000493 float output_gain = 1.0f;
494 float left_pan = 1.0f;
495 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000497 CriticalSectionScoped cs(&volume_settings_critsect_);
498 output_gain = _outputGain;
499 left_pan = _panLeft;
500 right_pan= _panRight;
501 }
502
503 // Output volume scaling
504 if (output_gain < 0.99f || output_gain > 1.01f)
505 {
minyuel0f4b3732015-08-31 16:04:32 +0200506 AudioFrameOperations::ScaleWithSat(output_gain, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000507 }
508
509 // Scale left and/or right channel(s) if stereo and master balance is
510 // active
511
wu@webrtc.org63420662013-10-17 18:28:55 +0000512 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000513 {
minyuel0f4b3732015-08-31 16:04:32 +0200514 if (audioFrame->num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 {
516 // Emulate stereo mode since panning is active.
517 // The mono signal is copied to both left and right channels here.
minyuel0f4b3732015-08-31 16:04:32 +0200518 AudioFrameOperations::MonoToStereo(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 }
520 // For true stereo mode (when we are receiving a stereo signal), no
521 // action is needed.
522
523 // Do the panning operation (the audio frame contains stereo at this
524 // stage)
minyuel0f4b3732015-08-31 16:04:32 +0200525 AudioFrameOperations::Scale(left_pan, right_pan, *audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000526 }
527
528 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000529 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 {
minyuel0f4b3732015-08-31 16:04:32 +0200531 MixAudioWithFile(*audioFrame, audioFrame->sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000532 }
533
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 // External media
535 if (_outputExternalMedia)
536 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000537 CriticalSectionScoped cs(&_callbackCritSect);
minyuel0f4b3732015-08-31 16:04:32 +0200538 const bool isStereo = (audioFrame->num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 if (_outputExternalMediaCallbackPtr)
540 {
541 _outputExternalMediaCallbackPtr->Process(
542 _channelId,
543 kPlaybackPerChannel,
minyuel0f4b3732015-08-31 16:04:32 +0200544 (int16_t*)audioFrame->data_,
545 audioFrame->samples_per_channel_,
546 audioFrame->sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000547 isStereo);
548 }
549 }
550
551 // Record playout if enabled
552 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000553 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000554
555 if (_outputFileRecording && _outputFileRecorderPtr)
556 {
minyuel0f4b3732015-08-31 16:04:32 +0200557 _outputFileRecorderPtr->RecordAudioToFile(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 }
559 }
560
561 // Measure audio level (0-9)
minyuel0f4b3732015-08-31 16:04:32 +0200562 _outputAudioLevel.ComputeLevel(*audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000563
minyuel0f4b3732015-08-31 16:04:32 +0200564 if (capture_start_rtp_time_stamp_ < 0 && audioFrame->timestamp_ != 0) {
wu@webrtc.org94454b72014-06-05 20:34:08 +0000565 // The first frame with a valid rtp timestamp.
minyuel0f4b3732015-08-31 16:04:32 +0200566 capture_start_rtp_time_stamp_ = audioFrame->timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000567 }
568
569 if (capture_start_rtp_time_stamp_ >= 0) {
570 // audioFrame.timestamp_ should be valid from now on.
571
572 // Compute elapsed time.
573 int64_t unwrap_timestamp =
minyuel0f4b3732015-08-31 16:04:32 +0200574 rtp_ts_wraparound_handler_->Unwrap(audioFrame->timestamp_);
575 audioFrame->elapsed_time_ms_ =
wu@webrtc.org94454b72014-06-05 20:34:08 +0000576 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
577 (GetPlayoutFrequency() / 1000);
578
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000579 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000580 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000581 // Compute ntp time.
minyuel0f4b3732015-08-31 16:04:32 +0200582 audioFrame->ntp_time_ms_ = ntp_estimator_.Estimate(
583 audioFrame->timestamp_);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000584 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
minyuel0f4b3732015-08-31 16:04:32 +0200585 if (audioFrame->ntp_time_ms_ > 0) {
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000586 // Compute |capture_start_ntp_time_ms_| so that
587 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
588 capture_start_ntp_time_ms_ =
minyuel0f4b3732015-08-31 16:04:32 +0200589 audioFrame->ntp_time_ms_ - audioFrame->elapsed_time_ms_;
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000590 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000591 }
592 }
593
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 return 0;
595}
596
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000597int32_t
minyuel0f4b3732015-08-31 16:04:32 +0200598Channel::NeededFrequency(int32_t id) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000599{
600 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
601 "Channel::NeededFrequency(id=%d)", id);
602
603 int highestNeeded = 0;
604
605 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000606 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000607
608 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000609 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000611 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }
613 else
614 {
615 highestNeeded = receiveFrequency;
616 }
617
618 // Special case, if we're playing a file on the playout side
619 // we take that frequency into consideration as well
620 // This is not needed on sending side, since the codec will
621 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000622 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000624 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000625 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 {
627 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
628 {
629 highestNeeded=_outputFilePlayerPtr->Frequency();
630 }
631 }
632 }
633
634 return(highestNeeded);
635}
636
ivocb04965c2015-09-09 00:09:43 -0700637int32_t Channel::CreateChannel(Channel*& channel,
638 int32_t channelId,
639 uint32_t instanceId,
640 RtcEventLog* const event_log,
641 const Config& config) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
643 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
644 channelId, instanceId);
645
ivocb04965c2015-09-09 00:09:43 -0700646 channel = new Channel(channelId, instanceId, event_log, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 if (channel == NULL)
648 {
649 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
650 VoEId(instanceId,channelId),
651 "Channel::CreateChannel() unable to allocate memory for"
652 " channel");
653 return -1;
654 }
655 return 0;
656}
657
658void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000659Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000660{
661 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
662 "Channel::PlayNotification(id=%d, durationMs=%d)",
663 id, durationMs);
664
665 // Not implement yet
666}
667
668void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000669Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670{
671 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
672 "Channel::RecordNotification(id=%d, durationMs=%d)",
673 id, durationMs);
674
675 // Not implement yet
676}
677
678void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000679Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000680{
681 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
682 "Channel::PlayFileEnded(id=%d)", id);
683
684 if (id == _inputFilePlayerId)
685 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000686 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000687 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
688 VoEId(_instanceId,_channelId),
689 "Channel::PlayFileEnded() => input file player module is"
690 " shutdown");
691 }
692 else if (id == _outputFilePlayerId)
693 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000694 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
696 VoEId(_instanceId,_channelId),
697 "Channel::PlayFileEnded() => output file player module is"
698 " shutdown");
699 }
700}
701
702void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000703Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000704{
705 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
706 "Channel::RecordFileEnded(id=%d)", id);
707
708 assert(id == _outputFileRecorderId);
709
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000710 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000711
712 _outputFileRecording = false;
713 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
714 VoEId(_instanceId,_channelId),
715 "Channel::RecordFileEnded() => output file recorder module is"
716 " shutdown");
717}
718
pbos@webrtc.org92135212013-05-14 08:31:39 +0000719Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000720 uint32_t instanceId,
ivocb04965c2015-09-09 00:09:43 -0700721 RtcEventLog* const event_log,
722 const Config& config)
723 : _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000725 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000727 _channelId(channelId),
Ivo Creusenae856f22015-09-17 16:30:16 +0200728 event_log_(event_log),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000729 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000730 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000731 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
ivocb04965c2015-09-09 00:09:43 -0700732 rtp_receive_statistics_(
733 ReceiveStatistics::Create(Clock::GetRealTimeClock())),
734 rtp_receiver_(
735 RtpReceiver::CreateAudioReceiver(VoEModuleId(instanceId, channelId),
736 Clock::GetRealTimeClock(),
737 this,
738 this,
739 this,
740 rtp_payload_registry_.get())),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000741 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000742 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 _externalTransport(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000744 _inputFilePlayerPtr(NULL),
745 _outputFilePlayerPtr(NULL),
746 _outputFileRecorderPtr(NULL),
747 // Avoid conflict with other channels by adding 1024 - 1026,
748 // won't use as much as 1024 channels.
749 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
750 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
751 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000752 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000753 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
754 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000755 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 _inputExternalMediaCallbackPtr(NULL),
757 _outputExternalMediaCallbackPtr(NULL),
ivocb04965c2015-09-09 00:09:43 -0700758 _timeStamp(0), // This is just an offset, RTP module will add it's own
759 // random offset
xians@google.com22963ab2011-08-03 12:40:23 +0000760 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000761 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000762 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000763 playout_timestamp_rtp_(0),
764 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000765 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000766 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000767 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000768 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000769 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
770 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000771 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000772 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000773 _outputMixerPtr(NULL),
774 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000775 _moduleProcessThreadPtr(NULL),
776 _audioDeviceModulePtr(NULL),
777 _voiceEngineObserverPtr(NULL),
778 _callbackCritSectPtr(NULL),
779 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000780 _rxVadObserverPtr(NULL),
781 _oldVadDecision(-1),
782 _sendFrameType(0),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000783 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000784 _mixFileWithMicrophone(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000785 _mute(false),
786 _panLeft(1.0f),
787 _panRight(1.0f),
788 _outputGain(1.0f),
789 _playOutbandDtmfEvent(false),
790 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 _lastLocalTimeStamp(0),
792 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000793 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000794 _outputSpeechType(AudioFrame::kNormalSpeech),
deadbeef74375882015-08-13 12:09:10 -0700795 video_sync_lock_(CriticalSectionWrapper::CreateCriticalSection()),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000796 _average_jitter_buffer_delay_us(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 _previousTimestamp(0),
798 _recPacketDelayMs(20),
799 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000800 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000801 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000802 restored_packet_in_use_(false),
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000803 rtcp_observer_(new VoERtcpObserver(this)),
Minyue2013aec2015-05-13 14:14:42 +0200804 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock())),
805 assoc_send_channel_lock_(CriticalSectionWrapper::CreateCriticalSection()),
ivocb04965c2015-09-09 00:09:43 -0700806 associate_send_channel_(ChannelOwner(nullptr)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
808 "Channel::Channel() - ctor");
Henrik Lundin64dad832015-05-11 12:44:23 +0200809 AudioCodingModule::Config acm_config;
810 acm_config.id = VoEModuleId(instanceId, channelId);
811 if (config.Get<NetEqCapacityConfig>().enabled) {
812 // Clamping the buffer capacity at 20 packets. While going lower will
813 // probably work, it makes little sense.
814 acm_config.neteq_config.max_packets_in_buffer =
815 std::max(20, config.Get<NetEqCapacityConfig>().capacity);
816 }
Henrik Lundin5263b3c2015-06-01 10:29:41 +0200817 acm_config.neteq_config.enable_fast_accelerate =
818 config.Get<NetEqFastAccelerate>().enabled;
Henrik Lundin64dad832015-05-11 12:44:23 +0200819 audio_coding_.reset(AudioCodingModule::Create(acm_config));
820
niklase@google.com470e71d2011-07-07 08:21:25 +0000821 _inbandDtmfQueue.ResetDtmf();
822 _inbandDtmfGenerator.Init();
823 _outputAudioLevel.Clear();
824
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000825 RtpRtcp::Configuration configuration;
826 configuration.id = VoEModuleId(instanceId, channelId);
827 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000828 configuration.outgoing_transport = this;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000829 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000830 configuration.receive_statistics = rtp_receive_statistics_.get();
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +0000831 configuration.bandwidth_callback = rtcp_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000832
833 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000834
835 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
836 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
837 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000838
839 Config audioproc_config;
840 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
841 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000842}
843
844Channel::~Channel()
845{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000846 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
848 "Channel::~Channel() - dtor");
849
850 if (_outputExternalMedia)
851 {
852 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
853 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000854 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 {
856 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
857 }
858 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 StopPlayout();
860
861 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000862 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 if (_inputFilePlayerPtr)
864 {
865 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
866 _inputFilePlayerPtr->StopPlayingFile();
867 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
868 _inputFilePlayerPtr = NULL;
869 }
870 if (_outputFilePlayerPtr)
871 {
872 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
873 _outputFilePlayerPtr->StopPlayingFile();
874 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
875 _outputFilePlayerPtr = NULL;
876 }
877 if (_outputFileRecorderPtr)
878 {
879 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
880 _outputFileRecorderPtr->StopRecording();
881 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
882 _outputFileRecorderPtr = NULL;
883 }
884 }
885
886 // The order to safely shutdown modules in a channel is:
887 // 1. De-register callbacks in modules
888 // 2. De-register modules in process thread
889 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000890 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000891 {
892 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
893 VoEId(_instanceId,_channelId),
894 "~Channel() failed to de-register transport callback"
895 " (Audio coding module)");
896 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000897 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 {
899 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
900 VoEId(_instanceId,_channelId),
901 "~Channel() failed to de-register VAD callback"
902 " (Audio coding module)");
903 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 // De-register modules in process thread
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000905 _moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get());
906
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 // End of modules shutdown
908
909 // Delete other objects
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000912 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000913}
914
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000915int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000916Channel::Init()
917{
918 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
919 "Channel::Init()");
920
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000921 channel_state_.Reset();
922
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 // --- Initial sanity
924
925 if ((_engineStatisticsPtr == NULL) ||
926 (_moduleProcessThreadPtr == NULL))
927 {
928 WEBRTC_TRACE(kTraceError, kTraceVoice,
929 VoEId(_instanceId,_channelId),
930 "Channel::Init() must call SetEngineInformation() first");
931 return -1;
932 }
933
934 // --- Add modules to process thread (for periodic schedulation)
935
tommi@webrtc.org3985f012015-02-27 13:36:34 +0000936 _moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get());
937
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +0000938 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +0000939
Henrik Lundin45c64492015-03-30 19:00:44 +0200940 if ((audio_coding_->InitializeReceiver() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 // out-of-band Dtmf tones are played out by default
kwiberg1f9baab2015-09-16 19:29:43 -0700942 || (audio_coding_->SetDtmfPlayoutStatus(true) == -1)) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 _engineStatisticsPtr->SetLastError(
944 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
945 "Channel::Init() unable to initialize the ACM - 1");
946 return -1;
947 }
948
949 // --- RTP/RTCP module initialization
950
951 // Ensure that RTCP is enabled by default for the created channel.
952 // Note that, the module will keep generating RTCP until it is explicitly
953 // disabled by the user.
954 // After StopListen (when no sockets exists), RTCP packets will no longer
955 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000956 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
957 // RTCP is enabled by default.
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000958 _rtpRtcpModule->SetRTCPStatus(kRtcpCompound);
959 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000961 (audio_coding_->RegisterTransportCallback(this) == -1) ||
962 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000963
964 if (fail)
965 {
966 _engineStatisticsPtr->SetLastError(
967 VE_CANNOT_INIT_CHANNEL, kTraceError,
968 "Channel::Init() callbacks not registered");
969 return -1;
970 }
971
972 // --- Register all supported codecs to the receiving side of the
973 // RTP/RTCP module
974
975 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000976 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +0000977
978 for (int idx = 0; idx < nSupportedCodecs; idx++)
979 {
980 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000981 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000982 (rtp_receiver_->RegisterReceivePayload(
983 codec.plname,
984 codec.pltype,
985 codec.plfreq,
986 codec.channels,
987 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +0000988 {
989 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
990 VoEId(_instanceId,_channelId),
991 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
992 "to RTP/RTCP receiver",
993 codec.plname, codec.pltype, codec.plfreq,
994 codec.channels, codec.rate);
995 }
996 else
997 {
998 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
999 VoEId(_instanceId,_channelId),
1000 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1001 "the RTP/RTCP receiver",
1002 codec.plname, codec.pltype, codec.plfreq,
1003 codec.channels, codec.rate);
1004 }
1005
1006 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001007 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 {
1009 SetSendCodec(codec);
1010 }
1011
1012 // Register default PT for outband 'telephone-event'
1013 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1014 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001015 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001016 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 {
1018 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1019 VoEId(_instanceId,_channelId),
1020 "Channel::Init() failed to register outband "
1021 "'telephone-event' (%d/%d) correctly",
1022 codec.pltype, codec.plfreq);
1023 }
1024 }
1025
1026 if (!STR_CASE_CMP(codec.plname, "CN"))
1027 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001028 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1029 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001030 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001031 {
1032 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1033 VoEId(_instanceId,_channelId),
1034 "Channel::Init() failed to register CN (%d/%d) "
1035 "correctly - 1",
1036 codec.pltype, codec.plfreq);
1037 }
1038 }
1039#ifdef WEBRTC_CODEC_RED
1040 // Register RED to the receiving side of the ACM.
1041 // We will not receive an OnInitializeDecoder() callback for RED.
1042 if (!STR_CASE_CMP(codec.plname, "RED"))
1043 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001044 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 {
1046 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1047 VoEId(_instanceId,_channelId),
1048 "Channel::Init() failed to register RED (%d/%d) "
1049 "correctly",
1050 codec.pltype, codec.plfreq);
1051 }
1052 }
1053#endif
1054 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001055
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001056 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1057 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1058 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001060 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1061 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1062 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 }
1064
1065 return 0;
1066}
1067
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001068int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001069Channel::SetEngineInformation(Statistics& engineStatistics,
1070 OutputMixer& outputMixer,
1071 voe::TransmitMixer& transmitMixer,
1072 ProcessThread& moduleProcessThread,
1073 AudioDeviceModule& audioDeviceModule,
1074 VoiceEngineObserver* voiceEngineObserver,
1075 CriticalSectionWrapper* callbackCritSect)
1076{
1077 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1078 "Channel::SetEngineInformation()");
1079 _engineStatisticsPtr = &engineStatistics;
1080 _outputMixerPtr = &outputMixer;
1081 _transmitMixerPtr = &transmitMixer,
1082 _moduleProcessThreadPtr = &moduleProcessThread;
1083 _audioDeviceModulePtr = &audioDeviceModule;
1084 _voiceEngineObserverPtr = voiceEngineObserver;
1085 _callbackCritSectPtr = callbackCritSect;
1086 return 0;
1087}
1088
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001089int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001090Channel::UpdateLocalTimeStamp()
1091{
1092
Peter Kastingb7e50542015-06-11 12:55:50 -07001093 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 return 0;
1095}
1096
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001097int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001098Channel::StartPlayout()
1099{
1100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1101 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001102 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 {
1104 return 0;
1105 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001106
1107 if (!_externalMixing) {
1108 // Add participant as candidates for mixing.
1109 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1110 {
1111 _engineStatisticsPtr->SetLastError(
1112 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1113 "StartPlayout() failed to add participant to mixer");
1114 return -1;
1115 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001116 }
1117
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001118 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001119 if (RegisterFilePlayingToMixer() != 0)
1120 return -1;
1121
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 return 0;
1123}
1124
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001125int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001126Channel::StopPlayout()
1127{
1128 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1129 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001130 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 {
1132 return 0;
1133 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001134
1135 if (!_externalMixing) {
1136 // Remove participant as candidates for mixing
1137 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1138 {
1139 _engineStatisticsPtr->SetLastError(
1140 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1141 "StopPlayout() failed to remove participant from mixer");
1142 return -1;
1143 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 }
1145
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001146 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 _outputAudioLevel.Clear();
1148
1149 return 0;
1150}
1151
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001152int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001153Channel::StartSend()
1154{
1155 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1156 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001157 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001158 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001159 if (send_sequence_number_)
1160 SetInitSequenceNumber(send_sequence_number_);
1161
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001162 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001164 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001165 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001166 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001167
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001168 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 {
1170 _engineStatisticsPtr->SetLastError(
1171 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1172 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001173 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001174 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 return -1;
1176 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001177
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 return 0;
1179}
1180
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001181int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001182Channel::StopSend()
1183{
1184 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1185 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001186 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001188 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001190 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001191
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001192 // Store the sequence number to be able to pick up the same sequence for
1193 // the next StartSend(). This is needed for restarting device, otherwise
1194 // it might cause libSRTP to complain about packets being replayed.
1195 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1196 // CL is landed. See issue
1197 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1198 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1199
niklase@google.com470e71d2011-07-07 08:21:25 +00001200 // Reset sending SSRC and sequence number and triggers direct transmission
1201 // of RTCP BYE
pbosd4362982015-07-07 08:32:48 -07001202 if (_rtpRtcpModule->SetSendingStatus(false) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 {
1204 _engineStatisticsPtr->SetLastError(
1205 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1206 "StartSend() RTP/RTCP failed to stop sending");
1207 }
1208
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 return 0;
1210}
1211
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001212int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001213Channel::StartReceiving()
1214{
1215 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1216 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001217 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 {
1219 return 0;
1220 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001221 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 _numberOfDiscardedPackets = 0;
1223 return 0;
1224}
1225
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001226int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001227Channel::StopReceiving()
1228{
1229 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1230 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001231 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001232 {
1233 return 0;
1234 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001235
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001236 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001237 return 0;
1238}
1239
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001240int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001241Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1242{
1243 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1244 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001245 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001246
1247 if (_voiceEngineObserverPtr)
1248 {
1249 _engineStatisticsPtr->SetLastError(
1250 VE_INVALID_OPERATION, kTraceError,
1251 "RegisterVoiceEngineObserver() observer already enabled");
1252 return -1;
1253 }
1254 _voiceEngineObserverPtr = &observer;
1255 return 0;
1256}
1257
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001258int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001259Channel::DeRegisterVoiceEngineObserver()
1260{
1261 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1262 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001263 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001264
1265 if (!_voiceEngineObserverPtr)
1266 {
1267 _engineStatisticsPtr->SetLastError(
1268 VE_INVALID_OPERATION, kTraceWarning,
1269 "DeRegisterVoiceEngineObserver() observer already disabled");
1270 return 0;
1271 }
1272 _voiceEngineObserverPtr = NULL;
1273 return 0;
1274}
1275
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001276int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001277Channel::GetSendCodec(CodecInst& codec)
1278{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001279 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001280}
1281
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001282int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001283Channel::GetRecCodec(CodecInst& codec)
1284{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001285 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001286}
1287
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001288int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001289Channel::SetSendCodec(const CodecInst& codec)
1290{
1291 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1292 "Channel::SetSendCodec()");
1293
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001294 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 {
1296 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1297 "SetSendCodec() failed to register codec to ACM");
1298 return -1;
1299 }
1300
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001301 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001303 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1304 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 {
1306 WEBRTC_TRACE(
1307 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1308 "SetSendCodec() failed to register codec to"
1309 " RTP/RTCP module");
1310 return -1;
1311 }
1312 }
1313
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001314 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 {
1316 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1317 "SetSendCodec() failed to set audio packet size");
1318 return -1;
1319 }
1320
1321 return 0;
1322}
1323
Ivo Creusenadf89b72015-04-29 16:03:33 +02001324void Channel::SetBitRate(int bitrate_bps) {
1325 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1326 "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
1327 audio_coding_->SetBitRate(bitrate_bps);
1328}
1329
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001330void Channel::OnIncomingFractionLoss(int fraction_lost) {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001331 network_predictor_->UpdatePacketLossRate(fraction_lost);
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001332 uint8_t average_fraction_loss = network_predictor_->GetLossRate();
1333
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001334 // Normalizes rate to 0 - 100.
mflodman@webrtc.org0a7d4ee2015-02-17 12:57:14 +00001335 if (audio_coding_->SetPacketLossRate(
1336 100 * average_fraction_loss / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001337 assert(false); // This should not happen.
1338 }
1339}
1340
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001341int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001342Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1343{
1344 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1345 "Channel::SetVADStatus(mode=%d)", mode);
henrik.lundin@webrtc.org664ccb72015-01-28 14:49:05 +00001346 assert(!(disableDTX && enableVAD)); // disableDTX mode is deprecated.
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 // To disable VAD, DTX must be disabled too
1348 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001349 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 {
1351 _engineStatisticsPtr->SetLastError(
1352 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1353 "SetVADStatus() failed to set VAD");
1354 return -1;
1355 }
1356 return 0;
1357}
1358
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001359int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001360Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1361{
1362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1363 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001364 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001365 {
1366 _engineStatisticsPtr->SetLastError(
1367 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1368 "GetVADStatus() failed to get VAD status");
1369 return -1;
1370 }
1371 disabledDTX = !disabledDTX;
1372 return 0;
1373}
1374
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001375int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001376Channel::SetRecPayloadType(const CodecInst& codec)
1377{
1378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1379 "Channel::SetRecPayloadType()");
1380
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001381 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001382 {
1383 _engineStatisticsPtr->SetLastError(
1384 VE_ALREADY_PLAYING, kTraceError,
1385 "SetRecPayloadType() unable to set PT while playing");
1386 return -1;
1387 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001388 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001389 {
1390 _engineStatisticsPtr->SetLastError(
1391 VE_ALREADY_LISTENING, kTraceError,
1392 "SetRecPayloadType() unable to set PT while listening");
1393 return -1;
1394 }
1395
1396 if (codec.pltype == -1)
1397 {
1398 // De-register the selected codec (RTP/RTCP module and ACM)
1399
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001400 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001401 CodecInst rxCodec = codec;
1402
1403 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001404 rtp_payload_registry_->ReceivePayloadType(
1405 rxCodec.plname,
1406 rxCodec.plfreq,
1407 rxCodec.channels,
1408 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1409 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001410 rxCodec.pltype = pltype;
1411
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001412 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001413 {
1414 _engineStatisticsPtr->SetLastError(
1415 VE_RTP_RTCP_MODULE_ERROR,
1416 kTraceError,
1417 "SetRecPayloadType() RTP/RTCP-module deregistration "
1418 "failed");
1419 return -1;
1420 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001421 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001422 {
1423 _engineStatisticsPtr->SetLastError(
1424 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1425 "SetRecPayloadType() ACM deregistration failed - 1");
1426 return -1;
1427 }
1428 return 0;
1429 }
1430
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001431 if (rtp_receiver_->RegisterReceivePayload(
1432 codec.plname,
1433 codec.pltype,
1434 codec.plfreq,
1435 codec.channels,
1436 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001437 {
1438 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001439 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1440 if (rtp_receiver_->RegisterReceivePayload(
1441 codec.plname,
1442 codec.pltype,
1443 codec.plfreq,
1444 codec.channels,
1445 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001446 {
1447 _engineStatisticsPtr->SetLastError(
1448 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1449 "SetRecPayloadType() RTP/RTCP-module registration failed");
1450 return -1;
1451 }
1452 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001453 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001454 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001455 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1456 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001457 {
1458 _engineStatisticsPtr->SetLastError(
1459 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1460 "SetRecPayloadType() ACM registration failed - 1");
1461 return -1;
1462 }
1463 }
1464 return 0;
1465}
1466
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001467int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001468Channel::GetRecPayloadType(CodecInst& codec)
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001472 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001473 if (rtp_payload_registry_->ReceivePayloadType(
1474 codec.plname,
1475 codec.plfreq,
1476 codec.channels,
1477 (codec.rate < 0) ? 0 : codec.rate,
1478 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001479 {
1480 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001481 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001482 "GetRecPayloadType() failed to retrieve RX payload type");
1483 return -1;
1484 }
1485 codec.pltype = payloadType;
1486 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pkasting@chromium.orgd3245462015-02-23 21:28:22 +00001487 "Channel::GetRecPayloadType() => pltype=%d", codec.pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001488 return 0;
1489}
1490
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001491int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001492Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1493{
1494 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1495 "Channel::SetSendCNPayloadType()");
1496
1497 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001498 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001499 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001500 if (frequency == kFreq32000Hz)
1501 samplingFreqHz = 32000;
1502 else if (frequency == kFreq16000Hz)
1503 samplingFreqHz = 16000;
1504
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001505 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 {
1507 _engineStatisticsPtr->SetLastError(
1508 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1509 "SetSendCNPayloadType() failed to retrieve default CN codec "
1510 "settings");
1511 return -1;
1512 }
1513
1514 // Modify the payload type (must be set to dynamic range)
1515 codec.pltype = type;
1516
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001517 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001518 {
1519 _engineStatisticsPtr->SetLastError(
1520 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1521 "SetSendCNPayloadType() failed to register CN to ACM");
1522 return -1;
1523 }
1524
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001525 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001526 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001527 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1528 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001529 {
1530 _engineStatisticsPtr->SetLastError(
1531 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1532 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1533 "module");
1534 return -1;
1535 }
1536 }
1537 return 0;
1538}
1539
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001540int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001542 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001543
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001544 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001545 _engineStatisticsPtr->SetLastError(
1546 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001547 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001548 return -1;
1549 }
1550 return 0;
1551}
1552
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001553int Channel::SetOpusDtx(bool enable_dtx) {
1554 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1555 "Channel::SetOpusDtx(%d)", enable_dtx);
Minyue Li092041c2015-05-11 12:19:35 +02001556 int ret = enable_dtx ? audio_coding_->EnableOpusDtx()
minyue@webrtc.org9b2e1142015-03-13 09:38:07 +00001557 : audio_coding_->DisableOpusDtx();
1558 if (ret != 0) {
1559 _engineStatisticsPtr->SetLastError(
1560 VE_AUDIO_CODING_MODULE_ERROR, kTraceError, "SetOpusDtx() failed");
1561 return -1;
1562 }
1563 return 0;
1564}
1565
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001566int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001567{
1568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1569 "Channel::RegisterExternalTransport()");
1570
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001571 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001572
niklase@google.com470e71d2011-07-07 08:21:25 +00001573 if (_externalTransport)
1574 {
1575 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1576 kTraceError,
1577 "RegisterExternalTransport() external transport already enabled");
1578 return -1;
1579 }
1580 _externalTransport = true;
1581 _transportPtr = &transport;
1582 return 0;
1583}
1584
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001585int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001586Channel::DeRegisterExternalTransport()
1587{
1588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1589 "Channel::DeRegisterExternalTransport()");
1590
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001591 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001592
niklase@google.com470e71d2011-07-07 08:21:25 +00001593 if (!_transportPtr)
1594 {
1595 _engineStatisticsPtr->SetLastError(
1596 VE_INVALID_OPERATION, kTraceWarning,
1597 "DeRegisterExternalTransport() external transport already "
1598 "disabled");
1599 return 0;
1600 }
1601 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001602 _transportPtr = NULL;
1603 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1604 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001605 return 0;
1606}
1607
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001608int32_t Channel::ReceivedRTPPacket(const int8_t* data, size_t length,
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001609 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001610 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1611 "Channel::ReceivedRTPPacket()");
1612
1613 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001614 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001615
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001616 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001617 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001618 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1619 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1620 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001621 return -1;
1622 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001623 header.payload_type_frequency =
1624 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001625 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001626 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001627 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001628 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001629 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001630 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001631
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001632 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001633}
1634
1635bool Channel::ReceivePacket(const uint8_t* packet,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001636 size_t packet_length,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001637 const RTPHeader& header,
1638 bool in_order) {
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001639 if (rtp_payload_registry_->IsRtx(header)) {
1640 return HandleRtxPacket(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001641 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001642 const uint8_t* payload = packet + header.headerLength;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001643 assert(packet_length >= header.headerLength);
1644 size_t payload_length = packet_length - header.headerLength;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001645 PayloadUnion payload_specific;
1646 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001647 &payload_specific)) {
1648 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001649 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001650 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1651 payload_specific, in_order);
1652}
1653
minyue@webrtc.org456f0142015-01-23 11:58:42 +00001654bool Channel::HandleRtxPacket(const uint8_t* packet,
1655 size_t packet_length,
1656 const RTPHeader& header) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001657 if (!rtp_payload_registry_->IsRtx(header))
1658 return false;
1659
1660 // Remove the RTX header and parse the original RTP header.
1661 if (packet_length < header.headerLength)
1662 return false;
1663 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1664 return false;
1665 if (restored_packet_in_use_) {
1666 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1667 "Multiple RTX headers detected, dropping packet");
1668 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001669 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001670 uint8_t* restored_packet_ptr = restored_packet_;
1671 if (!rtp_payload_registry_->RestoreOriginalPacket(
1672 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1673 header)) {
1674 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1675 "Incoming RTX packet: invalid RTP header");
1676 return false;
1677 }
1678 restored_packet_in_use_ = true;
1679 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1680 restored_packet_in_use_ = false;
1681 return ret;
1682}
1683
1684bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1685 StreamStatistician* statistician =
1686 rtp_receive_statistics_->GetStatistician(header.ssrc);
1687 if (!statistician)
1688 return false;
1689 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001690}
1691
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001692bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1693 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001694 // Retransmissions are handled separately if RTX is enabled.
1695 if (rtp_payload_registry_->RtxEnabled())
1696 return false;
1697 StreamStatistician* statistician =
1698 rtp_receive_statistics_->GetStatistician(header.ssrc);
1699 if (!statistician)
1700 return false;
1701 // Check if this is a retransmission.
pkasting@chromium.org16825b12015-01-12 21:51:21 +00001702 int64_t min_rtt = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001703 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001704 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001705 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001706}
1707
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001708int32_t Channel::ReceivedRTCPPacket(const int8_t* data, size_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001709 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1710 "Channel::ReceivedRTCPPacket()");
1711 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001712 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001713
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001714 // Deliver RTCP packet to RTP/RTCP module for parsing
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001715 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data, length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001716 _engineStatisticsPtr->SetLastError(
1717 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1718 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1719 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001720
Minyue2013aec2015-05-13 14:14:42 +02001721 int64_t rtt = GetRTT(true);
1722 if (rtt == 0) {
1723 // Waiting for valid RTT.
1724 return 0;
1725 }
1726 uint32_t ntp_secs = 0;
1727 uint32_t ntp_frac = 0;
1728 uint32_t rtp_timestamp = 0;
1729 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1730 &rtp_timestamp)) {
1731 // Waiting for RTCP.
1732 return 0;
1733 }
1734
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001735 {
1736 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001737 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001738 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001739 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001740}
1741
niklase@google.com470e71d2011-07-07 08:21:25 +00001742int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001743 bool loop,
1744 FileFormats format,
1745 int startPosition,
1746 float volumeScaling,
1747 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001748 const CodecInst* codecInst)
1749{
1750 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1751 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1752 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1753 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1754 startPosition, stopPosition);
1755
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001756 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001757 {
1758 _engineStatisticsPtr->SetLastError(
1759 VE_ALREADY_PLAYING, kTraceError,
1760 "StartPlayingFileLocally() is already playing");
1761 return -1;
1762 }
1763
niklase@google.com470e71d2011-07-07 08:21:25 +00001764 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001765 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001766
1767 if (_outputFilePlayerPtr)
1768 {
1769 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1770 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1771 _outputFilePlayerPtr = NULL;
1772 }
1773
1774 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1775 _outputFilePlayerId, (const FileFormats)format);
1776
1777 if (_outputFilePlayerPtr == NULL)
1778 {
1779 _engineStatisticsPtr->SetLastError(
1780 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001781 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001782 return -1;
1783 }
1784
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001785 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001786
1787 if (_outputFilePlayerPtr->StartPlayingFile(
1788 fileName,
1789 loop,
1790 startPosition,
1791 volumeScaling,
1792 notificationTime,
1793 stopPosition,
1794 (const CodecInst*)codecInst) != 0)
1795 {
1796 _engineStatisticsPtr->SetLastError(
1797 VE_BAD_FILE, kTraceError,
1798 "StartPlayingFile() failed to start file playout");
1799 _outputFilePlayerPtr->StopPlayingFile();
1800 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1801 _outputFilePlayerPtr = NULL;
1802 return -1;
1803 }
1804 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001805 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001806 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001807
1808 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001809 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001810
1811 return 0;
1812}
1813
1814int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001815 FileFormats format,
1816 int startPosition,
1817 float volumeScaling,
1818 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001819 const CodecInst* codecInst)
1820{
1821 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1822 "Channel::StartPlayingFileLocally(format=%d,"
1823 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1824 format, volumeScaling, startPosition, stopPosition);
1825
1826 if(stream == NULL)
1827 {
1828 _engineStatisticsPtr->SetLastError(
1829 VE_BAD_FILE, kTraceError,
1830 "StartPlayingFileLocally() NULL as input stream");
1831 return -1;
1832 }
1833
1834
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001835 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001836 {
1837 _engineStatisticsPtr->SetLastError(
1838 VE_ALREADY_PLAYING, kTraceError,
1839 "StartPlayingFileLocally() is already playing");
1840 return -1;
1841 }
1842
niklase@google.com470e71d2011-07-07 08:21:25 +00001843 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001844 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001845
1846 // Destroy the old instance
1847 if (_outputFilePlayerPtr)
1848 {
1849 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1850 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1851 _outputFilePlayerPtr = NULL;
1852 }
1853
1854 // Create the instance
1855 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1856 _outputFilePlayerId,
1857 (const FileFormats)format);
1858
1859 if (_outputFilePlayerPtr == NULL)
1860 {
1861 _engineStatisticsPtr->SetLastError(
1862 VE_INVALID_ARGUMENT, kTraceError,
1863 "StartPlayingFileLocally() filePlayer format isnot correct");
1864 return -1;
1865 }
1866
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001867 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001868
1869 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1870 volumeScaling,
1871 notificationTime,
1872 stopPosition, codecInst) != 0)
1873 {
1874 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1875 "StartPlayingFile() failed to "
1876 "start file playout");
1877 _outputFilePlayerPtr->StopPlayingFile();
1878 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1879 _outputFilePlayerPtr = NULL;
1880 return -1;
1881 }
1882 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001883 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001884 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001885
1886 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001887 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001888
niklase@google.com470e71d2011-07-07 08:21:25 +00001889 return 0;
1890}
1891
1892int Channel::StopPlayingFileLocally()
1893{
1894 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1895 "Channel::StopPlayingFileLocally()");
1896
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001897 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001898 {
1899 _engineStatisticsPtr->SetLastError(
1900 VE_INVALID_OPERATION, kTraceWarning,
1901 "StopPlayingFileLocally() isnot playing");
1902 return 0;
1903 }
1904
niklase@google.com470e71d2011-07-07 08:21:25 +00001905 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001906 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001907
1908 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
1909 {
1910 _engineStatisticsPtr->SetLastError(
1911 VE_STOP_RECORDING_FAILED, kTraceError,
1912 "StopPlayingFile() could not stop playing");
1913 return -1;
1914 }
1915 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1916 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1917 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001918 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001919 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001920 // _fileCritSect cannot be taken while calling
1921 // SetAnonymousMixibilityStatus. Refer to comments in
1922 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001923 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
1924 {
1925 _engineStatisticsPtr->SetLastError(
1926 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001927 "StopPlayingFile() failed to stop participant from playing as"
1928 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001929 return -1;
1930 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001931
1932 return 0;
1933}
1934
1935int Channel::IsPlayingFileLocally() const
1936{
1937 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1938 "Channel::IsPlayingFileLocally()");
1939
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001940 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00001941}
1942
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001943int Channel::RegisterFilePlayingToMixer()
1944{
1945 // Return success for not registering for file playing to mixer if:
1946 // 1. playing file before playout is started on that channel.
1947 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001948 if (!channel_state_.Get().playing ||
1949 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001950 {
1951 return 0;
1952 }
1953
1954 // |_fileCritSect| cannot be taken while calling
1955 // SetAnonymousMixabilityStatus() since as soon as the participant is added
1956 // frames can be pulled by the mixer. Since the frames are generated from
1957 // the file, _fileCritSect will be taken. This would result in a deadlock.
1958 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
1959 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001960 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001961 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001962 _engineStatisticsPtr->SetLastError(
1963 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1964 "StartPlayingFile() failed to add participant as file to mixer");
1965 _outputFilePlayerPtr->StopPlayingFile();
1966 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1967 _outputFilePlayerPtr = NULL;
1968 return -1;
1969 }
1970
1971 return 0;
1972}
1973
niklase@google.com470e71d2011-07-07 08:21:25 +00001974int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001975 bool loop,
1976 FileFormats format,
1977 int startPosition,
1978 float volumeScaling,
1979 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001980 const CodecInst* codecInst)
1981{
1982 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1983 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
1984 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
1985 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1986 startPosition, stopPosition);
1987
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001988 CriticalSectionScoped cs(&_fileCritSect);
1989
1990 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001991 {
1992 _engineStatisticsPtr->SetLastError(
1993 VE_ALREADY_PLAYING, kTraceWarning,
1994 "StartPlayingFileAsMicrophone() filePlayer is playing");
1995 return 0;
1996 }
1997
niklase@google.com470e71d2011-07-07 08:21:25 +00001998 // Destroy the old instance
1999 if (_inputFilePlayerPtr)
2000 {
2001 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2002 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2003 _inputFilePlayerPtr = NULL;
2004 }
2005
2006 // Create the instance
2007 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2008 _inputFilePlayerId, (const FileFormats)format);
2009
2010 if (_inputFilePlayerPtr == NULL)
2011 {
2012 _engineStatisticsPtr->SetLastError(
2013 VE_INVALID_ARGUMENT, kTraceError,
2014 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2015 return -1;
2016 }
2017
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002018 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002019
2020 if (_inputFilePlayerPtr->StartPlayingFile(
2021 fileName,
2022 loop,
2023 startPosition,
2024 volumeScaling,
2025 notificationTime,
2026 stopPosition,
2027 (const CodecInst*)codecInst) != 0)
2028 {
2029 _engineStatisticsPtr->SetLastError(
2030 VE_BAD_FILE, kTraceError,
2031 "StartPlayingFile() failed to start file playout");
2032 _inputFilePlayerPtr->StopPlayingFile();
2033 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2034 _inputFilePlayerPtr = NULL;
2035 return -1;
2036 }
2037 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002038 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002039
2040 return 0;
2041}
2042
2043int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002044 FileFormats format,
2045 int startPosition,
2046 float volumeScaling,
2047 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002048 const CodecInst* codecInst)
2049{
2050 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2051 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2052 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2053 format, volumeScaling, startPosition, stopPosition);
2054
2055 if(stream == NULL)
2056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_BAD_FILE, kTraceError,
2059 "StartPlayingFileAsMicrophone NULL as input stream");
2060 return -1;
2061 }
2062
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002063 CriticalSectionScoped cs(&_fileCritSect);
2064
2065 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002066 {
2067 _engineStatisticsPtr->SetLastError(
2068 VE_ALREADY_PLAYING, kTraceWarning,
2069 "StartPlayingFileAsMicrophone() is playing");
2070 return 0;
2071 }
2072
niklase@google.com470e71d2011-07-07 08:21:25 +00002073 // Destroy the old instance
2074 if (_inputFilePlayerPtr)
2075 {
2076 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2077 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2078 _inputFilePlayerPtr = NULL;
2079 }
2080
2081 // Create the instance
2082 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2083 _inputFilePlayerId, (const FileFormats)format);
2084
2085 if (_inputFilePlayerPtr == NULL)
2086 {
2087 _engineStatisticsPtr->SetLastError(
2088 VE_INVALID_ARGUMENT, kTraceError,
2089 "StartPlayingInputFile() filePlayer format isnot correct");
2090 return -1;
2091 }
2092
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002093 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002094
2095 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2096 volumeScaling, notificationTime,
2097 stopPosition, codecInst) != 0)
2098 {
2099 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2100 "StartPlayingFile() failed to start "
2101 "file playout");
2102 _inputFilePlayerPtr->StopPlayingFile();
2103 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2104 _inputFilePlayerPtr = NULL;
2105 return -1;
2106 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002107
niklase@google.com470e71d2011-07-07 08:21:25 +00002108 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002109 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002110
2111 return 0;
2112}
2113
2114int Channel::StopPlayingFileAsMicrophone()
2115{
2116 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2117 "Channel::StopPlayingFileAsMicrophone()");
2118
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002119 CriticalSectionScoped cs(&_fileCritSect);
2120
2121 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002122 {
2123 _engineStatisticsPtr->SetLastError(
2124 VE_INVALID_OPERATION, kTraceWarning,
2125 "StopPlayingFileAsMicrophone() isnot playing");
2126 return 0;
2127 }
2128
niklase@google.com470e71d2011-07-07 08:21:25 +00002129 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2130 {
2131 _engineStatisticsPtr->SetLastError(
2132 VE_STOP_RECORDING_FAILED, kTraceError,
2133 "StopPlayingFile() could not stop playing");
2134 return -1;
2135 }
2136 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2137 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2138 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002139 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002140
2141 return 0;
2142}
2143
2144int Channel::IsPlayingFileAsMicrophone() const
2145{
2146 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2147 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002148 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002149}
2150
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002151int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002152 const CodecInst* codecInst)
2153{
2154 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2155 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2156
2157 if (_outputFileRecording)
2158 {
2159 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2160 "StartRecordingPlayout() is already recording");
2161 return 0;
2162 }
2163
2164 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002165 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002166 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2167
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002168 if ((codecInst != NULL) &&
2169 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002170 {
2171 _engineStatisticsPtr->SetLastError(
2172 VE_BAD_ARGUMENT, kTraceError,
2173 "StartRecordingPlayout() invalid compression");
2174 return(-1);
2175 }
2176 if(codecInst == NULL)
2177 {
2178 format = kFileFormatPcm16kHzFile;
2179 codecInst=&dummyCodec;
2180 }
2181 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2182 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2183 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2184 {
2185 format = kFileFormatWavFile;
2186 }
2187 else
2188 {
2189 format = kFileFormatCompressedFile;
2190 }
2191
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002192 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002193
2194 // Destroy the old instance
2195 if (_outputFileRecorderPtr)
2196 {
2197 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2198 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2199 _outputFileRecorderPtr = NULL;
2200 }
2201
2202 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2203 _outputFileRecorderId, (const FileFormats)format);
2204 if (_outputFileRecorderPtr == NULL)
2205 {
2206 _engineStatisticsPtr->SetLastError(
2207 VE_INVALID_ARGUMENT, kTraceError,
2208 "StartRecordingPlayout() fileRecorder format isnot correct");
2209 return -1;
2210 }
2211
2212 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2213 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2214 {
2215 _engineStatisticsPtr->SetLastError(
2216 VE_BAD_FILE, kTraceError,
2217 "StartRecordingAudioFile() failed to start file recording");
2218 _outputFileRecorderPtr->StopRecording();
2219 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2220 _outputFileRecorderPtr = NULL;
2221 return -1;
2222 }
2223 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2224 _outputFileRecording = true;
2225
2226 return 0;
2227}
2228
2229int Channel::StartRecordingPlayout(OutStream* stream,
2230 const CodecInst* codecInst)
2231{
2232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2233 "Channel::StartRecordingPlayout()");
2234
2235 if (_outputFileRecording)
2236 {
2237 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2238 "StartRecordingPlayout() is already recording");
2239 return 0;
2240 }
2241
2242 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002243 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002244 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2245
2246 if (codecInst != NULL && codecInst->channels != 1)
2247 {
2248 _engineStatisticsPtr->SetLastError(
2249 VE_BAD_ARGUMENT, kTraceError,
2250 "StartRecordingPlayout() invalid compression");
2251 return(-1);
2252 }
2253 if(codecInst == NULL)
2254 {
2255 format = kFileFormatPcm16kHzFile;
2256 codecInst=&dummyCodec;
2257 }
2258 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2259 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2260 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2261 {
2262 format = kFileFormatWavFile;
2263 }
2264 else
2265 {
2266 format = kFileFormatCompressedFile;
2267 }
2268
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002269 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002270
2271 // Destroy the old instance
2272 if (_outputFileRecorderPtr)
2273 {
2274 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2275 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2276 _outputFileRecorderPtr = NULL;
2277 }
2278
2279 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2280 _outputFileRecorderId, (const FileFormats)format);
2281 if (_outputFileRecorderPtr == NULL)
2282 {
2283 _engineStatisticsPtr->SetLastError(
2284 VE_INVALID_ARGUMENT, kTraceError,
2285 "StartRecordingPlayout() fileRecorder format isnot correct");
2286 return -1;
2287 }
2288
2289 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2290 notificationTime) != 0)
2291 {
2292 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2293 "StartRecordingPlayout() failed to "
2294 "start file recording");
2295 _outputFileRecorderPtr->StopRecording();
2296 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2297 _outputFileRecorderPtr = NULL;
2298 return -1;
2299 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002300
niklase@google.com470e71d2011-07-07 08:21:25 +00002301 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2302 _outputFileRecording = true;
2303
2304 return 0;
2305}
2306
2307int Channel::StopRecordingPlayout()
2308{
2309 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2310 "Channel::StopRecordingPlayout()");
2311
2312 if (!_outputFileRecording)
2313 {
2314 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2315 "StopRecordingPlayout() isnot recording");
2316 return -1;
2317 }
2318
2319
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002320 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002321
2322 if (_outputFileRecorderPtr->StopRecording() != 0)
2323 {
2324 _engineStatisticsPtr->SetLastError(
2325 VE_STOP_RECORDING_FAILED, kTraceError,
2326 "StopRecording() could not stop recording");
2327 return(-1);
2328 }
2329 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2330 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2331 _outputFileRecorderPtr = NULL;
2332 _outputFileRecording = false;
2333
2334 return 0;
2335}
2336
2337void
2338Channel::SetMixWithMicStatus(bool mix)
2339{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002340 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002341 _mixFileWithMicrophone=mix;
2342}
2343
2344int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002345Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002346{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002347 int8_t currentLevel = _outputAudioLevel.Level();
2348 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002349 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2350 VoEId(_instanceId,_channelId),
2351 "GetSpeechOutputLevel() => level=%u", level);
2352 return 0;
2353}
2354
2355int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002356Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002357{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002358 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2359 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002360 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2361 VoEId(_instanceId,_channelId),
2362 "GetSpeechOutputLevelFullRange() => level=%u", level);
2363 return 0;
2364}
2365
2366int
2367Channel::SetMute(bool enable)
2368{
wu@webrtc.org63420662013-10-17 18:28:55 +00002369 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002370 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2371 "Channel::SetMute(enable=%d)", enable);
2372 _mute = enable;
2373 return 0;
2374}
2375
2376bool
2377Channel::Mute() const
2378{
wu@webrtc.org63420662013-10-17 18:28:55 +00002379 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002380 return _mute;
2381}
2382
2383int
2384Channel::SetOutputVolumePan(float left, float right)
2385{
wu@webrtc.org63420662013-10-17 18:28:55 +00002386 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2388 "Channel::SetOutputVolumePan()");
2389 _panLeft = left;
2390 _panRight = right;
2391 return 0;
2392}
2393
2394int
2395Channel::GetOutputVolumePan(float& left, float& right) const
2396{
wu@webrtc.org63420662013-10-17 18:28:55 +00002397 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002398 left = _panLeft;
2399 right = _panRight;
2400 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2401 VoEId(_instanceId,_channelId),
2402 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2403 return 0;
2404}
2405
2406int
2407Channel::SetChannelOutputVolumeScaling(float scaling)
2408{
wu@webrtc.org63420662013-10-17 18:28:55 +00002409 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002410 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2411 "Channel::SetChannelOutputVolumeScaling()");
2412 _outputGain = scaling;
2413 return 0;
2414}
2415
2416int
2417Channel::GetChannelOutputVolumeScaling(float& scaling) const
2418{
wu@webrtc.org63420662013-10-17 18:28:55 +00002419 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002420 scaling = _outputGain;
2421 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2422 VoEId(_instanceId,_channelId),
2423 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2424 return 0;
2425}
2426
niklase@google.com470e71d2011-07-07 08:21:25 +00002427int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002428 int lengthMs, int attenuationDb,
2429 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002430{
2431 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2432 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2433 playDtmfEvent);
2434
2435 _playOutbandDtmfEvent = playDtmfEvent;
2436
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002437 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002438 attenuationDb) != 0)
2439 {
2440 _engineStatisticsPtr->SetLastError(
2441 VE_SEND_DTMF_FAILED,
2442 kTraceWarning,
2443 "SendTelephoneEventOutband() failed to send event");
2444 return -1;
2445 }
2446 return 0;
2447}
2448
2449int Channel::SendTelephoneEventInband(unsigned char eventCode,
2450 int lengthMs,
2451 int attenuationDb,
2452 bool playDtmfEvent)
2453{
2454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2455 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2456 playDtmfEvent);
2457
2458 _playInbandDtmfEvent = playDtmfEvent;
2459 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2460
2461 return 0;
2462}
2463
2464int
niklase@google.com470e71d2011-07-07 08:21:25 +00002465Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2466{
2467 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2468 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002469 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002470 {
2471 _engineStatisticsPtr->SetLastError(
2472 VE_INVALID_ARGUMENT, kTraceError,
2473 "SetSendTelephoneEventPayloadType() invalid type");
2474 return -1;
2475 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002476 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002477 codec.plfreq = 8000;
2478 codec.pltype = type;
2479 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002480 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002481 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002482 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2483 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2484 _engineStatisticsPtr->SetLastError(
2485 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2486 "SetSendTelephoneEventPayloadType() failed to register send"
2487 "payload type");
2488 return -1;
2489 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002490 }
2491 _sendTelephoneEventPayloadType = type;
2492 return 0;
2493}
2494
2495int
2496Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2497{
2498 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2499 "Channel::GetSendTelephoneEventPayloadType()");
2500 type = _sendTelephoneEventPayloadType;
2501 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2502 VoEId(_instanceId,_channelId),
2503 "GetSendTelephoneEventPayloadType() => type=%u", type);
2504 return 0;
2505}
2506
niklase@google.com470e71d2011-07-07 08:21:25 +00002507int
2508Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2509{
2510 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2511 "Channel::UpdateRxVadDetection()");
2512
2513 int vadDecision = 1;
2514
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002515 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002516
2517 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2518 {
2519 OnRxVadDetected(vadDecision);
2520 _oldVadDecision = vadDecision;
2521 }
2522
2523 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2524 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2525 vadDecision);
2526 return 0;
2527}
2528
2529int
2530Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2531{
2532 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2533 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002534 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002535
2536 if (_rxVadObserverPtr)
2537 {
2538 _engineStatisticsPtr->SetLastError(
2539 VE_INVALID_OPERATION, kTraceError,
2540 "RegisterRxVadObserver() observer already enabled");
2541 return -1;
2542 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002543 _rxVadObserverPtr = &observer;
2544 _RxVadDetection = true;
2545 return 0;
2546}
2547
2548int
2549Channel::DeRegisterRxVadObserver()
2550{
2551 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2552 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002553 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002554
2555 if (!_rxVadObserverPtr)
2556 {
2557 _engineStatisticsPtr->SetLastError(
2558 VE_INVALID_OPERATION, kTraceWarning,
2559 "DeRegisterRxVadObserver() observer already disabled");
2560 return 0;
2561 }
2562 _rxVadObserverPtr = NULL;
2563 _RxVadDetection = false;
2564 return 0;
2565}
2566
2567int
2568Channel::VoiceActivityIndicator(int &activity)
2569{
2570 activity = _sendFrameType;
2571
2572 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002573 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002574 return 0;
2575}
2576
2577#ifdef WEBRTC_VOICE_ENGINE_AGC
2578
2579int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002580Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002581{
2582 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2583 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2584 (int)enable, (int)mode);
2585
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002586 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002587 switch (mode)
2588 {
2589 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002590 break;
2591 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002592 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002593 break;
2594 case kAgcFixedDigital:
2595 agcMode = GainControl::kFixedDigital;
2596 break;
2597 case kAgcAdaptiveDigital:
2598 agcMode =GainControl::kAdaptiveDigital;
2599 break;
2600 default:
2601 _engineStatisticsPtr->SetLastError(
2602 VE_INVALID_ARGUMENT, kTraceError,
2603 "SetRxAgcStatus() invalid Agc mode");
2604 return -1;
2605 }
2606
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002607 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002608 {
2609 _engineStatisticsPtr->SetLastError(
2610 VE_APM_ERROR, kTraceError,
2611 "SetRxAgcStatus() failed to set Agc mode");
2612 return -1;
2613 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002614 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002615 {
2616 _engineStatisticsPtr->SetLastError(
2617 VE_APM_ERROR, kTraceError,
2618 "SetRxAgcStatus() failed to set Agc state");
2619 return -1;
2620 }
2621
2622 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002623 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002624
2625 return 0;
2626}
2627
2628int
2629Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2630{
2631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2632 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2633
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002634 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002635 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002636 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002637
2638 enabled = enable;
2639
2640 switch (agcMode)
2641 {
2642 case GainControl::kFixedDigital:
2643 mode = kAgcFixedDigital;
2644 break;
2645 case GainControl::kAdaptiveDigital:
2646 mode = kAgcAdaptiveDigital;
2647 break;
2648 default:
2649 _engineStatisticsPtr->SetLastError(
2650 VE_APM_ERROR, kTraceError,
2651 "GetRxAgcStatus() invalid Agc mode");
2652 return -1;
2653 }
2654
2655 return 0;
2656}
2657
2658int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002659Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002660{
2661 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2662 "Channel::SetRxAgcConfig()");
2663
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002664 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002665 config.targetLeveldBOv) != 0)
2666 {
2667 _engineStatisticsPtr->SetLastError(
2668 VE_APM_ERROR, kTraceError,
2669 "SetRxAgcConfig() failed to set target peak |level|"
2670 "(or envelope) of the Agc");
2671 return -1;
2672 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002673 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002674 config.digitalCompressionGaindB) != 0)
2675 {
2676 _engineStatisticsPtr->SetLastError(
2677 VE_APM_ERROR, kTraceError,
2678 "SetRxAgcConfig() failed to set the range in |gain| the"
2679 " digital compression stage may apply");
2680 return -1;
2681 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002682 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002683 config.limiterEnable) != 0)
2684 {
2685 _engineStatisticsPtr->SetLastError(
2686 VE_APM_ERROR, kTraceError,
2687 "SetRxAgcConfig() failed to set hard limiter to the signal");
2688 return -1;
2689 }
2690
2691 return 0;
2692}
2693
2694int
2695Channel::GetRxAgcConfig(AgcConfig& config)
2696{
2697 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2698 "Channel::GetRxAgcConfig(config=%?)");
2699
2700 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002701 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002702 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002703 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002704 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002705 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002706
2707 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2708 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2709 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2710 " limiterEnable=%d",
2711 config.targetLeveldBOv,
2712 config.digitalCompressionGaindB,
2713 config.limiterEnable);
2714
2715 return 0;
2716}
2717
2718#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2719
2720#ifdef WEBRTC_VOICE_ENGINE_NR
2721
2722int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002723Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002724{
2725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2726 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2727 (int)enable, (int)mode);
2728
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002729 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002730 switch (mode)
2731 {
2732
2733 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002734 break;
2735 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002736 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002737 break;
2738 case kNsConference:
2739 nsLevel = NoiseSuppression::kHigh;
2740 break;
2741 case kNsLowSuppression:
2742 nsLevel = NoiseSuppression::kLow;
2743 break;
2744 case kNsModerateSuppression:
2745 nsLevel = NoiseSuppression::kModerate;
2746 break;
2747 case kNsHighSuppression:
2748 nsLevel = NoiseSuppression::kHigh;
2749 break;
2750 case kNsVeryHighSuppression:
2751 nsLevel = NoiseSuppression::kVeryHigh;
2752 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002753 }
2754
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002755 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002756 != 0)
2757 {
2758 _engineStatisticsPtr->SetLastError(
2759 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002760 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 return -1;
2762 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002763 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 {
2765 _engineStatisticsPtr->SetLastError(
2766 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002767 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002768 return -1;
2769 }
2770
2771 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002772 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002773
2774 return 0;
2775}
2776
2777int
2778Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2779{
2780 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2781 "Channel::GetRxNsStatus(enable=?, mode=?)");
2782
2783 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002784 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002785 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002786 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002787
2788 enabled = enable;
2789
2790 switch (ncLevel)
2791 {
2792 case NoiseSuppression::kLow:
2793 mode = kNsLowSuppression;
2794 break;
2795 case NoiseSuppression::kModerate:
2796 mode = kNsModerateSuppression;
2797 break;
2798 case NoiseSuppression::kHigh:
2799 mode = kNsHighSuppression;
2800 break;
2801 case NoiseSuppression::kVeryHigh:
2802 mode = kNsVeryHighSuppression;
2803 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002804 }
2805
2806 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2807 VoEId(_instanceId,_channelId),
2808 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2809 return 0;
2810}
2811
2812#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2813
2814int
niklase@google.com470e71d2011-07-07 08:21:25 +00002815Channel::SetLocalSSRC(unsigned int ssrc)
2816{
2817 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2818 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002819 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002820 {
2821 _engineStatisticsPtr->SetLastError(
2822 VE_ALREADY_SENDING, kTraceError,
2823 "SetLocalSSRC() already sending");
2824 return -1;
2825 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00002826 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00002827 return 0;
2828}
2829
2830int
2831Channel::GetLocalSSRC(unsigned int& ssrc)
2832{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002833 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002834 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2835 VoEId(_instanceId,_channelId),
2836 "GetLocalSSRC() => ssrc=%lu", ssrc);
2837 return 0;
2838}
2839
2840int
2841Channel::GetRemoteSSRC(unsigned int& ssrc)
2842{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002843 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00002844 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2845 VoEId(_instanceId,_channelId),
2846 "GetRemoteSSRC() => ssrc=%lu", ssrc);
2847 return 0;
2848}
2849
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002850int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002851 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002852 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00002853}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002854
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00002855int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
2856 unsigned char id) {
2857 rtp_header_parser_->DeregisterRtpHeaderExtension(
2858 kRtpExtensionAudioLevel);
2859 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2860 kRtpExtensionAudioLevel, id)) {
2861 return -1;
2862 }
2863 return 0;
2864}
2865
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002866int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2867 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
2868}
2869
2870int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
2871 rtp_header_parser_->DeregisterRtpHeaderExtension(
2872 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002873 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
2874 kRtpExtensionAbsoluteSendTime, id)) {
2875 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00002876 }
2877 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002878}
2879
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002880void Channel::SetRTCPStatus(bool enable) {
2881 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2882 "Channel::SetRTCPStatus()");
2883 _rtpRtcpModule->SetRTCPStatus(enable ? kRtcpCompound : kRtcpOff);
niklase@google.com470e71d2011-07-07 08:21:25 +00002884}
2885
2886int
2887Channel::GetRTCPStatus(bool& enabled)
2888{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002889 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00002890 enabled = (method != kRtcpOff);
2891 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2892 VoEId(_instanceId,_channelId),
2893 "GetRTCPStatus() => enabled=%d", enabled);
2894 return 0;
2895}
2896
2897int
2898Channel::SetRTCP_CNAME(const char cName[256])
2899{
2900 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2901 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002902 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002903 {
2904 _engineStatisticsPtr->SetLastError(
2905 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2906 "SetRTCP_CNAME() failed to set RTCP CNAME");
2907 return -1;
2908 }
2909 return 0;
2910}
2911
2912int
niklase@google.com470e71d2011-07-07 08:21:25 +00002913Channel::GetRemoteRTCP_CNAME(char cName[256])
2914{
2915 if (cName == NULL)
2916 {
2917 _engineStatisticsPtr->SetLastError(
2918 VE_INVALID_ARGUMENT, kTraceError,
2919 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
2920 return -1;
2921 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002922 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002923 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002924 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002925 {
2926 _engineStatisticsPtr->SetLastError(
2927 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
2928 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
2929 return -1;
2930 }
2931 strcpy(cName, cname);
2932 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2933 VoEId(_instanceId, _channelId),
2934 "GetRemoteRTCP_CNAME() => cName=%s", cName);
2935 return 0;
2936}
2937
2938int
2939Channel::GetRemoteRTCPData(
2940 unsigned int& NTPHigh,
2941 unsigned int& NTPLow,
2942 unsigned int& timestamp,
2943 unsigned int& playoutTimestamp,
2944 unsigned int* jitter,
2945 unsigned short* fractionLost)
2946{
2947 // --- Information from sender info in received Sender Reports
2948
2949 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002950 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002951 {
2952 _engineStatisticsPtr->SetLastError(
2953 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00002954 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00002955 "side");
2956 return -1;
2957 }
2958
2959 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
2960 // and octet count)
2961 NTPHigh = senderInfo.NTPseconds;
2962 NTPLow = senderInfo.NTPfraction;
2963 timestamp = senderInfo.RTPtimeStamp;
2964
2965 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2966 VoEId(_instanceId, _channelId),
2967 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
2968 "timestamp=%lu",
2969 NTPHigh, NTPLow, timestamp);
2970
2971 // --- Locally derived information
2972
2973 // This value is updated on each incoming RTCP packet (0 when no packet
2974 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002975 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00002976
2977 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2978 VoEId(_instanceId, _channelId),
2979 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002980 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002981
2982 if (NULL != jitter || NULL != fractionLost)
2983 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002984 // Get all RTCP receiver report blocks that have been received on this
2985 // channel. If we receive RTP packets from a remote source we know the
2986 // remote SSRC and use the report block from him.
2987 // Otherwise use the first report block.
2988 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002989 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002990 remote_stats.empty()) {
2991 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2992 VoEId(_instanceId, _channelId),
2993 "GetRemoteRTCPData() failed to measure statistics due"
2994 " to lack of received RTP and/or RTCP packets");
2995 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002996 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002997
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002998 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00002999 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3000 for (; it != remote_stats.end(); ++it) {
3001 if (it->remoteSSRC == remoteSSRC)
3002 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003003 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003004
3005 if (it == remote_stats.end()) {
3006 // If we have not received any RTCP packets from this SSRC it probably
3007 // means that we have not received any RTP packets.
3008 // Use the first received report block instead.
3009 it = remote_stats.begin();
3010 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003011 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003012
xians@webrtc.org79af7342012-01-31 12:22:14 +00003013 if (jitter) {
3014 *jitter = it->jitter;
3015 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3016 VoEId(_instanceId, _channelId),
3017 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3018 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003019
xians@webrtc.org79af7342012-01-31 12:22:14 +00003020 if (fractionLost) {
3021 *fractionLost = it->fractionLost;
3022 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3023 VoEId(_instanceId, _channelId),
3024 "GetRemoteRTCPData() => fractionLost = %lu",
3025 *fractionLost);
3026 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003027 }
3028 return 0;
3029}
3030
3031int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003032Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003033 unsigned int name,
3034 const char* data,
3035 unsigned short dataLengthInBytes)
3036{
3037 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3038 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003039 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003040 {
3041 _engineStatisticsPtr->SetLastError(
3042 VE_NOT_SENDING, kTraceError,
3043 "SendApplicationDefinedRTCPPacket() not sending");
3044 return -1;
3045 }
3046 if (NULL == data)
3047 {
3048 _engineStatisticsPtr->SetLastError(
3049 VE_INVALID_ARGUMENT, kTraceError,
3050 "SendApplicationDefinedRTCPPacket() invalid data value");
3051 return -1;
3052 }
3053 if (dataLengthInBytes % 4 != 0)
3054 {
3055 _engineStatisticsPtr->SetLastError(
3056 VE_INVALID_ARGUMENT, kTraceError,
3057 "SendApplicationDefinedRTCPPacket() invalid length value");
3058 return -1;
3059 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003060 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003061 if (status == kRtcpOff)
3062 {
3063 _engineStatisticsPtr->SetLastError(
3064 VE_RTCP_ERROR, kTraceError,
3065 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3066 return -1;
3067 }
3068
3069 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003070 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003071 subType,
3072 name,
3073 (const unsigned char*) data,
3074 dataLengthInBytes) != 0)
3075 {
3076 _engineStatisticsPtr->SetLastError(
3077 VE_SEND_ERROR, kTraceError,
3078 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3079 return -1;
3080 }
3081 return 0;
3082}
3083
3084int
3085Channel::GetRTPStatistics(
3086 unsigned int& averageJitterMs,
3087 unsigned int& maxJitterMs,
3088 unsigned int& discardedPackets)
3089{
niklase@google.com470e71d2011-07-07 08:21:25 +00003090 // The jitter statistics is updated for each received RTP packet and is
3091 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003092 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3093 // If RTCP is off, there is no timed thread in the RTCP module regularly
3094 // generating new stats, trigger the update manually here instead.
3095 StreamStatistician* statistician =
3096 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3097 if (statistician) {
3098 // Don't use returned statistics, use data from proxy instead so that
3099 // max jitter can be fetched atomically.
3100 RtcpStatistics s;
3101 statistician->GetStatistics(&s, true);
3102 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003103 }
3104
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003105 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003106 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003107 if (playoutFrequency > 0) {
3108 // Scale RTP statistics given the current playout frequency
3109 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3110 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003111 }
3112
3113 discardedPackets = _numberOfDiscardedPackets;
3114
3115 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3116 VoEId(_instanceId, _channelId),
3117 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003118 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 averageJitterMs, maxJitterMs, discardedPackets);
3120 return 0;
3121}
3122
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003123int Channel::GetRemoteRTCPReportBlocks(
3124 std::vector<ReportBlock>* report_blocks) {
3125 if (report_blocks == NULL) {
3126 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3127 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3128 return -1;
3129 }
3130
3131 // Get the report blocks from the latest received RTCP Sender or Receiver
3132 // Report. Each element in the vector contains the sender's SSRC and a
3133 // report block according to RFC 3550.
3134 std::vector<RTCPReportBlock> rtcp_report_blocks;
3135 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3136 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3137 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3138 return -1;
3139 }
3140
3141 if (rtcp_report_blocks.empty())
3142 return 0;
3143
3144 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3145 for (; it != rtcp_report_blocks.end(); ++it) {
3146 ReportBlock report_block;
3147 report_block.sender_SSRC = it->remoteSSRC;
3148 report_block.source_SSRC = it->sourceSSRC;
3149 report_block.fraction_lost = it->fractionLost;
3150 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3151 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3152 report_block.interarrival_jitter = it->jitter;
3153 report_block.last_SR_timestamp = it->lastSR;
3154 report_block.delay_since_last_SR = it->delaySinceLastSR;
3155 report_blocks->push_back(report_block);
3156 }
3157 return 0;
3158}
3159
niklase@google.com470e71d2011-07-07 08:21:25 +00003160int
3161Channel::GetRTPStatistics(CallStatistics& stats)
3162{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003163 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003164
3165 // The jitter statistics is updated for each received RTP packet and is
3166 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003167 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003168 StreamStatistician* statistician =
3169 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3170 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003171 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3172 _engineStatisticsPtr->SetLastError(
3173 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3174 "GetRTPStatistics() failed to read RTP statistics from the "
3175 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003176 }
3177
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003178 stats.fractionLost = statistics.fraction_lost;
3179 stats.cumulativeLost = statistics.cumulative_lost;
3180 stats.extendedMax = statistics.extended_max_sequence_number;
3181 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003182
3183 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3184 VoEId(_instanceId, _channelId),
3185 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003186 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003187 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3188 stats.jitterSamples);
3189
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003190 // --- RTT
Minyue2013aec2015-05-13 14:14:42 +02003191 stats.rttMs = GetRTT(true);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003192 if (stats.rttMs == 0) {
3193 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, _channelId),
3194 "GetRTPStatistics() failed to get RTT");
3195 } else {
3196 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId, _channelId),
pkasting@chromium.org16825b12015-01-12 21:51:21 +00003197 "GetRTPStatistics() => rttMs=%" PRId64, stats.rttMs);
minyue@webrtc.org6fd93082014-12-15 14:56:44 +00003198 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003199
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003200 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003201
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003202 size_t bytesSent(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003203 uint32_t packetsSent(0);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003204 size_t bytesReceived(0);
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003205 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003206
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003207 if (statistician) {
3208 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3209 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003210
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003211 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003212 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003213 {
3214 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3215 VoEId(_instanceId, _channelId),
3216 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003217 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003218 }
3219
3220 stats.bytesSent = bytesSent;
3221 stats.packetsSent = packetsSent;
3222 stats.bytesReceived = bytesReceived;
3223 stats.packetsReceived = packetsReceived;
3224
3225 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3226 VoEId(_instanceId, _channelId),
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003227 "GetRTPStatistics() => bytesSent=%" PRIuS ", packetsSent=%d,"
3228 " bytesReceived=%" PRIuS ", packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003229 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3230 stats.packetsReceived);
3231
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003232 // --- Timestamps
3233 {
3234 CriticalSectionScoped lock(ts_stats_lock_.get());
3235 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3236 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003237 return 0;
3238}
3239
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003240int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003241 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003242 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003243
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003244 if (enable) {
3245 if (redPayloadtype < 0 || redPayloadtype > 127) {
3246 _engineStatisticsPtr->SetLastError(
3247 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003248 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003249 return -1;
3250 }
3251
3252 if (SetRedPayloadType(redPayloadtype) < 0) {
3253 _engineStatisticsPtr->SetLastError(
3254 VE_CODEC_ERROR, kTraceError,
3255 "SetSecondarySendCodec() Failed to register RED ACM");
3256 return -1;
3257 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003258 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003259
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003260 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003261 _engineStatisticsPtr->SetLastError(
3262 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003263 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003264 return -1;
3265 }
3266 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003267}
3268
3269int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003270Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003271{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003272 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003273 if (enabled)
3274 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003275 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003276 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 {
3278 _engineStatisticsPtr->SetLastError(
3279 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003280 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 "module");
3282 return -1;
3283 }
pkasting@chromium.orgdf9a41d2015-01-26 22:35:29 +00003284 redPayloadtype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +00003285 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3286 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003287 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 enabled, redPayloadtype);
3289 return 0;
3290 }
3291 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3292 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003293 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003294 return 0;
3295}
3296
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003297int Channel::SetCodecFECStatus(bool enable) {
3298 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3299 "Channel::SetCodecFECStatus()");
3300
3301 if (audio_coding_->SetCodecFEC(enable) != 0) {
3302 _engineStatisticsPtr->SetLastError(
3303 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3304 "SetCodecFECStatus() failed to set FEC state");
3305 return -1;
3306 }
3307 return 0;
3308}
3309
3310bool Channel::GetCodecFECStatus() {
3311 bool enabled = audio_coding_->CodecFEC();
3312 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3313 VoEId(_instanceId, _channelId),
3314 "GetCodecFECStatus() => enabled=%d", enabled);
3315 return enabled;
3316}
3317
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003318void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3319 // None of these functions can fail.
3320 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003321 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3322 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003323 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003324 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003325 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003326 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003327}
3328
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003329// Called when we are missing one or more packets.
3330int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003331 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3332}
3333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003334uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003335Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003336{
3337 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003338 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003339 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003340 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003341 return 0;
3342}
3343
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003344void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003345 int sample_rate,
Peter Kastingdce40cf2015-08-24 14:52:23 -07003346 size_t number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003347 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003348 CodecInst codec;
3349 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003350
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003351 if (!mono_recording_audio_.get()) {
3352 // Temporary space for DownConvertToCodecFormat.
3353 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003354 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003355 DownConvertToCodecFormat(audio_data,
3356 number_of_frames,
3357 number_of_channels,
3358 sample_rate,
3359 codec.channels,
3360 codec.plfreq,
3361 mono_recording_audio_.get(),
3362 &input_resampler_,
3363 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003364}
3365
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003366uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003367Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003368{
3369 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3370 "Channel::PrepareEncodeAndSend()");
3371
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003372 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003373 {
3374 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3375 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003376 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003377 }
3378
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003379 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003380 {
3381 MixOrReplaceAudioWithFile(mixingFrequency);
3382 }
3383
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003384 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3385 if (is_muted) {
3386 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003387 }
3388
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003389 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003390 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003391 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003392 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003393 if (_inputExternalMediaCallbackPtr)
3394 {
3395 _inputExternalMediaCallbackPtr->Process(
3396 _channelId,
3397 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003398 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003399 _audioFrame.samples_per_channel_,
3400 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003401 isStereo);
3402 }
3403 }
3404
3405 InsertInbandDtmfTone();
3406
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003407 if (_includeAudioLevelIndication) {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003408 size_t length =
3409 _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003410 if (is_muted) {
3411 rms_level_.ProcessMuted(length);
3412 } else {
3413 rms_level_.Process(_audioFrame.data_, length);
3414 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003415 }
3416
niklase@google.com470e71d2011-07-07 08:21:25 +00003417 return 0;
3418}
3419
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003420uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003421Channel::EncodeAndSend()
3422{
3423 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3424 "Channel::EncodeAndSend()");
3425
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003426 assert(_audioFrame.num_channels_ <= 2);
3427 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003428 {
3429 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3430 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003431 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003432 }
3433
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003434 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003435
3436 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3437
3438 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003439 _audioFrame.timestamp_ = _timeStamp;
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003440 // This call will trigger AudioPacketizationCallback::SendData if encoding
3441 // is done and payload is ready for packetization and transmission.
3442 // Otherwise, it will return without invoking the callback.
3443 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) < 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003444 {
3445 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3446 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003447 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003448 }
3449
Peter Kastingb7e50542015-06-11 12:55:50 -07003450 _timeStamp += static_cast<uint32_t>(_audioFrame.samples_per_channel_);
henrik.lundin@webrtc.orgf56c1622015-03-02 12:29:30 +00003451 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003452}
3453
Minyue2013aec2015-05-13 14:14:42 +02003454void Channel::DisassociateSendChannel(int channel_id) {
3455 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
3456 Channel* channel = associate_send_channel_.channel();
3457 if (channel && channel->ChannelId() == channel_id) {
3458 // If this channel is associated with a send channel of the specified
3459 // Channel ID, disassociate with it.
3460 ChannelOwner ref(NULL);
3461 associate_send_channel_ = ref;
3462 }
3463}
3464
niklase@google.com470e71d2011-07-07 08:21:25 +00003465int Channel::RegisterExternalMediaProcessing(
3466 ProcessingTypes type,
3467 VoEMediaProcess& processObject)
3468{
3469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3470 "Channel::RegisterExternalMediaProcessing()");
3471
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003472 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003473
3474 if (kPlaybackPerChannel == type)
3475 {
3476 if (_outputExternalMediaCallbackPtr)
3477 {
3478 _engineStatisticsPtr->SetLastError(
3479 VE_INVALID_OPERATION, kTraceError,
3480 "Channel::RegisterExternalMediaProcessing() "
3481 "output external media already enabled");
3482 return -1;
3483 }
3484 _outputExternalMediaCallbackPtr = &processObject;
3485 _outputExternalMedia = true;
3486 }
3487 else if (kRecordingPerChannel == type)
3488 {
3489 if (_inputExternalMediaCallbackPtr)
3490 {
3491 _engineStatisticsPtr->SetLastError(
3492 VE_INVALID_OPERATION, kTraceError,
3493 "Channel::RegisterExternalMediaProcessing() "
3494 "output external media already enabled");
3495 return -1;
3496 }
3497 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003498 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003499 }
3500 return 0;
3501}
3502
3503int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3504{
3505 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3506 "Channel::DeRegisterExternalMediaProcessing()");
3507
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003508 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003509
3510 if (kPlaybackPerChannel == type)
3511 {
3512 if (!_outputExternalMediaCallbackPtr)
3513 {
3514 _engineStatisticsPtr->SetLastError(
3515 VE_INVALID_OPERATION, kTraceWarning,
3516 "Channel::DeRegisterExternalMediaProcessing() "
3517 "output external media already disabled");
3518 return 0;
3519 }
3520 _outputExternalMedia = false;
3521 _outputExternalMediaCallbackPtr = NULL;
3522 }
3523 else if (kRecordingPerChannel == type)
3524 {
3525 if (!_inputExternalMediaCallbackPtr)
3526 {
3527 _engineStatisticsPtr->SetLastError(
3528 VE_INVALID_OPERATION, kTraceWarning,
3529 "Channel::DeRegisterExternalMediaProcessing() "
3530 "input external media already disabled");
3531 return 0;
3532 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003533 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003534 _inputExternalMediaCallbackPtr = NULL;
3535 }
3536
3537 return 0;
3538}
3539
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003540int Channel::SetExternalMixing(bool enabled) {
3541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3542 "Channel::SetExternalMixing(enabled=%d)", enabled);
3543
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003544 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003545 {
3546 _engineStatisticsPtr->SetLastError(
3547 VE_INVALID_OPERATION, kTraceError,
3548 "Channel::SetExternalMixing() "
3549 "external mixing cannot be changed while playing.");
3550 return -1;
3551 }
3552
3553 _externalMixing = enabled;
3554
3555 return 0;
3556}
3557
niklase@google.com470e71d2011-07-07 08:21:25 +00003558int
niklase@google.com470e71d2011-07-07 08:21:25 +00003559Channel::GetNetworkStatistics(NetworkStatistics& stats)
3560{
3561 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3562 "Channel::GetNetworkStatistics()");
minyue@webrtc.orgc0bd7be2015-02-18 15:24:13 +00003563 return audio_coding_->GetNetworkStatistics(&stats);
niklase@google.com470e71d2011-07-07 08:21:25 +00003564}
3565
wu@webrtc.org24301a62013-12-13 19:17:43 +00003566void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3567 audio_coding_->GetDecodingCallStatistics(stats);
3568}
3569
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003570bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3571 int* playout_buffer_delay_ms) const {
deadbeef74375882015-08-13 12:09:10 -07003572 CriticalSectionScoped cs(video_sync_lock_.get());
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003573 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003575 "Channel::GetDelayEstimate() no valid estimate.");
3576 return false;
3577 }
3578 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3579 _recPacketDelayMs;
3580 *playout_buffer_delay_ms = playout_delay_ms_;
3581 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3582 "Channel::GetDelayEstimate()");
3583 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003584}
3585
deadbeef74375882015-08-13 12:09:10 -07003586int Channel::LeastRequiredDelayMs() const {
3587 return audio_coding_->LeastRequiredDelayMs();
3588}
3589
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003590int Channel::SetInitialPlayoutDelay(int delay_ms)
3591{
3592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3593 "Channel::SetInitialPlayoutDelay()");
3594 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3595 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3596 {
3597 _engineStatisticsPtr->SetLastError(
3598 VE_INVALID_ARGUMENT, kTraceError,
3599 "SetInitialPlayoutDelay() invalid min delay");
3600 return -1;
3601 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003602 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3606 "SetInitialPlayoutDelay() failed to set min playout delay");
3607 return -1;
3608 }
3609 return 0;
3610}
3611
3612
niklase@google.com470e71d2011-07-07 08:21:25 +00003613int
3614Channel::SetMinimumPlayoutDelay(int delayMs)
3615{
3616 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3617 "Channel::SetMinimumPlayoutDelay()");
3618 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3619 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3620 {
3621 _engineStatisticsPtr->SetLastError(
3622 VE_INVALID_ARGUMENT, kTraceError,
3623 "SetMinimumPlayoutDelay() invalid min delay");
3624 return -1;
3625 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003626 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003627 {
3628 _engineStatisticsPtr->SetLastError(
3629 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3630 "SetMinimumPlayoutDelay() failed to set min playout delay");
3631 return -1;
3632 }
3633 return 0;
3634}
3635
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003636int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3637 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3638 "Channel::GetPlayoutTimestamp()");
deadbeef74375882015-08-13 12:09:10 -07003639 uint32_t playout_timestamp_rtp = 0;
3640 {
3641 CriticalSectionScoped cs(video_sync_lock_.get());
3642 playout_timestamp_rtp = playout_timestamp_rtp_;
3643 }
3644 if (playout_timestamp_rtp == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003645 _engineStatisticsPtr->SetLastError(
3646 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3647 "GetPlayoutTimestamp() failed to retrieve timestamp");
3648 return -1;
3649 }
deadbeef74375882015-08-13 12:09:10 -07003650 timestamp = playout_timestamp_rtp;
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003651 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3652 VoEId(_instanceId,_channelId),
3653 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3654 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003655}
3656
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003657int Channel::SetInitTimestamp(unsigned int timestamp) {
3658 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +00003659 "Channel::SetInitTimestamp()");
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003660 if (channel_state_.Get().sending) {
3661 _engineStatisticsPtr->SetLastError(VE_SENDING, kTraceError,
3662 "SetInitTimestamp() already sending");
3663 return -1;
3664 }
3665 _rtpRtcpModule->SetStartTimestamp(timestamp);
3666 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003667}
3668
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00003669int Channel::SetInitSequenceNumber(short sequenceNumber) {
3670 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3671 "Channel::SetInitSequenceNumber()");
3672 if (channel_state_.Get().sending) {
3673 _engineStatisticsPtr->SetLastError(
3674 VE_SENDING, kTraceError, "SetInitSequenceNumber() already sending");
3675 return -1;
3676 }
3677 _rtpRtcpModule->SetSequenceNumber(sequenceNumber);
3678 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003679}
3680
3681int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003682Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00003683{
3684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3685 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003686 *rtpRtcpModule = _rtpRtcpModule.get();
3687 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00003688 return 0;
3689}
3690
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003691// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
3692// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003693int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00003694Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003695{
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003696 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003697 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003698
3699 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003700 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003701
3702 if (_inputFilePlayerPtr == NULL)
3703 {
3704 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3705 VoEId(_instanceId, _channelId),
3706 "Channel::MixOrReplaceAudioWithFile() fileplayer"
3707 " doesnt exist");
3708 return -1;
3709 }
3710
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003711 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003712 fileSamples,
3713 mixingFrequency) == -1)
3714 {
3715 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3716 VoEId(_instanceId, _channelId),
3717 "Channel::MixOrReplaceAudioWithFile() file mixing "
3718 "failed");
3719 return -1;
3720 }
3721 if (fileSamples == 0)
3722 {
3723 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3724 VoEId(_instanceId, _channelId),
3725 "Channel::MixOrReplaceAudioWithFile() file is ended");
3726 return 0;
3727 }
3728 }
3729
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003730 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003731
3732 if (_mixFileWithMicrophone)
3733 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003734 // Currently file stream is always mono.
3735 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003736 MixWithSat(_audioFrame.data_,
3737 _audioFrame.num_channels_,
3738 fileBuffer.get(),
3739 1,
3740 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003741 }
3742 else
3743 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003744 // Replace ACM audio with file.
3745 // Currently file stream is always mono.
3746 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00003747 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003748 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003749 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00003750 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00003751 mixingFrequency,
3752 AudioFrame::kNormalSpeech,
3753 AudioFrame::kVadUnknown,
3754 1);
3755
3756 }
3757 return 0;
3758}
3759
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003760int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003761Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00003762 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003763{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00003764 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003765
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +00003766 rtc::scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
Peter Kastingdce40cf2015-08-24 14:52:23 -07003767 size_t fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003768
3769 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003770 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003771
3772 if (_outputFilePlayerPtr == NULL)
3773 {
3774 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3775 VoEId(_instanceId, _channelId),
3776 "Channel::MixAudioWithFile() file mixing failed");
3777 return -1;
3778 }
3779
3780 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003781 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00003782 fileSamples,
3783 mixingFrequency) == -1)
3784 {
3785 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3786 VoEId(_instanceId, _channelId),
3787 "Channel::MixAudioWithFile() file mixing failed");
3788 return -1;
3789 }
3790 }
3791
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003792 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00003793 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00003794 // Currently file stream is always mono.
3795 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003796 MixWithSat(audioFrame.data_,
3797 audioFrame.num_channels_,
3798 fileBuffer.get(),
3799 1,
3800 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003801 }
3802 else
3803 {
3804 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
Peter Kastingdce40cf2015-08-24 14:52:23 -07003805 "Channel::MixAudioWithFile() samples_per_channel_(%" PRIuS ") != "
3806 "fileSamples(%" PRIuS ")",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003807 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003808 return -1;
3809 }
3810
3811 return 0;
3812}
3813
3814int
3815Channel::InsertInbandDtmfTone()
3816{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003817 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00003818 if (_inbandDtmfQueue.PendingDtmf() &&
3819 !_inbandDtmfGenerator.IsAddingTone() &&
3820 _inbandDtmfGenerator.DelaySinceLastTone() >
3821 kMinTelephoneEventSeparationMs)
3822 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003823 int8_t eventCode(0);
3824 uint16_t lengthMs(0);
3825 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003826
3827 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
3828 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
3829 if (_playInbandDtmfEvent)
3830 {
3831 // Add tone to output mixer using a reduced length to minimize
3832 // risk of echo.
3833 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
3834 attenuationDb);
3835 }
3836 }
3837
3838 if (_inbandDtmfGenerator.IsAddingTone())
3839 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003840 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003841 _inbandDtmfGenerator.GetSampleRate(frequency);
3842
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003843 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00003844 {
3845 // Update sample rate of Dtmf tone since the mixing frequency
3846 // has changed.
3847 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003848 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00003849 // Reset the tone to be added taking the new sample rate into
3850 // account.
3851 _inbandDtmfGenerator.ResetTone();
3852 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003853
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003854 int16_t toneBuffer[320];
3855 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003856 // Get 10ms tone segment and set time since last tone to zero
3857 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
3858 {
3859 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3860 VoEId(_instanceId, _channelId),
3861 "Channel::EncodeAndSend() inserting Dtmf failed");
3862 return -1;
3863 }
3864
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003865 // Replace mixed audio with DTMF tone.
Peter Kastingdce40cf2015-08-24 14:52:23 -07003866 for (size_t sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003867 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003868 sample++)
3869 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003870 for (int channel = 0;
3871 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003872 channel++)
3873 {
Peter Kastingdce40cf2015-08-24 14:52:23 -07003874 const size_t index =
3875 sample * _audioFrame.num_channels_ + channel;
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003876 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00003877 }
3878 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003879
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003880 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00003881 } else
3882 {
3883 // Add 10ms to "delay-since-last-tone" counter
3884 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
3885 }
3886 return 0;
3887}
3888
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003889int32_t
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00003890Channel::SendPacketRaw(const void *data, size_t len, bool RTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +00003891{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00003892 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003893 if (_transportPtr == NULL)
3894 {
3895 return -1;
3896 }
3897 if (!RTCP)
3898 {
3899 return _transportPtr->SendPacket(_channelId, data, len);
3900 }
3901 else
3902 {
3903 return _transportPtr->SendRTCPPacket(_channelId, data, len);
3904 }
3905}
3906
deadbeef74375882015-08-13 12:09:10 -07003907void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3908 uint32_t playout_timestamp = 0;
3909
3910 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
3911 // This can happen if this channel has not been received any RTP packet. In
3912 // this case, NetEq is not capable of computing playout timestamp.
3913 return;
3914 }
3915
3916 uint16_t delay_ms = 0;
3917 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3918 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3919 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3920 " delay from the ADM");
3921 _engineStatisticsPtr->SetLastError(
3922 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3923 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3924 return;
3925 }
3926
3927 jitter_buffer_playout_timestamp_ = playout_timestamp;
3928
3929 // Remove the playout delay.
3930 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
3931
3932 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3933 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3934 playout_timestamp);
3935
3936 {
3937 CriticalSectionScoped cs(video_sync_lock_.get());
3938 if (rtcp) {
3939 playout_timestamp_rtcp_ = playout_timestamp;
3940 } else {
3941 playout_timestamp_rtp_ = playout_timestamp;
3942 }
3943 playout_delay_ms_ = delay_ms;
3944 }
3945}
3946
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003947// Called for incoming RTP packets after successful RTP header parsing.
3948void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
3949 uint16_t sequence_number) {
3950 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3951 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
3952 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00003953
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003954 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00003955 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00003956
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003957 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
3958 // every incoming packet.
3959 uint32_t timestamp_diff_ms = (rtp_timestamp -
3960 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00003961 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
3962 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
3963 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
3964 // timestamp, the resulting difference is negative, but is set to zero.
3965 // This can happen when a network glitch causes a packet to arrive late,
3966 // and during long comfort noise periods with clock drift.
3967 timestamp_diff_ms = 0;
3968 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003969
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003970 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
3971 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003972
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003973 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00003974
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003975 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00003976
deadbeef74375882015-08-13 12:09:10 -07003977 {
3978 CriticalSectionScoped cs(video_sync_lock_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00003979
deadbeef74375882015-08-13 12:09:10 -07003980 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
3981 _recPacketDelayMs = packet_delay_ms;
3982 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003983
deadbeef74375882015-08-13 12:09:10 -07003984 if (_average_jitter_buffer_delay_us == 0) {
3985 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
3986 return;
3987 }
3988
3989 // Filter average delay value using exponential filter (alpha is
3990 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
3991 // risk of rounding error) and compensate for it in GetDelayEstimate()
3992 // later.
3993 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
3994 1000 * timestamp_diff_ms + 500) / 8;
3995 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003996}
3997
3998void
3999Channel::RegisterReceiveCodecsToRTPModule()
4000{
4001 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4002 "Channel::RegisterReceiveCodecsToRTPModule()");
4003
4004
4005 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004006 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004007
4008 for (int idx = 0; idx < nSupportedCodecs; idx++)
4009 {
4010 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004011 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004012 (rtp_receiver_->RegisterReceivePayload(
4013 codec.plname,
4014 codec.pltype,
4015 codec.plfreq,
4016 codec.channels,
4017 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004018 {
4019 WEBRTC_TRACE(
4020 kTraceWarning,
4021 kTraceVoice,
4022 VoEId(_instanceId, _channelId),
4023 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4024 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4025 codec.plname, codec.pltype, codec.plfreq,
4026 codec.channels, codec.rate);
4027 }
4028 else
4029 {
4030 WEBRTC_TRACE(
4031 kTraceInfo,
4032 kTraceVoice,
4033 VoEId(_instanceId, _channelId),
4034 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004035 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004036 "receiver",
4037 codec.plname, codec.pltype, codec.plfreq,
4038 codec.channels, codec.rate);
4039 }
4040 }
4041}
4042
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004043// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004044int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004045 CodecInst codec;
4046 bool found_red = false;
4047
4048 // Get default RED settings from the ACM database
4049 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4050 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004051 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004052 if (!STR_CASE_CMP(codec.plname, "RED")) {
4053 found_red = true;
4054 break;
4055 }
4056 }
4057
4058 if (!found_red) {
4059 _engineStatisticsPtr->SetLastError(
4060 VE_CODEC_ERROR, kTraceError,
4061 "SetRedPayloadType() RED is not supported");
4062 return -1;
4063 }
4064
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004065 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004066 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004067 _engineStatisticsPtr->SetLastError(
4068 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4069 "SetRedPayloadType() RED registration in ACM module failed");
4070 return -1;
4071 }
4072
4073 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4074 _engineStatisticsPtr->SetLastError(
4075 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4076 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4077 return -1;
4078 }
4079 return 0;
4080}
4081
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004082int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4083 unsigned char id) {
4084 int error = 0;
4085 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4086 if (enable) {
4087 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4088 }
4089 return error;
4090}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004091
wu@webrtc.org94454b72014-06-05 20:34:08 +00004092int32_t Channel::GetPlayoutFrequency() {
4093 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4094 CodecInst current_recive_codec;
4095 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4096 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4097 // Even though the actual sampling rate for G.722 audio is
4098 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4099 // 8,000 Hz because that value was erroneously assigned in
4100 // RFC 1890 and must remain unchanged for backward compatibility.
4101 playout_frequency = 8000;
4102 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4103 // We are resampling Opus internally to 32,000 Hz until all our
4104 // DSP routines can operate at 48,000 Hz, but the RTP clock
4105 // rate for the Opus payload format is standardized to 48,000 Hz,
4106 // because that is the maximum supported decoding sampling rate.
4107 playout_frequency = 48000;
4108 }
4109 }
4110 return playout_frequency;
4111}
4112
Minyue2013aec2015-05-13 14:14:42 +02004113int64_t Channel::GetRTT(bool allow_associate_channel) const {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004114 RTCPMethod method = _rtpRtcpModule->RTCP();
4115 if (method == kRtcpOff) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004116 return 0;
4117 }
4118 std::vector<RTCPReportBlock> report_blocks;
4119 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
Minyue2013aec2015-05-13 14:14:42 +02004120
4121 int64_t rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004122 if (report_blocks.empty()) {
Minyue2013aec2015-05-13 14:14:42 +02004123 if (allow_associate_channel) {
4124 CriticalSectionScoped lock(assoc_send_channel_lock_.get());
4125 Channel* channel = associate_send_channel_.channel();
4126 // Tries to get RTT from an associated channel. This is important for
4127 // receive-only channels.
4128 if (channel) {
4129 // To prevent infinite recursion and deadlock, calling GetRTT of
4130 // associate channel should always use "false" for argument:
4131 // |allow_associate_channel|.
4132 rtt = channel->GetRTT(false);
4133 }
4134 }
4135 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004136 }
4137
4138 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4139 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4140 for (; it != report_blocks.end(); ++it) {
4141 if (it->remoteSSRC == remoteSSRC)
4142 break;
4143 }
4144 if (it == report_blocks.end()) {
4145 // We have not received packets with SSRC matching the report blocks.
4146 // To calculate RTT we try with the SSRC of the first report block.
4147 // This is very important for send-only channels where we don't know
4148 // the SSRC of the other end.
4149 remoteSSRC = report_blocks[0].remoteSSRC;
4150 }
Minyue2013aec2015-05-13 14:14:42 +02004151
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004152 int64_t avg_rtt = 0;
4153 int64_t max_rtt= 0;
4154 int64_t min_rtt = 0;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004155 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4156 != 0) {
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004157 return 0;
4158 }
pkasting@chromium.org16825b12015-01-12 21:51:21 +00004159 return rtt;
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004160}
4161
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004162} // namespace voe
4163} // namespace webrtc