blob: 6d6b099cd119f538ed4d91277a5831850a6f6db9 [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
wu@webrtc.org94454b72014-06-05 20:34:08 +000013#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000014#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000015#include "webrtc/modules/audio_device/include/audio_device.h"
16#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000017#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000018#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
19#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
21#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000022#include "webrtc/modules/utility/interface/audio_frame_operations.h"
23#include "webrtc/modules/utility/interface/process_thread.h"
24#include "webrtc/modules/utility/interface/rtp_dump.h"
25#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
26#include "webrtc/system_wrappers/interface/logging.h"
27#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000028#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000029#include "webrtc/voice_engine/include/voe_base.h"
30#include "webrtc/voice_engine/include/voe_external_media.h"
31#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
32#include "webrtc/voice_engine/output_mixer.h"
33#include "webrtc/voice_engine/statistics.h"
34#include "webrtc/voice_engine/transmit_mixer.h"
35#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37#if defined(_WIN32)
38#include <Qos.h>
39#endif
40
andrew@webrtc.org50419b02012-11-14 19:07:54 +000041namespace webrtc {
42namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000043
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000044// Extend the default RTCP statistics struct with max_jitter, defined as the
45// maximum jitter value seen in an RTCP report block.
46struct ChannelStatistics : public RtcpStatistics {
47 ChannelStatistics() : rtcp(), max_jitter(0) {}
48
49 RtcpStatistics rtcp;
50 uint32_t max_jitter;
51};
52
53// Statistics callback, called at each generation of a new RTCP report block.
54class StatisticsProxy : public RtcpStatisticsCallback {
55 public:
56 StatisticsProxy(uint32_t ssrc)
57 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
58 ssrc_(ssrc) {}
59 virtual ~StatisticsProxy() {}
60
61 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
62 uint32_t ssrc) OVERRIDE {
63 if (ssrc != ssrc_)
64 return;
65
66 CriticalSectionScoped cs(stats_lock_.get());
67 stats_.rtcp = statistics;
68 if (statistics.jitter > stats_.max_jitter) {
69 stats_.max_jitter = statistics.jitter;
70 }
71 }
72
73 void ResetStatistics() {
74 CriticalSectionScoped cs(stats_lock_.get());
75 stats_ = ChannelStatistics();
76 }
77
78 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.
87 scoped_ptr<CriticalSectionWrapper> stats_lock_;
88 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000092class VoEBitrateObserver : public BitrateObserver {
93 public:
94 explicit VoEBitrateObserver(Channel* owner)
95 : owner_(owner) {}
96 virtual ~VoEBitrateObserver() {}
97
98 // Implements BitrateObserver.
99 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
100 const uint8_t fraction_lost,
101 const uint32_t rtt) OVERRIDE {
102 // |fraction_lost| has a scale of 0 - 255.
103 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
104 }
105
106 private:
107 Channel* owner_;
108};
109
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000110int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000111Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000112 uint8_t payloadType,
113 uint32_t timeStamp,
114 const uint8_t* payloadData,
115 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 const RTPFragmentationHeader* fragmentation)
117{
118 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
119 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
120 " payloadSize=%u, fragmentation=0x%x)",
121 frameType, payloadType, timeStamp, payloadSize, fragmentation);
122
123 if (_includeAudioLevelIndication)
124 {
125 // Store current audio level in the RTP/RTCP module.
126 // The level will be used in combination with voice-activity state
127 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000128 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 }
130
131 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
132 // packetization.
133 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000134 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000135 payloadType,
136 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000137 // Leaving the time when this frame was
138 // received from the capture device as
139 // undefined for voice for now.
140 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 payloadData,
142 payloadSize,
143 fragmentation) == -1)
144 {
145 _engineStatisticsPtr->SetLastError(
146 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
147 "Channel::SendData() failed to send data to RTP/RTCP module");
148 return -1;
149 }
150
151 _lastLocalTimeStamp = timeStamp;
152 _lastPayloadType = payloadType;
153
154 return 0;
155}
156
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000157int32_t
158Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000159{
160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
161 "Channel::InFrameType(frameType=%d)", frameType);
162
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000163 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 // 1 indicates speech
165 _sendFrameType = (frameType == 1) ? 1 : 0;
166 return 0;
167}
168
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000170Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000171{
172 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
173 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
174
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000175 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 if (_rxVadObserverPtr)
177 {
178 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
179 }
180
181 return 0;
182}
183
184int
185Channel::SendPacket(int channel, const void *data, int len)
186{
187 channel = VoEChannelId(channel);
188 assert(channel == _channelId);
189
190 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
191 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
192
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000193 CriticalSectionScoped cs(&_callbackCritSect);
194
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 if (_transportPtr == NULL)
196 {
197 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
198 "Channel::SendPacket() failed to send RTP packet due to"
199 " invalid transport object");
200 return -1;
201 }
202
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000203 uint8_t* bufferToSendPtr = (uint8_t*)data;
204 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205
206 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000207 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000208 {
209 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
210 VoEId(_instanceId,_channelId),
211 "Channel::SendPacket() RTP dump to output file failed");
212 }
213
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000214 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
215 bufferLength);
216 if (n < 0) {
217 std::string transport_name =
218 _externalTransport ? "external transport" : "WebRtc sockets";
219 WEBRTC_TRACE(kTraceError, kTraceVoice,
220 VoEId(_instanceId,_channelId),
221 "Channel::SendPacket() RTP transmission using %s failed",
222 transport_name.c_str());
223 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000225 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226}
227
228int
229Channel::SendRTCPPacket(int channel, const void *data, int len)
230{
231 channel = VoEChannelId(channel);
232 assert(channel == _channelId);
233
234 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
235 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
236
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000237 CriticalSectionScoped cs(&_callbackCritSect);
238 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000240 WEBRTC_TRACE(kTraceError, kTraceVoice,
241 VoEId(_instanceId,_channelId),
242 "Channel::SendRTCPPacket() failed to send RTCP packet"
243 " due to invalid transport object");
244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
246
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000247 uint8_t* bufferToSendPtr = (uint8_t*)data;
248 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
250 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 {
253 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254 VoEId(_instanceId,_channelId),
255 "Channel::SendPacket() RTCP dump to output file failed");
256 }
257
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 int n = _transportPtr->SendRTCPPacket(channel,
259 bufferToSendPtr,
260 bufferLength);
261 if (n < 0) {
262 std::string transport_name =
263 _externalTransport ? "external transport" : "WebRtc sockets";
264 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
265 VoEId(_instanceId,_channelId),
266 "Channel::SendRTCPPacket() transmission using %s failed",
267 transport_name.c_str());
268 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000270 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271}
272
273void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000274Channel::OnPlayTelephoneEvent(int32_t id,
275 uint8_t event,
276 uint16_t lengthMs,
277 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000278{
279 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
280 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000281 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
283 if (!_playOutbandDtmfEvent || (event > 15))
284 {
285 // Ignore callback since feedback is disabled or event is not a
286 // Dtmf tone event.
287 return;
288 }
289
290 assert(_outputMixerPtr != NULL);
291
292 // Start playing out the Dtmf tone (if playout is enabled).
293 // Reduce length of tone with 80ms to the reduce risk of echo.
294 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
295}
296
297void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000298Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000299{
300 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
301 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000302 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000303
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000304 // Update ssrc so that NTP for AV sync can be updated.
305 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000306}
307
pbos@webrtc.org92135212013-05-14 08:31:39 +0000308void Channel::OnIncomingCSRCChanged(int32_t id,
309 uint32_t CSRC,
310 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000311{
312 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
313 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
314 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000315}
316
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000317void Channel::ResetStatistics(uint32_t ssrc) {
318 StreamStatistician* statistician =
319 rtp_receive_statistics_->GetStatistician(ssrc);
320 if (statistician) {
321 statistician->ResetStatistics();
322 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000323 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000324}
325
niklase@google.com470e71d2011-07-07 08:21:25 +0000326void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000327Channel::OnApplicationDataReceived(int32_t id,
328 uint8_t subType,
329 uint32_t name,
330 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000331 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000332{
333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
334 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
335 " name=%u, length=%u)",
336 id, subType, name, length);
337
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000338 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 assert(channel == _channelId);
340
341 if (_rtcpObserver)
342 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000343 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 if (_rtcpObserverPtr)
346 {
347 _rtcpObserverPtr->OnApplicationDataReceived(channel,
348 subType,
349 name,
350 data,
351 length);
352 }
353 }
354}
355
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000356int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000357Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000358 int32_t id,
359 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000360 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000361 int frequency,
362 uint8_t channels,
363 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
367 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
368 id, payloadType, payloadName, frequency, channels, rate);
369
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000370 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000372 CodecInst receiveCodec = {0};
373 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
375 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 receiveCodec.plfreq = frequency;
377 receiveCodec.channels = channels;
378 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000379 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000380
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000381 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 receiveCodec.pacsize = dummyCodec.pacsize;
383
384 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000385 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 {
387 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000388 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 "Channel::OnInitializeDecoder() invalid codec ("
390 "pt=%d, name=%s) received - 1", payloadType, payloadName);
391 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
392 return -1;
393 }
394
395 return 0;
396}
397
398void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000399Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000400{
401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
402 "Channel::OnPacketTimeout(id=%d)", id);
403
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000404 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 if (_voiceEngineObserverPtr)
406 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000407 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000409 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 assert(channel == _channelId);
411 // Ensure that next OnReceivedPacket() callback will trigger
412 // a VE_PACKET_RECEIPT_RESTARTED callback.
413 _rtpPacketTimedOut = true;
414 // Deliver callback to the observer
415 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
416 VoEId(_instanceId,_channelId),
417 "Channel::OnPacketTimeout() => "
418 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
419 _voiceEngineObserverPtr->CallbackOnError(channel,
420 VE_RECEIVE_PACKET_TIMEOUT);
421 }
422 }
423}
424
425void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000426Channel::OnReceivedPacket(int32_t id,
427 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000428{
429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
430 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
431 id, packetType);
432
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000433 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000434
435 // Notify only for the case when we have restarted an RTP session.
436 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
437 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000438 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 if (_voiceEngineObserverPtr)
440 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000441 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 assert(channel == _channelId);
443 // Reset timeout mechanism
444 _rtpPacketTimedOut = false;
445 // Deliver callback to the observer
446 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
447 VoEId(_instanceId,_channelId),
448 "Channel::OnPacketTimeout() =>"
449 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
450 _voiceEngineObserverPtr->CallbackOnError(
451 channel,
452 VE_PACKET_RECEIPT_RESTARTED);
453 }
454 }
455}
456
457void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000458Channel::OnPeriodicDeadOrAlive(int32_t id,
459 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000460{
461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
462 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
463
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000464 {
465 CriticalSectionScoped cs(&_callbackCritSect);
466 if (!_connectionObserver)
467 return;
468 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000469
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000470 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 assert(channel == _channelId);
472
473 // Use Alive as default to limit risk of false Dead detections
474 bool isAlive(true);
475
476 // Always mark the connection as Dead when the module reports kRtpDead
477 if (kRtpDead == alive)
478 {
479 isAlive = false;
480 }
481
482 // It is possible that the connection is alive even if no RTP packet has
483 // been received for a long time since the other side might use VAD/DTX
484 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000485 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 {
487 // Detect Alive for all NetEQ states except for the case when we are
488 // in PLC_CNG state.
489 // PLC_CNG <=> background noise only due to long expand or error.
490 // Note that, the case where the other side stops sending during CNG
491 // state will be detected as Alive. Dead is is not set until after
492 // missing RTCP packets for at least twelve seconds (handled
493 // internally by the RTP/RTCP module).
494 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
495 }
496
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 // Send callback to the registered observer
498 if (_connectionObserver)
499 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000500 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 if (_connectionObserverPtr)
502 {
503 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
504 }
505 }
506}
507
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000508int32_t
509Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000510 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 const WebRtcRTPHeader* rtpHeader)
512{
513 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
514 "Channel::OnReceivedPayloadData(payloadSize=%d,"
515 " payloadType=%u, audioChannel=%u)",
516 payloadSize,
517 rtpHeader->header.payloadType,
518 rtpHeader->type.Audio.channel);
519
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000520 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 {
522 // Avoid inserting into NetEQ when we are not playing. Count the
523 // packet as discarded.
524 WEBRTC_TRACE(kTraceStream, kTraceVoice,
525 VoEId(_instanceId, _channelId),
526 "received packet is discarded since playing is not"
527 " activated");
528 _numberOfDiscardedPackets++;
529 return 0;
530 }
531
532 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000533 if (audio_coding_->IncomingPacket(payloadData,
534 payloadSize,
535 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 {
537 _engineStatisticsPtr->SetLastError(
538 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
539 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
540 return -1;
541 }
542
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000543 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 UpdatePacketDelay(rtpHeader->header.timestamp,
545 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000546
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000547 uint16_t round_trip_time = 0;
548 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
549 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000550
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000551 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000552 round_trip_time);
553 if (!nack_list.empty()) {
554 // Can't use nack_list.data() since it's not supported by all
555 // compilers.
556 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 return 0;
559}
560
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000561bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
562 int rtp_packet_length) {
563 RTPHeader header;
564 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
565 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
566 "IncomingPacket invalid RTP header");
567 return false;
568 }
569 header.payload_type_frequency =
570 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
571 if (header.payload_type_frequency < 0)
572 return false;
573 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
574}
575
pbos@webrtc.org92135212013-05-14 08:31:39 +0000576int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000577{
578 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
579 "Channel::GetAudioFrame(id=%d)", id);
580
581 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000582 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
583 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 {
585 WEBRTC_TRACE(kTraceError, kTraceVoice,
586 VoEId(_instanceId,_channelId),
587 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000588 // In all likelihood, the audio in this frame is garbage. We return an
589 // error so that the audio mixer module doesn't add it to the mix. As
590 // a result, it won't be played out and the actions skipped here are
591 // irrelevant.
592 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 }
594
595 if (_RxVadDetection)
596 {
597 UpdateRxVadDetection(audioFrame);
598 }
599
600 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000601 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000603 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000605 ChannelState::State state = channel_state_.Get();
606
607 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000608 int err = rx_audioproc_->ProcessStream(&audioFrame);
609 if (err) {
610 LOG(LS_ERROR) << "ProcessStream() error: " << err;
611 assert(false);
612 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 }
614
wu@webrtc.org63420662013-10-17 18:28:55 +0000615 float output_gain = 1.0f;
616 float left_pan = 1.0f;
617 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000619 CriticalSectionScoped cs(&volume_settings_critsect_);
620 output_gain = _outputGain;
621 left_pan = _panLeft;
622 right_pan= _panRight;
623 }
624
625 // Output volume scaling
626 if (output_gain < 0.99f || output_gain > 1.01f)
627 {
628 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 }
630
631 // Scale left and/or right channel(s) if stereo and master balance is
632 // active
633
wu@webrtc.org63420662013-10-17 18:28:55 +0000634 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000636 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 {
638 // Emulate stereo mode since panning is active.
639 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000640 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 }
642 // For true stereo mode (when we are receiving a stereo signal), no
643 // action is needed.
644
645 // Do the panning operation (the audio frame contains stereo at this
646 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000647 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 }
649
650 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000651 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000653 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 }
655
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 // External media
657 if (_outputExternalMedia)
658 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000659 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000660 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 if (_outputExternalMediaCallbackPtr)
662 {
663 _outputExternalMediaCallbackPtr->Process(
664 _channelId,
665 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000666 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000667 audioFrame.samples_per_channel_,
668 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 isStereo);
670 }
671 }
672
673 // Record playout if enabled
674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000675 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000676
677 if (_outputFileRecording && _outputFileRecorderPtr)
678 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000679 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000680 }
681 }
682
683 // Measure audio level (0-9)
684 _outputAudioLevel.ComputeLevel(audioFrame);
685
wu@webrtc.org94454b72014-06-05 20:34:08 +0000686 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
687 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000688 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000689 }
690
691 if (capture_start_rtp_time_stamp_ >= 0) {
692 // audioFrame.timestamp_ should be valid from now on.
693
694 // Compute elapsed time.
695 int64_t unwrap_timestamp =
696 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
697 audioFrame.elapsed_time_ms_ =
698 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
699 (GetPlayoutFrequency() / 1000);
700
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000701 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000702 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000703 // Compute ntp time.
704 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
705 audioFrame.timestamp_);
706 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
707 if (audioFrame.ntp_time_ms_ > 0) {
708 // Compute |capture_start_ntp_time_ms_| so that
709 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
710 capture_start_ntp_time_ms_ =
711 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
712 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000713 }
714 }
715
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 return 0;
717}
718
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000719int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000720Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000721{
722 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
723 "Channel::NeededFrequency(id=%d)", id);
724
725 int highestNeeded = 0;
726
727 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000728 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000729
730 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000731 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000733 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 }
735 else
736 {
737 highestNeeded = receiveFrequency;
738 }
739
740 // Special case, if we're playing a file on the playout side
741 // we take that frequency into consideration as well
742 // This is not needed on sending side, since the codec will
743 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000744 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000746 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000747 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 {
749 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
750 {
751 highestNeeded=_outputFilePlayerPtr->Frequency();
752 }
753 }
754 }
755
756 return(highestNeeded);
757}
758
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000759int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000760Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000761 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000762 uint32_t instanceId,
763 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000764{
765 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
766 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
767 channelId, instanceId);
768
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000769 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 if (channel == NULL)
771 {
772 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
773 VoEId(instanceId,channelId),
774 "Channel::CreateChannel() unable to allocate memory for"
775 " channel");
776 return -1;
777 }
778 return 0;
779}
780
781void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000782Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000783{
784 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
785 "Channel::PlayNotification(id=%d, durationMs=%d)",
786 id, durationMs);
787
788 // Not implement yet
789}
790
791void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000792Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000793{
794 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
795 "Channel::RecordNotification(id=%d, durationMs=%d)",
796 id, durationMs);
797
798 // Not implement yet
799}
800
801void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000802Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000803{
804 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
805 "Channel::PlayFileEnded(id=%d)", id);
806
807 if (id == _inputFilePlayerId)
808 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000809 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
811 VoEId(_instanceId,_channelId),
812 "Channel::PlayFileEnded() => input file player module is"
813 " shutdown");
814 }
815 else if (id == _outputFilePlayerId)
816 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000817 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000818 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
819 VoEId(_instanceId,_channelId),
820 "Channel::PlayFileEnded() => output file player module is"
821 " shutdown");
822 }
823}
824
825void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000826Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000827{
828 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
829 "Channel::RecordFileEnded(id=%d)", id);
830
831 assert(id == _outputFileRecorderId);
832
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000833 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000834
835 _outputFileRecording = false;
836 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
837 VoEId(_instanceId,_channelId),
838 "Channel::RecordFileEnded() => output file recorder module is"
839 " shutdown");
840}
841
pbos@webrtc.org92135212013-05-14 08:31:39 +0000842Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000843 uint32_t instanceId,
844 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
846 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000847 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000849 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000850 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000851 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000852 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000853 rtp_receive_statistics_(ReceiveStatistics::Create(
854 Clock::GetRealTimeClock())),
855 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
856 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
857 this, this, rtp_payload_registry_.get())),
858 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000859 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000860 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 _rtpDumpIn(*RtpDump::CreateRtpDump()),
862 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000865 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 _inputFilePlayerPtr(NULL),
867 _outputFilePlayerPtr(NULL),
868 _outputFileRecorderPtr(NULL),
869 // Avoid conflict with other channels by adding 1024 - 1026,
870 // won't use as much as 1024 channels.
871 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
872 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
873 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
876 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 _inputExternalMediaCallbackPtr(NULL),
879 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000880 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
881 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000882 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000883 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000884 playout_timestamp_rtp_(0),
885 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000886 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000887 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000888 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000889 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000890 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
891 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000892 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000893 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000894 _outputMixerPtr(NULL),
895 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000896 _moduleProcessThreadPtr(NULL),
897 _audioDeviceModulePtr(NULL),
898 _voiceEngineObserverPtr(NULL),
899 _callbackCritSectPtr(NULL),
900 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000901 _rxVadObserverPtr(NULL),
902 _oldVadDecision(-1),
903 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000905 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000906 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000907 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000908 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 _mute(false),
910 _panLeft(1.0f),
911 _panRight(1.0f),
912 _outputGain(1.0f),
913 _playOutbandDtmfEvent(false),
914 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 _lastLocalTimeStamp(0),
916 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000917 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _rtpPacketTimedOut(false),
919 _rtpPacketTimeOutIsEnabled(false),
920 _rtpTimeOutSeconds(0),
921 _connectionObserver(false),
922 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000924 vie_network_(NULL),
925 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000926 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000927 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 _previousTimestamp(0),
929 _recPacketDelayMs(20),
930 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000932 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000933 restored_packet_in_use_(false),
934 bitrate_controller_(
935 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
936 true)),
937 rtcp_bandwidth_observer_(
938 bitrate_controller_->CreateRtcpBandwidthObserver()),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000939 send_bitrate_observer_(new VoEBitrateObserver(this)),
940 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000941{
942 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
943 "Channel::Channel() - ctor");
944 _inbandDtmfQueue.ResetDtmf();
945 _inbandDtmfGenerator.Init();
946 _outputAudioLevel.Clear();
947
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000948 RtpRtcp::Configuration configuration;
949 configuration.id = VoEModuleId(instanceId, channelId);
950 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000951 configuration.outgoing_transport = this;
952 configuration.rtcp_feedback = this;
953 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000954 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000955 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000956
957 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000958
959 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
960 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
961 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000962
963 Config audioproc_config;
964 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
965 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000966}
967
968Channel::~Channel()
969{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000970 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
972 "Channel::~Channel() - dtor");
973
974 if (_outputExternalMedia)
975 {
976 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
977 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000978 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 {
980 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
981 }
982 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 StopPlayout();
984
985 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000986 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 if (_inputFilePlayerPtr)
988 {
989 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
990 _inputFilePlayerPtr->StopPlayingFile();
991 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
992 _inputFilePlayerPtr = NULL;
993 }
994 if (_outputFilePlayerPtr)
995 {
996 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
997 _outputFilePlayerPtr->StopPlayingFile();
998 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
999 _outputFilePlayerPtr = NULL;
1000 }
1001 if (_outputFileRecorderPtr)
1002 {
1003 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1004 _outputFileRecorderPtr->StopRecording();
1005 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1006 _outputFileRecorderPtr = NULL;
1007 }
1008 }
1009
1010 // The order to safely shutdown modules in a channel is:
1011 // 1. De-register callbacks in modules
1012 // 2. De-register modules in process thread
1013 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001014 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
1016 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1017 VoEId(_instanceId,_channelId),
1018 "~Channel() failed to de-register transport callback"
1019 " (Audio coding module)");
1020 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001021 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
1023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "~Channel() failed to de-register VAD callback"
1026 " (Audio coding module)");
1027 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001028 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001029 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 {
1031 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1032 VoEId(_instanceId,_channelId),
1033 "~Channel() failed to deregister RTP/RTCP module");
1034 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 // End of modules shutdown
1036
1037 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001038 if (vie_network_) {
1039 vie_network_->Release();
1040 vie_network_ = NULL;
1041 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1043 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001046 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001047}
1048
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001049int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001050Channel::Init()
1051{
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1053 "Channel::Init()");
1054
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001055 channel_state_.Reset();
1056
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 // --- Initial sanity
1058
1059 if ((_engineStatisticsPtr == NULL) ||
1060 (_moduleProcessThreadPtr == NULL))
1061 {
1062 WEBRTC_TRACE(kTraceError, kTraceVoice,
1063 VoEId(_instanceId,_channelId),
1064 "Channel::Init() must call SetEngineInformation() first");
1065 return -1;
1066 }
1067
1068 // --- Add modules to process thread (for periodic schedulation)
1069
1070 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001071 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 if (processThreadFail)
1074 {
1075 _engineStatisticsPtr->SetLastError(
1076 VE_CANNOT_INIT_CHANNEL, kTraceError,
1077 "Channel::Init() modules not registered");
1078 return -1;
1079 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001080 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001081
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001082 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001083#ifdef WEBRTC_CODEC_AVT
1084 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001085 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001086#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001087 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 {
1089 _engineStatisticsPtr->SetLastError(
1090 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1091 "Channel::Init() unable to initialize the ACM - 1");
1092 return -1;
1093 }
1094
1095 // --- RTP/RTCP module initialization
1096
1097 // Ensure that RTCP is enabled by default for the created channel.
1098 // Note that, the module will keep generating RTCP until it is explicitly
1099 // disabled by the user.
1100 // After StopListen (when no sockets exists), RTCP packets will no longer
1101 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001102 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1103 // RTCP is enabled by default.
1104 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1108 "Channel::Init() RTP/RTCP module not initialized");
1109 return -1;
1110 }
1111
1112 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001113 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001114 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1115 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001116
1117 if (fail)
1118 {
1119 _engineStatisticsPtr->SetLastError(
1120 VE_CANNOT_INIT_CHANNEL, kTraceError,
1121 "Channel::Init() callbacks not registered");
1122 return -1;
1123 }
1124
1125 // --- Register all supported codecs to the receiving side of the
1126 // RTP/RTCP module
1127
1128 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001129 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001130
1131 for (int idx = 0; idx < nSupportedCodecs; idx++)
1132 {
1133 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001134 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001135 (rtp_receiver_->RegisterReceivePayload(
1136 codec.plname,
1137 codec.pltype,
1138 codec.plfreq,
1139 codec.channels,
1140 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 {
1142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1143 VoEId(_instanceId,_channelId),
1144 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1145 "to RTP/RTCP receiver",
1146 codec.plname, codec.pltype, codec.plfreq,
1147 codec.channels, codec.rate);
1148 }
1149 else
1150 {
1151 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1152 VoEId(_instanceId,_channelId),
1153 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1154 "the RTP/RTCP receiver",
1155 codec.plname, codec.pltype, codec.plfreq,
1156 codec.channels, codec.rate);
1157 }
1158
1159 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001160 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 {
1162 SetSendCodec(codec);
1163 }
1164
1165 // Register default PT for outband 'telephone-event'
1166 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1167 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001168 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001169 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 {
1171 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1172 VoEId(_instanceId,_channelId),
1173 "Channel::Init() failed to register outband "
1174 "'telephone-event' (%d/%d) correctly",
1175 codec.pltype, codec.plfreq);
1176 }
1177 }
1178
1179 if (!STR_CASE_CMP(codec.plname, "CN"))
1180 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001181 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1182 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001183 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001184 {
1185 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1186 VoEId(_instanceId,_channelId),
1187 "Channel::Init() failed to register CN (%d/%d) "
1188 "correctly - 1",
1189 codec.pltype, codec.plfreq);
1190 }
1191 }
1192#ifdef WEBRTC_CODEC_RED
1193 // Register RED to the receiving side of the ACM.
1194 // We will not receive an OnInitializeDecoder() callback for RED.
1195 if (!STR_CASE_CMP(codec.plname, "RED"))
1196 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001197 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 {
1199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() failed to register RED (%d/%d) "
1202 "correctly",
1203 codec.pltype, codec.plfreq);
1204 }
1205 }
1206#endif
1207 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001208
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001209 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1210 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1211 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001213 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1214 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1215 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 }
1217
1218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::SetEngineInformation(Statistics& engineStatistics,
1223 OutputMixer& outputMixer,
1224 voe::TransmitMixer& transmitMixer,
1225 ProcessThread& moduleProcessThread,
1226 AudioDeviceModule& audioDeviceModule,
1227 VoiceEngineObserver* voiceEngineObserver,
1228 CriticalSectionWrapper* callbackCritSect)
1229{
1230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1231 "Channel::SetEngineInformation()");
1232 _engineStatisticsPtr = &engineStatistics;
1233 _outputMixerPtr = &outputMixer;
1234 _transmitMixerPtr = &transmitMixer,
1235 _moduleProcessThreadPtr = &moduleProcessThread;
1236 _audioDeviceModulePtr = &audioDeviceModule;
1237 _voiceEngineObserverPtr = voiceEngineObserver;
1238 _callbackCritSectPtr = callbackCritSect;
1239 return 0;
1240}
1241
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001242int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001243Channel::UpdateLocalTimeStamp()
1244{
1245
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001246 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 return 0;
1248}
1249
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001250int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001251Channel::StartPlayout()
1252{
1253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1254 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001255 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 {
1257 return 0;
1258 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001259
1260 if (!_externalMixing) {
1261 // Add participant as candidates for mixing.
1262 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1263 {
1264 _engineStatisticsPtr->SetLastError(
1265 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1266 "StartPlayout() failed to add participant to mixer");
1267 return -1;
1268 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 }
1270
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001271 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001272 if (RegisterFilePlayingToMixer() != 0)
1273 return -1;
1274
niklase@google.com470e71d2011-07-07 08:21:25 +00001275 return 0;
1276}
1277
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001278int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001279Channel::StopPlayout()
1280{
1281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1282 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001283 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 {
1285 return 0;
1286 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001287
1288 if (!_externalMixing) {
1289 // Remove participant as candidates for mixing
1290 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1291 {
1292 _engineStatisticsPtr->SetLastError(
1293 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1294 "StopPlayout() failed to remove participant from mixer");
1295 return -1;
1296 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 }
1298
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001299 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 _outputAudioLevel.Clear();
1301
1302 return 0;
1303}
1304
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001305int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001306Channel::StartSend()
1307{
1308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1309 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001310 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001311 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001312 if (send_sequence_number_)
1313 SetInitSequenceNumber(send_sequence_number_);
1314
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001315 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001316 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001317 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001319 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001320
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001321 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001322 {
1323 _engineStatisticsPtr->SetLastError(
1324 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1325 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001326 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001327 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 return -1;
1329 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001330
niklase@google.com470e71d2011-07-07 08:21:25 +00001331 return 0;
1332}
1333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001334int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001335Channel::StopSend()
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001339 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001341 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001342 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001343 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001344
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001345 // Store the sequence number to be able to pick up the same sequence for
1346 // the next StartSend(). This is needed for restarting device, otherwise
1347 // it might cause libSRTP to complain about packets being replayed.
1348 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1349 // CL is landed. See issue
1350 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1351 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1352
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 // Reset sending SSRC and sequence number and triggers direct transmission
1354 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001355 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1356 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001357 {
1358 _engineStatisticsPtr->SetLastError(
1359 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1360 "StartSend() RTP/RTCP failed to stop sending");
1361 }
1362
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 return 0;
1364}
1365
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001366int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001367Channel::StartReceiving()
1368{
1369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1370 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001371 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 {
1373 return 0;
1374 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001375 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 _numberOfDiscardedPackets = 0;
1377 return 0;
1378}
1379
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001380int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001381Channel::StopReceiving()
1382{
1383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1384 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001385 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001386 {
1387 return 0;
1388 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001389
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001390 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 return 0;
1392}
1393
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001394int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001395Channel::SetNetEQPlayoutMode(NetEqModes mode)
1396{
1397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1398 "Channel::SetNetEQPlayoutMode()");
1399 AudioPlayoutMode playoutMode(voice);
1400 switch (mode)
1401 {
1402 case kNetEqDefault:
1403 playoutMode = voice;
1404 break;
1405 case kNetEqStreaming:
1406 playoutMode = streaming;
1407 break;
1408 case kNetEqFax:
1409 playoutMode = fax;
1410 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001411 case kNetEqOff:
1412 playoutMode = off;
1413 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001414 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001415 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 {
1417 _engineStatisticsPtr->SetLastError(
1418 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1419 "SetNetEQPlayoutMode() failed to set playout mode");
1420 return -1;
1421 }
1422 return 0;
1423}
1424
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001425int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001426Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1427{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001428 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 switch (playoutMode)
1430 {
1431 case voice:
1432 mode = kNetEqDefault;
1433 break;
1434 case streaming:
1435 mode = kNetEqStreaming;
1436 break;
1437 case fax:
1438 mode = kNetEqFax;
1439 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001440 case off:
1441 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 }
1443 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1444 VoEId(_instanceId,_channelId),
1445 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1446 return 0;
1447}
1448
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001449int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001450Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1451{
1452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1453 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001454 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001455
1456 if (_voiceEngineObserverPtr)
1457 {
1458 _engineStatisticsPtr->SetLastError(
1459 VE_INVALID_OPERATION, kTraceError,
1460 "RegisterVoiceEngineObserver() observer already enabled");
1461 return -1;
1462 }
1463 _voiceEngineObserverPtr = &observer;
1464 return 0;
1465}
1466
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001467int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001468Channel::DeRegisterVoiceEngineObserver()
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001472 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001473
1474 if (!_voiceEngineObserverPtr)
1475 {
1476 _engineStatisticsPtr->SetLastError(
1477 VE_INVALID_OPERATION, kTraceWarning,
1478 "DeRegisterVoiceEngineObserver() observer already disabled");
1479 return 0;
1480 }
1481 _voiceEngineObserverPtr = NULL;
1482 return 0;
1483}
1484
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001485int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001486Channel::GetSendCodec(CodecInst& codec)
1487{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001488 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001489}
1490
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001491int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001492Channel::GetRecCodec(CodecInst& codec)
1493{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001494 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001495}
1496
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001497int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001498Channel::SetSendCodec(const CodecInst& codec)
1499{
1500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1501 "Channel::SetSendCodec()");
1502
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001503 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 {
1505 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1506 "SetSendCodec() failed to register codec to ACM");
1507 return -1;
1508 }
1509
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001510 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001512 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1513 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001514 {
1515 WEBRTC_TRACE(
1516 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1517 "SetSendCodec() failed to register codec to"
1518 " RTP/RTCP module");
1519 return -1;
1520 }
1521 }
1522
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001523 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
1525 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "SetSendCodec() failed to set audio packet size");
1527 return -1;
1528 }
1529
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001530 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1531 codec.rate, 0, 0);
1532
niklase@google.com470e71d2011-07-07 08:21:25 +00001533 return 0;
1534}
1535
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001536void
1537Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1538 const uint8_t fraction_lost, // 0 - 255.
1539 const uint32_t rtt) {
1540 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1541 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1542 bitrate_bps, fraction_lost, rtt);
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001543 // |fraction_lost| from BitrateObserver is short time observation of packet
1544 // loss rate from past. We use network predictor to make a more reasonable
1545 // loss rate estimation.
1546 network_predictor_->UpdatePacketLossRate(fraction_lost);
1547 uint8_t loss_rate = network_predictor_->GetLossRate();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001548 // Normalizes rate to 0 - 100.
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001549 if (audio_coding_->SetPacketLossRate(100 * loss_rate / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001550 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1551 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1552 assert(false); // This should not happen.
1553 }
1554}
1555
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001556int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001557Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1558{
1559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1560 "Channel::SetVADStatus(mode=%d)", mode);
1561 // To disable VAD, DTX must be disabled too
1562 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001563 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001564 {
1565 _engineStatisticsPtr->SetLastError(
1566 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1567 "SetVADStatus() failed to set VAD");
1568 return -1;
1569 }
1570 return 0;
1571}
1572
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001573int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001574Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1575{
1576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1577 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001578 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001579 {
1580 _engineStatisticsPtr->SetLastError(
1581 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1582 "GetVADStatus() failed to get VAD status");
1583 return -1;
1584 }
1585 disabledDTX = !disabledDTX;
1586 return 0;
1587}
1588
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001589int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001590Channel::SetRecPayloadType(const CodecInst& codec)
1591{
1592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1593 "Channel::SetRecPayloadType()");
1594
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001595 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 {
1597 _engineStatisticsPtr->SetLastError(
1598 VE_ALREADY_PLAYING, kTraceError,
1599 "SetRecPayloadType() unable to set PT while playing");
1600 return -1;
1601 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001602 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001603 {
1604 _engineStatisticsPtr->SetLastError(
1605 VE_ALREADY_LISTENING, kTraceError,
1606 "SetRecPayloadType() unable to set PT while listening");
1607 return -1;
1608 }
1609
1610 if (codec.pltype == -1)
1611 {
1612 // De-register the selected codec (RTP/RTCP module and ACM)
1613
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001614 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001615 CodecInst rxCodec = codec;
1616
1617 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001618 rtp_payload_registry_->ReceivePayloadType(
1619 rxCodec.plname,
1620 rxCodec.plfreq,
1621 rxCodec.channels,
1622 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1623 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001624 rxCodec.pltype = pltype;
1625
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001626 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001627 {
1628 _engineStatisticsPtr->SetLastError(
1629 VE_RTP_RTCP_MODULE_ERROR,
1630 kTraceError,
1631 "SetRecPayloadType() RTP/RTCP-module deregistration "
1632 "failed");
1633 return -1;
1634 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001635 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001636 {
1637 _engineStatisticsPtr->SetLastError(
1638 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1639 "SetRecPayloadType() ACM deregistration failed - 1");
1640 return -1;
1641 }
1642 return 0;
1643 }
1644
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001645 if (rtp_receiver_->RegisterReceivePayload(
1646 codec.plname,
1647 codec.pltype,
1648 codec.plfreq,
1649 codec.channels,
1650 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001651 {
1652 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001653 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1654 if (rtp_receiver_->RegisterReceivePayload(
1655 codec.plname,
1656 codec.pltype,
1657 codec.plfreq,
1658 codec.channels,
1659 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001660 {
1661 _engineStatisticsPtr->SetLastError(
1662 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1663 "SetRecPayloadType() RTP/RTCP-module registration failed");
1664 return -1;
1665 }
1666 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001667 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001669 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1670 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674 "SetRecPayloadType() ACM registration failed - 1");
1675 return -1;
1676 }
1677 }
1678 return 0;
1679}
1680
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001681int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001682Channel::GetRecPayloadType(CodecInst& codec)
1683{
1684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001686 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001687 if (rtp_payload_registry_->ReceivePayloadType(
1688 codec.plname,
1689 codec.plfreq,
1690 codec.channels,
1691 (codec.rate < 0) ? 0 : codec.rate,
1692 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001693 {
1694 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001695 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001696 "GetRecPayloadType() failed to retrieve RX payload type");
1697 return -1;
1698 }
1699 codec.pltype = payloadType;
1700 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1701 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1702 return 0;
1703}
1704
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001705int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001706Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1707{
1708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1709 "Channel::SetSendCNPayloadType()");
1710
1711 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001712 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001713 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001714 if (frequency == kFreq32000Hz)
1715 samplingFreqHz = 32000;
1716 else if (frequency == kFreq16000Hz)
1717 samplingFreqHz = 16000;
1718
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001719 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001720 {
1721 _engineStatisticsPtr->SetLastError(
1722 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1723 "SetSendCNPayloadType() failed to retrieve default CN codec "
1724 "settings");
1725 return -1;
1726 }
1727
1728 // Modify the payload type (must be set to dynamic range)
1729 codec.pltype = type;
1730
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001731 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001732 {
1733 _engineStatisticsPtr->SetLastError(
1734 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1735 "SetSendCNPayloadType() failed to register CN to ACM");
1736 return -1;
1737 }
1738
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001739 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001740 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001741 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1742 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001743 {
1744 _engineStatisticsPtr->SetLastError(
1745 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1746 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1747 "module");
1748 return -1;
1749 }
1750 }
1751 return 0;
1752}
1753
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001754int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001755 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001756 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001757
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001758 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001759 _engineStatisticsPtr->SetLastError(
1760 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001761 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001762 return -1;
1763 }
1764 return 0;
1765}
1766
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001767int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001768{
1769 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1770 "Channel::RegisterExternalTransport()");
1771
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001772 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001773
niklase@google.com470e71d2011-07-07 08:21:25 +00001774 if (_externalTransport)
1775 {
1776 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1777 kTraceError,
1778 "RegisterExternalTransport() external transport already enabled");
1779 return -1;
1780 }
1781 _externalTransport = true;
1782 _transportPtr = &transport;
1783 return 0;
1784}
1785
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001786int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001787Channel::DeRegisterExternalTransport()
1788{
1789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1790 "Channel::DeRegisterExternalTransport()");
1791
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001792 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001793
niklase@google.com470e71d2011-07-07 08:21:25 +00001794 if (!_transportPtr)
1795 {
1796 _engineStatisticsPtr->SetLastError(
1797 VE_INVALID_OPERATION, kTraceWarning,
1798 "DeRegisterExternalTransport() external transport already "
1799 "disabled");
1800 return 0;
1801 }
1802 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001803 _transportPtr = NULL;
1804 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1805 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001806 return 0;
1807}
1808
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001809int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1810 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001811 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1812 "Channel::ReceivedRTPPacket()");
1813
1814 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001815 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001816
1817 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001818 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1819 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001820 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1821 VoEId(_instanceId,_channelId),
1822 "Channel::SendPacket() RTP dump to input file failed");
1823 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001824 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001825 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001826 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1827 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1828 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001829 return -1;
1830 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001831 header.payload_type_frequency =
1832 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001833 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001834 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001835 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001836 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001837 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001838 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001839
1840 // Forward any packets to ViE bandwidth estimator, if enabled.
1841 {
1842 CriticalSectionScoped cs(&_callbackCritSect);
1843 if (vie_network_) {
1844 int64_t arrival_time_ms;
1845 if (packet_time.timestamp != -1) {
1846 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1847 } else {
1848 arrival_time_ms = TickTime::MillisecondTimestamp();
1849 }
1850 int payload_length = length - header.headerLength;
1851 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1852 payload_length, header);
1853 }
1854 }
1855
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001856 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001857}
1858
1859bool Channel::ReceivePacket(const uint8_t* packet,
1860 int packet_length,
1861 const RTPHeader& header,
1862 bool in_order) {
1863 if (rtp_payload_registry_->IsEncapsulated(header)) {
1864 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001865 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001866 const uint8_t* payload = packet + header.headerLength;
1867 int payload_length = packet_length - header.headerLength;
1868 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001869 PayloadUnion payload_specific;
1870 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001871 &payload_specific)) {
1872 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001873 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001874 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1875 payload_specific, in_order);
1876}
1877
1878bool Channel::HandleEncapsulation(const uint8_t* packet,
1879 int packet_length,
1880 const RTPHeader& header) {
1881 if (!rtp_payload_registry_->IsRtx(header))
1882 return false;
1883
1884 // Remove the RTX header and parse the original RTP header.
1885 if (packet_length < header.headerLength)
1886 return false;
1887 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1888 return false;
1889 if (restored_packet_in_use_) {
1890 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1891 "Multiple RTX headers detected, dropping packet");
1892 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001893 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001894 uint8_t* restored_packet_ptr = restored_packet_;
1895 if (!rtp_payload_registry_->RestoreOriginalPacket(
1896 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1897 header)) {
1898 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1899 "Incoming RTX packet: invalid RTP header");
1900 return false;
1901 }
1902 restored_packet_in_use_ = true;
1903 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1904 restored_packet_in_use_ = false;
1905 return ret;
1906}
1907
1908bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1909 StreamStatistician* statistician =
1910 rtp_receive_statistics_->GetStatistician(header.ssrc);
1911 if (!statistician)
1912 return false;
1913 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001914}
1915
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001916bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1917 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001918 // Retransmissions are handled separately if RTX is enabled.
1919 if (rtp_payload_registry_->RtxEnabled())
1920 return false;
1921 StreamStatistician* statistician =
1922 rtp_receive_statistics_->GetStatistician(header.ssrc);
1923 if (!statistician)
1924 return false;
1925 // Check if this is a retransmission.
1926 uint16_t min_rtt = 0;
1927 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001928 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001929 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001930}
1931
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001932int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001933 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1934 "Channel::ReceivedRTCPPacket()");
1935 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001936 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001937
1938 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001939 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1940 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001941 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1942 VoEId(_instanceId,_channelId),
1943 "Channel::SendPacket() RTCP dump to input file failed");
1944 }
1945
1946 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001947 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1948 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001949 _engineStatisticsPtr->SetLastError(
1950 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1951 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1952 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001953
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001954 {
1955 CriticalSectionScoped lock(ts_stats_lock_.get());
1956 ntp_estimator_.UpdateRtcpTimestamp(rtp_receiver_->SSRC(),
1957 _rtpRtcpModule.get());
1958 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001959 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001960}
1961
niklase@google.com470e71d2011-07-07 08:21:25 +00001962int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001963 bool loop,
1964 FileFormats format,
1965 int startPosition,
1966 float volumeScaling,
1967 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001968 const CodecInst* codecInst)
1969{
1970 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1971 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1972 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1973 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1974 startPosition, stopPosition);
1975
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001976 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001977 {
1978 _engineStatisticsPtr->SetLastError(
1979 VE_ALREADY_PLAYING, kTraceError,
1980 "StartPlayingFileLocally() is already playing");
1981 return -1;
1982 }
1983
niklase@google.com470e71d2011-07-07 08:21:25 +00001984 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001985 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001986
1987 if (_outputFilePlayerPtr)
1988 {
1989 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1990 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1991 _outputFilePlayerPtr = NULL;
1992 }
1993
1994 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1995 _outputFilePlayerId, (const FileFormats)format);
1996
1997 if (_outputFilePlayerPtr == NULL)
1998 {
1999 _engineStatisticsPtr->SetLastError(
2000 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002001 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002002 return -1;
2003 }
2004
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002005 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002006
2007 if (_outputFilePlayerPtr->StartPlayingFile(
2008 fileName,
2009 loop,
2010 startPosition,
2011 volumeScaling,
2012 notificationTime,
2013 stopPosition,
2014 (const CodecInst*)codecInst) != 0)
2015 {
2016 _engineStatisticsPtr->SetLastError(
2017 VE_BAD_FILE, kTraceError,
2018 "StartPlayingFile() failed to start file playout");
2019 _outputFilePlayerPtr->StopPlayingFile();
2020 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2021 _outputFilePlayerPtr = NULL;
2022 return -1;
2023 }
2024 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002025 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002026 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002027
2028 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002029 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002030
2031 return 0;
2032}
2033
2034int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002035 FileFormats format,
2036 int startPosition,
2037 float volumeScaling,
2038 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002039 const CodecInst* codecInst)
2040{
2041 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2042 "Channel::StartPlayingFileLocally(format=%d,"
2043 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2044 format, volumeScaling, startPosition, stopPosition);
2045
2046 if(stream == NULL)
2047 {
2048 _engineStatisticsPtr->SetLastError(
2049 VE_BAD_FILE, kTraceError,
2050 "StartPlayingFileLocally() NULL as input stream");
2051 return -1;
2052 }
2053
2054
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002055 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_ALREADY_PLAYING, kTraceError,
2059 "StartPlayingFileLocally() is already playing");
2060 return -1;
2061 }
2062
niklase@google.com470e71d2011-07-07 08:21:25 +00002063 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002064 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002065
2066 // Destroy the old instance
2067 if (_outputFilePlayerPtr)
2068 {
2069 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2070 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2071 _outputFilePlayerPtr = NULL;
2072 }
2073
2074 // Create the instance
2075 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2076 _outputFilePlayerId,
2077 (const FileFormats)format);
2078
2079 if (_outputFilePlayerPtr == NULL)
2080 {
2081 _engineStatisticsPtr->SetLastError(
2082 VE_INVALID_ARGUMENT, kTraceError,
2083 "StartPlayingFileLocally() filePlayer format isnot correct");
2084 return -1;
2085 }
2086
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002087 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002088
2089 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2090 volumeScaling,
2091 notificationTime,
2092 stopPosition, codecInst) != 0)
2093 {
2094 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2095 "StartPlayingFile() failed to "
2096 "start file playout");
2097 _outputFilePlayerPtr->StopPlayingFile();
2098 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2099 _outputFilePlayerPtr = NULL;
2100 return -1;
2101 }
2102 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002103 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002104 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002105
2106 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002107 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002108
niklase@google.com470e71d2011-07-07 08:21:25 +00002109 return 0;
2110}
2111
2112int Channel::StopPlayingFileLocally()
2113{
2114 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2115 "Channel::StopPlayingFileLocally()");
2116
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002117 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002118 {
2119 _engineStatisticsPtr->SetLastError(
2120 VE_INVALID_OPERATION, kTraceWarning,
2121 "StopPlayingFileLocally() isnot playing");
2122 return 0;
2123 }
2124
niklase@google.com470e71d2011-07-07 08:21:25 +00002125 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002126 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002127
2128 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2129 {
2130 _engineStatisticsPtr->SetLastError(
2131 VE_STOP_RECORDING_FAILED, kTraceError,
2132 "StopPlayingFile() could not stop playing");
2133 return -1;
2134 }
2135 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2136 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2137 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002138 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002139 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002140 // _fileCritSect cannot be taken while calling
2141 // SetAnonymousMixibilityStatus. Refer to comments in
2142 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002143 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2144 {
2145 _engineStatisticsPtr->SetLastError(
2146 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002147 "StopPlayingFile() failed to stop participant from playing as"
2148 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002149 return -1;
2150 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002151
2152 return 0;
2153}
2154
2155int Channel::IsPlayingFileLocally() const
2156{
2157 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2158 "Channel::IsPlayingFileLocally()");
2159
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002160 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002161}
2162
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002163int Channel::RegisterFilePlayingToMixer()
2164{
2165 // Return success for not registering for file playing to mixer if:
2166 // 1. playing file before playout is started on that channel.
2167 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002168 if (!channel_state_.Get().playing ||
2169 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002170 {
2171 return 0;
2172 }
2173
2174 // |_fileCritSect| cannot be taken while calling
2175 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2176 // frames can be pulled by the mixer. Since the frames are generated from
2177 // the file, _fileCritSect will be taken. This would result in a deadlock.
2178 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2179 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002180 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002181 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002182 _engineStatisticsPtr->SetLastError(
2183 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2184 "StartPlayingFile() failed to add participant as file to mixer");
2185 _outputFilePlayerPtr->StopPlayingFile();
2186 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2187 _outputFilePlayerPtr = NULL;
2188 return -1;
2189 }
2190
2191 return 0;
2192}
2193
niklase@google.com470e71d2011-07-07 08:21:25 +00002194int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002195 bool loop,
2196 FileFormats format,
2197 int startPosition,
2198 float volumeScaling,
2199 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002200 const CodecInst* codecInst)
2201{
2202 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2203 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2204 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2205 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2206 startPosition, stopPosition);
2207
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002208 CriticalSectionScoped cs(&_fileCritSect);
2209
2210 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002211 {
2212 _engineStatisticsPtr->SetLastError(
2213 VE_ALREADY_PLAYING, kTraceWarning,
2214 "StartPlayingFileAsMicrophone() filePlayer is playing");
2215 return 0;
2216 }
2217
niklase@google.com470e71d2011-07-07 08:21:25 +00002218 // Destroy the old instance
2219 if (_inputFilePlayerPtr)
2220 {
2221 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2222 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2223 _inputFilePlayerPtr = NULL;
2224 }
2225
2226 // Create the instance
2227 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2228 _inputFilePlayerId, (const FileFormats)format);
2229
2230 if (_inputFilePlayerPtr == NULL)
2231 {
2232 _engineStatisticsPtr->SetLastError(
2233 VE_INVALID_ARGUMENT, kTraceError,
2234 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2235 return -1;
2236 }
2237
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002238 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002239
2240 if (_inputFilePlayerPtr->StartPlayingFile(
2241 fileName,
2242 loop,
2243 startPosition,
2244 volumeScaling,
2245 notificationTime,
2246 stopPosition,
2247 (const CodecInst*)codecInst) != 0)
2248 {
2249 _engineStatisticsPtr->SetLastError(
2250 VE_BAD_FILE, kTraceError,
2251 "StartPlayingFile() failed to start file playout");
2252 _inputFilePlayerPtr->StopPlayingFile();
2253 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2254 _inputFilePlayerPtr = NULL;
2255 return -1;
2256 }
2257 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002258 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002259
2260 return 0;
2261}
2262
2263int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002264 FileFormats format,
2265 int startPosition,
2266 float volumeScaling,
2267 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002268 const CodecInst* codecInst)
2269{
2270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2271 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2272 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2273 format, volumeScaling, startPosition, stopPosition);
2274
2275 if(stream == NULL)
2276 {
2277 _engineStatisticsPtr->SetLastError(
2278 VE_BAD_FILE, kTraceError,
2279 "StartPlayingFileAsMicrophone NULL as input stream");
2280 return -1;
2281 }
2282
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002283 CriticalSectionScoped cs(&_fileCritSect);
2284
2285 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002286 {
2287 _engineStatisticsPtr->SetLastError(
2288 VE_ALREADY_PLAYING, kTraceWarning,
2289 "StartPlayingFileAsMicrophone() is playing");
2290 return 0;
2291 }
2292
niklase@google.com470e71d2011-07-07 08:21:25 +00002293 // Destroy the old instance
2294 if (_inputFilePlayerPtr)
2295 {
2296 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2297 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2298 _inputFilePlayerPtr = NULL;
2299 }
2300
2301 // Create the instance
2302 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2303 _inputFilePlayerId, (const FileFormats)format);
2304
2305 if (_inputFilePlayerPtr == NULL)
2306 {
2307 _engineStatisticsPtr->SetLastError(
2308 VE_INVALID_ARGUMENT, kTraceError,
2309 "StartPlayingInputFile() filePlayer format isnot correct");
2310 return -1;
2311 }
2312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002313 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002314
2315 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2316 volumeScaling, notificationTime,
2317 stopPosition, codecInst) != 0)
2318 {
2319 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2320 "StartPlayingFile() failed to start "
2321 "file playout");
2322 _inputFilePlayerPtr->StopPlayingFile();
2323 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2324 _inputFilePlayerPtr = NULL;
2325 return -1;
2326 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002327
niklase@google.com470e71d2011-07-07 08:21:25 +00002328 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002329 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002330
2331 return 0;
2332}
2333
2334int Channel::StopPlayingFileAsMicrophone()
2335{
2336 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2337 "Channel::StopPlayingFileAsMicrophone()");
2338
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002339 CriticalSectionScoped cs(&_fileCritSect);
2340
2341 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 {
2343 _engineStatisticsPtr->SetLastError(
2344 VE_INVALID_OPERATION, kTraceWarning,
2345 "StopPlayingFileAsMicrophone() isnot playing");
2346 return 0;
2347 }
2348
niklase@google.com470e71d2011-07-07 08:21:25 +00002349 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2350 {
2351 _engineStatisticsPtr->SetLastError(
2352 VE_STOP_RECORDING_FAILED, kTraceError,
2353 "StopPlayingFile() could not stop playing");
2354 return -1;
2355 }
2356 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2357 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2358 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002359 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002360
2361 return 0;
2362}
2363
2364int Channel::IsPlayingFileAsMicrophone() const
2365{
2366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2367 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002368 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002369}
2370
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002371int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002372 const CodecInst* codecInst)
2373{
2374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2375 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2376
2377 if (_outputFileRecording)
2378 {
2379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2380 "StartRecordingPlayout() is already recording");
2381 return 0;
2382 }
2383
2384 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002385 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002386 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2387
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002388 if ((codecInst != NULL) &&
2389 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002390 {
2391 _engineStatisticsPtr->SetLastError(
2392 VE_BAD_ARGUMENT, kTraceError,
2393 "StartRecordingPlayout() invalid compression");
2394 return(-1);
2395 }
2396 if(codecInst == NULL)
2397 {
2398 format = kFileFormatPcm16kHzFile;
2399 codecInst=&dummyCodec;
2400 }
2401 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2402 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2403 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2404 {
2405 format = kFileFormatWavFile;
2406 }
2407 else
2408 {
2409 format = kFileFormatCompressedFile;
2410 }
2411
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002412 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002413
2414 // Destroy the old instance
2415 if (_outputFileRecorderPtr)
2416 {
2417 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2418 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2419 _outputFileRecorderPtr = NULL;
2420 }
2421
2422 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2423 _outputFileRecorderId, (const FileFormats)format);
2424 if (_outputFileRecorderPtr == NULL)
2425 {
2426 _engineStatisticsPtr->SetLastError(
2427 VE_INVALID_ARGUMENT, kTraceError,
2428 "StartRecordingPlayout() fileRecorder format isnot correct");
2429 return -1;
2430 }
2431
2432 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2433 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2434 {
2435 _engineStatisticsPtr->SetLastError(
2436 VE_BAD_FILE, kTraceError,
2437 "StartRecordingAudioFile() failed to start file recording");
2438 _outputFileRecorderPtr->StopRecording();
2439 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2440 _outputFileRecorderPtr = NULL;
2441 return -1;
2442 }
2443 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2444 _outputFileRecording = true;
2445
2446 return 0;
2447}
2448
2449int Channel::StartRecordingPlayout(OutStream* stream,
2450 const CodecInst* codecInst)
2451{
2452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2453 "Channel::StartRecordingPlayout()");
2454
2455 if (_outputFileRecording)
2456 {
2457 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2458 "StartRecordingPlayout() is already recording");
2459 return 0;
2460 }
2461
2462 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002463 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002464 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2465
2466 if (codecInst != NULL && codecInst->channels != 1)
2467 {
2468 _engineStatisticsPtr->SetLastError(
2469 VE_BAD_ARGUMENT, kTraceError,
2470 "StartRecordingPlayout() invalid compression");
2471 return(-1);
2472 }
2473 if(codecInst == NULL)
2474 {
2475 format = kFileFormatPcm16kHzFile;
2476 codecInst=&dummyCodec;
2477 }
2478 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2479 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2480 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2481 {
2482 format = kFileFormatWavFile;
2483 }
2484 else
2485 {
2486 format = kFileFormatCompressedFile;
2487 }
2488
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002489 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002490
2491 // Destroy the old instance
2492 if (_outputFileRecorderPtr)
2493 {
2494 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2495 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2496 _outputFileRecorderPtr = NULL;
2497 }
2498
2499 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2500 _outputFileRecorderId, (const FileFormats)format);
2501 if (_outputFileRecorderPtr == NULL)
2502 {
2503 _engineStatisticsPtr->SetLastError(
2504 VE_INVALID_ARGUMENT, kTraceError,
2505 "StartRecordingPlayout() fileRecorder format isnot correct");
2506 return -1;
2507 }
2508
2509 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2510 notificationTime) != 0)
2511 {
2512 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2513 "StartRecordingPlayout() failed to "
2514 "start file recording");
2515 _outputFileRecorderPtr->StopRecording();
2516 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2517 _outputFileRecorderPtr = NULL;
2518 return -1;
2519 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002520
niklase@google.com470e71d2011-07-07 08:21:25 +00002521 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2522 _outputFileRecording = true;
2523
2524 return 0;
2525}
2526
2527int Channel::StopRecordingPlayout()
2528{
2529 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2530 "Channel::StopRecordingPlayout()");
2531
2532 if (!_outputFileRecording)
2533 {
2534 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2535 "StopRecordingPlayout() isnot recording");
2536 return -1;
2537 }
2538
2539
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002540 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002541
2542 if (_outputFileRecorderPtr->StopRecording() != 0)
2543 {
2544 _engineStatisticsPtr->SetLastError(
2545 VE_STOP_RECORDING_FAILED, kTraceError,
2546 "StopRecording() could not stop recording");
2547 return(-1);
2548 }
2549 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2550 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2551 _outputFileRecorderPtr = NULL;
2552 _outputFileRecording = false;
2553
2554 return 0;
2555}
2556
2557void
2558Channel::SetMixWithMicStatus(bool mix)
2559{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002560 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002561 _mixFileWithMicrophone=mix;
2562}
2563
2564int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002565Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002566{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002567 int8_t currentLevel = _outputAudioLevel.Level();
2568 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002569 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2570 VoEId(_instanceId,_channelId),
2571 "GetSpeechOutputLevel() => level=%u", level);
2572 return 0;
2573}
2574
2575int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002576Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002577{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002578 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2579 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002580 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2581 VoEId(_instanceId,_channelId),
2582 "GetSpeechOutputLevelFullRange() => level=%u", level);
2583 return 0;
2584}
2585
2586int
2587Channel::SetMute(bool enable)
2588{
wu@webrtc.org63420662013-10-17 18:28:55 +00002589 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002590 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2591 "Channel::SetMute(enable=%d)", enable);
2592 _mute = enable;
2593 return 0;
2594}
2595
2596bool
2597Channel::Mute() const
2598{
wu@webrtc.org63420662013-10-17 18:28:55 +00002599 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002600 return _mute;
2601}
2602
2603int
2604Channel::SetOutputVolumePan(float left, float right)
2605{
wu@webrtc.org63420662013-10-17 18:28:55 +00002606 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2608 "Channel::SetOutputVolumePan()");
2609 _panLeft = left;
2610 _panRight = right;
2611 return 0;
2612}
2613
2614int
2615Channel::GetOutputVolumePan(float& left, float& right) const
2616{
wu@webrtc.org63420662013-10-17 18:28:55 +00002617 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002618 left = _panLeft;
2619 right = _panRight;
2620 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2621 VoEId(_instanceId,_channelId),
2622 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2623 return 0;
2624}
2625
2626int
2627Channel::SetChannelOutputVolumeScaling(float scaling)
2628{
wu@webrtc.org63420662013-10-17 18:28:55 +00002629 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002630 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2631 "Channel::SetChannelOutputVolumeScaling()");
2632 _outputGain = scaling;
2633 return 0;
2634}
2635
2636int
2637Channel::GetChannelOutputVolumeScaling(float& scaling) const
2638{
wu@webrtc.org63420662013-10-17 18:28:55 +00002639 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002640 scaling = _outputGain;
2641 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2642 VoEId(_instanceId,_channelId),
2643 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2644 return 0;
2645}
2646
niklase@google.com470e71d2011-07-07 08:21:25 +00002647int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002648 int lengthMs, int attenuationDb,
2649 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002650{
2651 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2652 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2653 playDtmfEvent);
2654
2655 _playOutbandDtmfEvent = playDtmfEvent;
2656
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002657 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002658 attenuationDb) != 0)
2659 {
2660 _engineStatisticsPtr->SetLastError(
2661 VE_SEND_DTMF_FAILED,
2662 kTraceWarning,
2663 "SendTelephoneEventOutband() failed to send event");
2664 return -1;
2665 }
2666 return 0;
2667}
2668
2669int Channel::SendTelephoneEventInband(unsigned char eventCode,
2670 int lengthMs,
2671 int attenuationDb,
2672 bool playDtmfEvent)
2673{
2674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2675 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2676 playDtmfEvent);
2677
2678 _playInbandDtmfEvent = playDtmfEvent;
2679 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2680
2681 return 0;
2682}
2683
2684int
2685Channel::SetDtmfPlayoutStatus(bool enable)
2686{
2687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2688 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002689 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002690 {
2691 _engineStatisticsPtr->SetLastError(
2692 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2693 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2694 return -1;
2695 }
2696 return 0;
2697}
2698
2699bool
2700Channel::DtmfPlayoutStatus() const
2701{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002702 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002703}
2704
2705int
2706Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2707{
2708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2709 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002710 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002711 {
2712 _engineStatisticsPtr->SetLastError(
2713 VE_INVALID_ARGUMENT, kTraceError,
2714 "SetSendTelephoneEventPayloadType() invalid type");
2715 return -1;
2716 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002717 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002718 codec.plfreq = 8000;
2719 codec.pltype = type;
2720 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002721 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002722 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002723 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2724 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2725 _engineStatisticsPtr->SetLastError(
2726 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2727 "SetSendTelephoneEventPayloadType() failed to register send"
2728 "payload type");
2729 return -1;
2730 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002731 }
2732 _sendTelephoneEventPayloadType = type;
2733 return 0;
2734}
2735
2736int
2737Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2738{
2739 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2740 "Channel::GetSendTelephoneEventPayloadType()");
2741 type = _sendTelephoneEventPayloadType;
2742 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2743 VoEId(_instanceId,_channelId),
2744 "GetSendTelephoneEventPayloadType() => type=%u", type);
2745 return 0;
2746}
2747
niklase@google.com470e71d2011-07-07 08:21:25 +00002748int
2749Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2750{
2751 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2752 "Channel::UpdateRxVadDetection()");
2753
2754 int vadDecision = 1;
2755
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002756 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002757
2758 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2759 {
2760 OnRxVadDetected(vadDecision);
2761 _oldVadDecision = vadDecision;
2762 }
2763
2764 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2765 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2766 vadDecision);
2767 return 0;
2768}
2769
2770int
2771Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2772{
2773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2774 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002775 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002776
2777 if (_rxVadObserverPtr)
2778 {
2779 _engineStatisticsPtr->SetLastError(
2780 VE_INVALID_OPERATION, kTraceError,
2781 "RegisterRxVadObserver() observer already enabled");
2782 return -1;
2783 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002784 _rxVadObserverPtr = &observer;
2785 _RxVadDetection = true;
2786 return 0;
2787}
2788
2789int
2790Channel::DeRegisterRxVadObserver()
2791{
2792 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2793 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002794 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002795
2796 if (!_rxVadObserverPtr)
2797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_INVALID_OPERATION, kTraceWarning,
2800 "DeRegisterRxVadObserver() observer already disabled");
2801 return 0;
2802 }
2803 _rxVadObserverPtr = NULL;
2804 _RxVadDetection = false;
2805 return 0;
2806}
2807
2808int
2809Channel::VoiceActivityIndicator(int &activity)
2810{
2811 activity = _sendFrameType;
2812
2813 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002814 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002815 return 0;
2816}
2817
2818#ifdef WEBRTC_VOICE_ENGINE_AGC
2819
2820int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002821Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002822{
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2824 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2825 (int)enable, (int)mode);
2826
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002827 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002828 switch (mode)
2829 {
2830 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002831 break;
2832 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002833 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002834 break;
2835 case kAgcFixedDigital:
2836 agcMode = GainControl::kFixedDigital;
2837 break;
2838 case kAgcAdaptiveDigital:
2839 agcMode =GainControl::kAdaptiveDigital;
2840 break;
2841 default:
2842 _engineStatisticsPtr->SetLastError(
2843 VE_INVALID_ARGUMENT, kTraceError,
2844 "SetRxAgcStatus() invalid Agc mode");
2845 return -1;
2846 }
2847
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002848 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002849 {
2850 _engineStatisticsPtr->SetLastError(
2851 VE_APM_ERROR, kTraceError,
2852 "SetRxAgcStatus() failed to set Agc mode");
2853 return -1;
2854 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002855 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002856 {
2857 _engineStatisticsPtr->SetLastError(
2858 VE_APM_ERROR, kTraceError,
2859 "SetRxAgcStatus() failed to set Agc state");
2860 return -1;
2861 }
2862
2863 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002864 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002865
2866 return 0;
2867}
2868
2869int
2870Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2871{
2872 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2873 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2874
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002875 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002876 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002877 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002878
2879 enabled = enable;
2880
2881 switch (agcMode)
2882 {
2883 case GainControl::kFixedDigital:
2884 mode = kAgcFixedDigital;
2885 break;
2886 case GainControl::kAdaptiveDigital:
2887 mode = kAgcAdaptiveDigital;
2888 break;
2889 default:
2890 _engineStatisticsPtr->SetLastError(
2891 VE_APM_ERROR, kTraceError,
2892 "GetRxAgcStatus() invalid Agc mode");
2893 return -1;
2894 }
2895
2896 return 0;
2897}
2898
2899int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002900Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002901{
2902 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2903 "Channel::SetRxAgcConfig()");
2904
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002905 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002906 config.targetLeveldBOv) != 0)
2907 {
2908 _engineStatisticsPtr->SetLastError(
2909 VE_APM_ERROR, kTraceError,
2910 "SetRxAgcConfig() failed to set target peak |level|"
2911 "(or envelope) of the Agc");
2912 return -1;
2913 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002914 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002915 config.digitalCompressionGaindB) != 0)
2916 {
2917 _engineStatisticsPtr->SetLastError(
2918 VE_APM_ERROR, kTraceError,
2919 "SetRxAgcConfig() failed to set the range in |gain| the"
2920 " digital compression stage may apply");
2921 return -1;
2922 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002923 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002924 config.limiterEnable) != 0)
2925 {
2926 _engineStatisticsPtr->SetLastError(
2927 VE_APM_ERROR, kTraceError,
2928 "SetRxAgcConfig() failed to set hard limiter to the signal");
2929 return -1;
2930 }
2931
2932 return 0;
2933}
2934
2935int
2936Channel::GetRxAgcConfig(AgcConfig& config)
2937{
2938 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2939 "Channel::GetRxAgcConfig(config=%?)");
2940
2941 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002942 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002943 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002944 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002945 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002946 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002947
2948 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2949 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2950 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2951 " limiterEnable=%d",
2952 config.targetLeveldBOv,
2953 config.digitalCompressionGaindB,
2954 config.limiterEnable);
2955
2956 return 0;
2957}
2958
2959#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2960
2961#ifdef WEBRTC_VOICE_ENGINE_NR
2962
2963int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002964Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002965{
2966 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2967 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2968 (int)enable, (int)mode);
2969
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002970 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002971 switch (mode)
2972 {
2973
2974 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002975 break;
2976 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002977 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002978 break;
2979 case kNsConference:
2980 nsLevel = NoiseSuppression::kHigh;
2981 break;
2982 case kNsLowSuppression:
2983 nsLevel = NoiseSuppression::kLow;
2984 break;
2985 case kNsModerateSuppression:
2986 nsLevel = NoiseSuppression::kModerate;
2987 break;
2988 case kNsHighSuppression:
2989 nsLevel = NoiseSuppression::kHigh;
2990 break;
2991 case kNsVeryHighSuppression:
2992 nsLevel = NoiseSuppression::kVeryHigh;
2993 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002994 }
2995
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002996 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002997 != 0)
2998 {
2999 _engineStatisticsPtr->SetLastError(
3000 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003001 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003002 return -1;
3003 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003004 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003005 {
3006 _engineStatisticsPtr->SetLastError(
3007 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003008 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003009 return -1;
3010 }
3011
3012 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003013 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003014
3015 return 0;
3016}
3017
3018int
3019Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3020{
3021 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3022 "Channel::GetRxNsStatus(enable=?, mode=?)");
3023
3024 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003025 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003026 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003027 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003028
3029 enabled = enable;
3030
3031 switch (ncLevel)
3032 {
3033 case NoiseSuppression::kLow:
3034 mode = kNsLowSuppression;
3035 break;
3036 case NoiseSuppression::kModerate:
3037 mode = kNsModerateSuppression;
3038 break;
3039 case NoiseSuppression::kHigh:
3040 mode = kNsHighSuppression;
3041 break;
3042 case NoiseSuppression::kVeryHigh:
3043 mode = kNsVeryHighSuppression;
3044 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003045 }
3046
3047 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3048 VoEId(_instanceId,_channelId),
3049 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3050 return 0;
3051}
3052
3053#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3054
3055int
niklase@google.com470e71d2011-07-07 08:21:25 +00003056Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3057{
3058 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3059 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003060 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003061
3062 if (_rtcpObserverPtr)
3063 {
3064 _engineStatisticsPtr->SetLastError(
3065 VE_INVALID_OPERATION, kTraceError,
3066 "RegisterRTCPObserver() observer already enabled");
3067 return -1;
3068 }
3069
3070 _rtcpObserverPtr = &observer;
3071 _rtcpObserver = true;
3072
3073 return 0;
3074}
3075
3076int
3077Channel::DeRegisterRTCPObserver()
3078{
3079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3080 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003081 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003082
3083 if (!_rtcpObserverPtr)
3084 {
3085 _engineStatisticsPtr->SetLastError(
3086 VE_INVALID_OPERATION, kTraceWarning,
3087 "DeRegisterRTCPObserver() observer already disabled");
3088 return 0;
3089 }
3090
3091 _rtcpObserver = false;
3092 _rtcpObserverPtr = NULL;
3093
3094 return 0;
3095}
3096
3097int
3098Channel::SetLocalSSRC(unsigned int ssrc)
3099{
3100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3101 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003102 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003103 {
3104 _engineStatisticsPtr->SetLastError(
3105 VE_ALREADY_SENDING, kTraceError,
3106 "SetLocalSSRC() already sending");
3107 return -1;
3108 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00003109 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00003110 return 0;
3111}
3112
3113int
3114Channel::GetLocalSSRC(unsigned int& ssrc)
3115{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003116 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003117 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3118 VoEId(_instanceId,_channelId),
3119 "GetLocalSSRC() => ssrc=%lu", ssrc);
3120 return 0;
3121}
3122
3123int
3124Channel::GetRemoteSSRC(unsigned int& ssrc)
3125{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003126 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3128 VoEId(_instanceId,_channelId),
3129 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3130 return 0;
3131}
3132
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003133int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003134 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003135 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003136}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003137
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003138int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3139 unsigned char id) {
3140 rtp_header_parser_->DeregisterRtpHeaderExtension(
3141 kRtpExtensionAudioLevel);
3142 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3143 kRtpExtensionAudioLevel, id)) {
3144 return -1;
3145 }
3146 return 0;
3147}
3148
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003149int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3150 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3151}
3152
3153int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3154 rtp_header_parser_->DeregisterRtpHeaderExtension(
3155 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003156 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3157 kRtpExtensionAbsoluteSendTime, id)) {
3158 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003159 }
3160 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003161}
3162
3163int
3164Channel::SetRTCPStatus(bool enable)
3165{
3166 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3167 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003168 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003169 kRtcpCompound : kRtcpOff) != 0)
3170 {
3171 _engineStatisticsPtr->SetLastError(
3172 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3173 "SetRTCPStatus() failed to set RTCP status");
3174 return -1;
3175 }
3176 return 0;
3177}
3178
3179int
3180Channel::GetRTCPStatus(bool& enabled)
3181{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003182 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003183 enabled = (method != kRtcpOff);
3184 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3185 VoEId(_instanceId,_channelId),
3186 "GetRTCPStatus() => enabled=%d", enabled);
3187 return 0;
3188}
3189
3190int
3191Channel::SetRTCP_CNAME(const char cName[256])
3192{
3193 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3194 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003195 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003196 {
3197 _engineStatisticsPtr->SetLastError(
3198 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3199 "SetRTCP_CNAME() failed to set RTCP CNAME");
3200 return -1;
3201 }
3202 return 0;
3203}
3204
3205int
niklase@google.com470e71d2011-07-07 08:21:25 +00003206Channel::GetRemoteRTCP_CNAME(char cName[256])
3207{
3208 if (cName == NULL)
3209 {
3210 _engineStatisticsPtr->SetLastError(
3211 VE_INVALID_ARGUMENT, kTraceError,
3212 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3213 return -1;
3214 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003215 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003216 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003217 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003218 {
3219 _engineStatisticsPtr->SetLastError(
3220 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3221 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3222 return -1;
3223 }
3224 strcpy(cName, cname);
3225 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3226 VoEId(_instanceId, _channelId),
3227 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3228 return 0;
3229}
3230
3231int
3232Channel::GetRemoteRTCPData(
3233 unsigned int& NTPHigh,
3234 unsigned int& NTPLow,
3235 unsigned int& timestamp,
3236 unsigned int& playoutTimestamp,
3237 unsigned int* jitter,
3238 unsigned short* fractionLost)
3239{
3240 // --- Information from sender info in received Sender Reports
3241
3242 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003243 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003244 {
3245 _engineStatisticsPtr->SetLastError(
3246 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003247 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003248 "side");
3249 return -1;
3250 }
3251
3252 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3253 // and octet count)
3254 NTPHigh = senderInfo.NTPseconds;
3255 NTPLow = senderInfo.NTPfraction;
3256 timestamp = senderInfo.RTPtimeStamp;
3257
3258 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3259 VoEId(_instanceId, _channelId),
3260 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3261 "timestamp=%lu",
3262 NTPHigh, NTPLow, timestamp);
3263
3264 // --- Locally derived information
3265
3266 // This value is updated on each incoming RTCP packet (0 when no packet
3267 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003268 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003269
3270 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3271 VoEId(_instanceId, _channelId),
3272 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003273 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003274
3275 if (NULL != jitter || NULL != fractionLost)
3276 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003277 // Get all RTCP receiver report blocks that have been received on this
3278 // channel. If we receive RTP packets from a remote source we know the
3279 // remote SSRC and use the report block from him.
3280 // Otherwise use the first report block.
3281 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003282 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003283 remote_stats.empty()) {
3284 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3285 VoEId(_instanceId, _channelId),
3286 "GetRemoteRTCPData() failed to measure statistics due"
3287 " to lack of received RTP and/or RTCP packets");
3288 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003289 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003290
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003291 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003292 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3293 for (; it != remote_stats.end(); ++it) {
3294 if (it->remoteSSRC == remoteSSRC)
3295 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003297
3298 if (it == remote_stats.end()) {
3299 // If we have not received any RTCP packets from this SSRC it probably
3300 // means that we have not received any RTP packets.
3301 // Use the first received report block instead.
3302 it = remote_stats.begin();
3303 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003304 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003305
xians@webrtc.org79af7342012-01-31 12:22:14 +00003306 if (jitter) {
3307 *jitter = it->jitter;
3308 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3309 VoEId(_instanceId, _channelId),
3310 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3311 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003312
xians@webrtc.org79af7342012-01-31 12:22:14 +00003313 if (fractionLost) {
3314 *fractionLost = it->fractionLost;
3315 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3316 VoEId(_instanceId, _channelId),
3317 "GetRemoteRTCPData() => fractionLost = %lu",
3318 *fractionLost);
3319 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003320 }
3321 return 0;
3322}
3323
3324int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003325Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003326 unsigned int name,
3327 const char* data,
3328 unsigned short dataLengthInBytes)
3329{
3330 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3331 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003332 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003333 {
3334 _engineStatisticsPtr->SetLastError(
3335 VE_NOT_SENDING, kTraceError,
3336 "SendApplicationDefinedRTCPPacket() not sending");
3337 return -1;
3338 }
3339 if (NULL == data)
3340 {
3341 _engineStatisticsPtr->SetLastError(
3342 VE_INVALID_ARGUMENT, kTraceError,
3343 "SendApplicationDefinedRTCPPacket() invalid data value");
3344 return -1;
3345 }
3346 if (dataLengthInBytes % 4 != 0)
3347 {
3348 _engineStatisticsPtr->SetLastError(
3349 VE_INVALID_ARGUMENT, kTraceError,
3350 "SendApplicationDefinedRTCPPacket() invalid length value");
3351 return -1;
3352 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003353 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003354 if (status == kRtcpOff)
3355 {
3356 _engineStatisticsPtr->SetLastError(
3357 VE_RTCP_ERROR, kTraceError,
3358 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3359 return -1;
3360 }
3361
3362 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003363 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003364 subType,
3365 name,
3366 (const unsigned char*) data,
3367 dataLengthInBytes) != 0)
3368 {
3369 _engineStatisticsPtr->SetLastError(
3370 VE_SEND_ERROR, kTraceError,
3371 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3372 return -1;
3373 }
3374 return 0;
3375}
3376
3377int
3378Channel::GetRTPStatistics(
3379 unsigned int& averageJitterMs,
3380 unsigned int& maxJitterMs,
3381 unsigned int& discardedPackets)
3382{
niklase@google.com470e71d2011-07-07 08:21:25 +00003383 // The jitter statistics is updated for each received RTP packet and is
3384 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003385 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3386 // If RTCP is off, there is no timed thread in the RTCP module regularly
3387 // generating new stats, trigger the update manually here instead.
3388 StreamStatistician* statistician =
3389 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3390 if (statistician) {
3391 // Don't use returned statistics, use data from proxy instead so that
3392 // max jitter can be fetched atomically.
3393 RtcpStatistics s;
3394 statistician->GetStatistics(&s, true);
3395 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003396 }
3397
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003398 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003399 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003400 if (playoutFrequency > 0) {
3401 // Scale RTP statistics given the current playout frequency
3402 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3403 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003404 }
3405
3406 discardedPackets = _numberOfDiscardedPackets;
3407
3408 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3409 VoEId(_instanceId, _channelId),
3410 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003411 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003412 averageJitterMs, maxJitterMs, discardedPackets);
3413 return 0;
3414}
3415
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003416int Channel::GetRemoteRTCPReportBlocks(
3417 std::vector<ReportBlock>* report_blocks) {
3418 if (report_blocks == NULL) {
3419 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3420 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3421 return -1;
3422 }
3423
3424 // Get the report blocks from the latest received RTCP Sender or Receiver
3425 // Report. Each element in the vector contains the sender's SSRC and a
3426 // report block according to RFC 3550.
3427 std::vector<RTCPReportBlock> rtcp_report_blocks;
3428 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3429 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3430 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3431 return -1;
3432 }
3433
3434 if (rtcp_report_blocks.empty())
3435 return 0;
3436
3437 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3438 for (; it != rtcp_report_blocks.end(); ++it) {
3439 ReportBlock report_block;
3440 report_block.sender_SSRC = it->remoteSSRC;
3441 report_block.source_SSRC = it->sourceSSRC;
3442 report_block.fraction_lost = it->fractionLost;
3443 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3444 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3445 report_block.interarrival_jitter = it->jitter;
3446 report_block.last_SR_timestamp = it->lastSR;
3447 report_block.delay_since_last_SR = it->delaySinceLastSR;
3448 report_blocks->push_back(report_block);
3449 }
3450 return 0;
3451}
3452
niklase@google.com470e71d2011-07-07 08:21:25 +00003453int
3454Channel::GetRTPStatistics(CallStatistics& stats)
3455{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003456 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003457
3458 // The jitter statistics is updated for each received RTP packet and is
3459 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003460 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003461 StreamStatistician* statistician =
3462 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3463 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003464 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3465 _engineStatisticsPtr->SetLastError(
3466 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3467 "GetRTPStatistics() failed to read RTP statistics from the "
3468 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003469 }
3470
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003471 stats.fractionLost = statistics.fraction_lost;
3472 stats.cumulativeLost = statistics.cumulative_lost;
3473 stats.extendedMax = statistics.extended_max_sequence_number;
3474 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003475
3476 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3477 VoEId(_instanceId, _channelId),
3478 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003479 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003480 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3481 stats.jitterSamples);
3482
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003483 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003484 stats.rttMs = GetRTT();
niklase@google.com470e71d2011-07-07 08:21:25 +00003485
3486 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3487 VoEId(_instanceId, _channelId),
3488 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3489
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003490 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003491
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003492 uint32_t bytesSent(0);
3493 uint32_t packetsSent(0);
3494 uint32_t bytesReceived(0);
3495 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003496
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003497 if (statistician) {
3498 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3499 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003500
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003501 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003502 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003503 {
3504 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3505 VoEId(_instanceId, _channelId),
3506 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003507 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003508 }
3509
3510 stats.bytesSent = bytesSent;
3511 stats.packetsSent = packetsSent;
3512 stats.bytesReceived = bytesReceived;
3513 stats.packetsReceived = packetsReceived;
3514
3515 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3516 VoEId(_instanceId, _channelId),
3517 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003518 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003519 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3520 stats.packetsReceived);
3521
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003522 // --- Timestamps
3523 {
3524 CriticalSectionScoped lock(ts_stats_lock_.get());
3525 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3526 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003527 return 0;
3528}
3529
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003530int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003531 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003532 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003533
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003534 if (enable) {
3535 if (redPayloadtype < 0 || redPayloadtype > 127) {
3536 _engineStatisticsPtr->SetLastError(
3537 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003538 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003539 return -1;
3540 }
3541
3542 if (SetRedPayloadType(redPayloadtype) < 0) {
3543 _engineStatisticsPtr->SetLastError(
3544 VE_CODEC_ERROR, kTraceError,
3545 "SetSecondarySendCodec() Failed to register RED ACM");
3546 return -1;
3547 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003548 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003549
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003550 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003551 _engineStatisticsPtr->SetLastError(
3552 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003553 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003554 return -1;
3555 }
3556 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003557}
3558
3559int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003560Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003561{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003562 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003563 if (enabled)
3564 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003565 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003566 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003567 {
3568 _engineStatisticsPtr->SetLastError(
3569 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003570 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003571 "module");
3572 return -1;
3573 }
3574 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3575 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003576 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003577 enabled, redPayloadtype);
3578 return 0;
3579 }
3580 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3581 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003582 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003583 return 0;
3584}
3585
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003586int Channel::SetCodecFECStatus(bool enable) {
3587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3588 "Channel::SetCodecFECStatus()");
3589
3590 if (audio_coding_->SetCodecFEC(enable) != 0) {
3591 _engineStatisticsPtr->SetLastError(
3592 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3593 "SetCodecFECStatus() failed to set FEC state");
3594 return -1;
3595 }
3596 return 0;
3597}
3598
3599bool Channel::GetCodecFECStatus() {
3600 bool enabled = audio_coding_->CodecFEC();
3601 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3602 VoEId(_instanceId, _channelId),
3603 "GetCodecFECStatus() => enabled=%d", enabled);
3604 return enabled;
3605}
3606
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003607void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3608 // None of these functions can fail.
3609 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003610 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3611 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003612 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003613 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003614 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003615 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003616}
3617
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003618// Called when we are missing one or more packets.
3619int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003620 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3621}
3622
niklase@google.com470e71d2011-07-07 08:21:25 +00003623int
niklase@google.com470e71d2011-07-07 08:21:25 +00003624Channel::StartRTPDump(const char fileNameUTF8[1024],
3625 RTPDirections direction)
3626{
3627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3628 "Channel::StartRTPDump()");
3629 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3630 {
3631 _engineStatisticsPtr->SetLastError(
3632 VE_INVALID_ARGUMENT, kTraceError,
3633 "StartRTPDump() invalid RTP direction");
3634 return -1;
3635 }
3636 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3637 &_rtpDumpIn : &_rtpDumpOut;
3638 if (rtpDumpPtr == NULL)
3639 {
3640 assert(false);
3641 return -1;
3642 }
3643 if (rtpDumpPtr->IsActive())
3644 {
3645 rtpDumpPtr->Stop();
3646 }
3647 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3648 {
3649 _engineStatisticsPtr->SetLastError(
3650 VE_BAD_FILE, kTraceError,
3651 "StartRTPDump() failed to create file");
3652 return -1;
3653 }
3654 return 0;
3655}
3656
3657int
3658Channel::StopRTPDump(RTPDirections direction)
3659{
3660 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3661 "Channel::StopRTPDump()");
3662 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3663 {
3664 _engineStatisticsPtr->SetLastError(
3665 VE_INVALID_ARGUMENT, kTraceError,
3666 "StopRTPDump() invalid RTP direction");
3667 return -1;
3668 }
3669 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3670 &_rtpDumpIn : &_rtpDumpOut;
3671 if (rtpDumpPtr == NULL)
3672 {
3673 assert(false);
3674 return -1;
3675 }
3676 if (!rtpDumpPtr->IsActive())
3677 {
3678 return 0;
3679 }
3680 return rtpDumpPtr->Stop();
3681}
3682
3683bool
3684Channel::RTPDumpIsActive(RTPDirections direction)
3685{
3686 if ((direction != kRtpIncoming) &&
3687 (direction != kRtpOutgoing))
3688 {
3689 _engineStatisticsPtr->SetLastError(
3690 VE_INVALID_ARGUMENT, kTraceError,
3691 "RTPDumpIsActive() invalid RTP direction");
3692 return false;
3693 }
3694 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3695 &_rtpDumpIn : &_rtpDumpOut;
3696 return rtpDumpPtr->IsActive();
3697}
3698
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003699void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3700 int video_channel) {
3701 CriticalSectionScoped cs(&_callbackCritSect);
3702 if (vie_network_) {
3703 vie_network_->Release();
3704 vie_network_ = NULL;
3705 }
3706 video_channel_ = -1;
3707
3708 if (vie_network != NULL && video_channel != -1) {
3709 vie_network_ = vie_network;
3710 video_channel_ = video_channel;
3711 }
3712}
3713
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003714uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003715Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003716{
3717 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003718 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003719 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003720 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003721 return 0;
3722}
3723
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003724void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003725 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003726 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003727 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003728 CodecInst codec;
3729 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003730
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003731 if (!mono_recording_audio_.get()) {
3732 // Temporary space for DownConvertToCodecFormat.
3733 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003734 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003735 DownConvertToCodecFormat(audio_data,
3736 number_of_frames,
3737 number_of_channels,
3738 sample_rate,
3739 codec.channels,
3740 codec.plfreq,
3741 mono_recording_audio_.get(),
3742 &input_resampler_,
3743 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003744}
3745
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003746uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003747Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003748{
3749 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3750 "Channel::PrepareEncodeAndSend()");
3751
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003752 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003753 {
3754 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3755 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003756 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 }
3758
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003759 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003760 {
3761 MixOrReplaceAudioWithFile(mixingFrequency);
3762 }
3763
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003764 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3765 if (is_muted) {
3766 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003767 }
3768
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003769 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003770 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003771 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003772 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003773 if (_inputExternalMediaCallbackPtr)
3774 {
3775 _inputExternalMediaCallbackPtr->Process(
3776 _channelId,
3777 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003778 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003779 _audioFrame.samples_per_channel_,
3780 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003781 isStereo);
3782 }
3783 }
3784
3785 InsertInbandDtmfTone();
3786
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003787 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003788 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003789 if (is_muted) {
3790 rms_level_.ProcessMuted(length);
3791 } else {
3792 rms_level_.Process(_audioFrame.data_, length);
3793 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003794 }
3795
niklase@google.com470e71d2011-07-07 08:21:25 +00003796 return 0;
3797}
3798
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003799uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003800Channel::EncodeAndSend()
3801{
3802 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3803 "Channel::EncodeAndSend()");
3804
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003805 assert(_audioFrame.num_channels_ <= 2);
3806 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003807 {
3808 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3809 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003810 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003811 }
3812
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003813 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003814
3815 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3816
3817 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003818 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003819 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003820 {
3821 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3822 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003823 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003824 }
3825
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003826 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003827
3828 // --- Encode if complete frame is ready
3829
3830 // This call will trigger AudioPacketizationCallback::SendData if encoding
3831 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003832 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003833}
3834
3835int Channel::RegisterExternalMediaProcessing(
3836 ProcessingTypes type,
3837 VoEMediaProcess& processObject)
3838{
3839 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3840 "Channel::RegisterExternalMediaProcessing()");
3841
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003842 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003843
3844 if (kPlaybackPerChannel == type)
3845 {
3846 if (_outputExternalMediaCallbackPtr)
3847 {
3848 _engineStatisticsPtr->SetLastError(
3849 VE_INVALID_OPERATION, kTraceError,
3850 "Channel::RegisterExternalMediaProcessing() "
3851 "output external media already enabled");
3852 return -1;
3853 }
3854 _outputExternalMediaCallbackPtr = &processObject;
3855 _outputExternalMedia = true;
3856 }
3857 else if (kRecordingPerChannel == type)
3858 {
3859 if (_inputExternalMediaCallbackPtr)
3860 {
3861 _engineStatisticsPtr->SetLastError(
3862 VE_INVALID_OPERATION, kTraceError,
3863 "Channel::RegisterExternalMediaProcessing() "
3864 "output external media already enabled");
3865 return -1;
3866 }
3867 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003868 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003869 }
3870 return 0;
3871}
3872
3873int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3874{
3875 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3876 "Channel::DeRegisterExternalMediaProcessing()");
3877
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003878 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003879
3880 if (kPlaybackPerChannel == type)
3881 {
3882 if (!_outputExternalMediaCallbackPtr)
3883 {
3884 _engineStatisticsPtr->SetLastError(
3885 VE_INVALID_OPERATION, kTraceWarning,
3886 "Channel::DeRegisterExternalMediaProcessing() "
3887 "output external media already disabled");
3888 return 0;
3889 }
3890 _outputExternalMedia = false;
3891 _outputExternalMediaCallbackPtr = NULL;
3892 }
3893 else if (kRecordingPerChannel == type)
3894 {
3895 if (!_inputExternalMediaCallbackPtr)
3896 {
3897 _engineStatisticsPtr->SetLastError(
3898 VE_INVALID_OPERATION, kTraceWarning,
3899 "Channel::DeRegisterExternalMediaProcessing() "
3900 "input external media already disabled");
3901 return 0;
3902 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003903 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003904 _inputExternalMediaCallbackPtr = NULL;
3905 }
3906
3907 return 0;
3908}
3909
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003910int Channel::SetExternalMixing(bool enabled) {
3911 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3912 "Channel::SetExternalMixing(enabled=%d)", enabled);
3913
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003914 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003915 {
3916 _engineStatisticsPtr->SetLastError(
3917 VE_INVALID_OPERATION, kTraceError,
3918 "Channel::SetExternalMixing() "
3919 "external mixing cannot be changed while playing.");
3920 return -1;
3921 }
3922
3923 _externalMixing = enabled;
3924
3925 return 0;
3926}
3927
niklase@google.com470e71d2011-07-07 08:21:25 +00003928int
niklase@google.com470e71d2011-07-07 08:21:25 +00003929Channel::GetNetworkStatistics(NetworkStatistics& stats)
3930{
3931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3932 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003933 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003934 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003935 if (return_value >= 0) {
3936 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3937 }
3938 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003939}
3940
wu@webrtc.org24301a62013-12-13 19:17:43 +00003941void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3942 audio_coding_->GetDecodingCallStatistics(stats);
3943}
3944
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003945bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3946 int* playout_buffer_delay_ms) const {
3947 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003948 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003949 "Channel::GetDelayEstimate() no valid estimate.");
3950 return false;
3951 }
3952 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3953 _recPacketDelayMs;
3954 *playout_buffer_delay_ms = playout_delay_ms_;
3955 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3956 "Channel::GetDelayEstimate()");
3957 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003958}
3959
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003960int Channel::SetInitialPlayoutDelay(int delay_ms)
3961{
3962 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3963 "Channel::SetInitialPlayoutDelay()");
3964 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3965 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3966 {
3967 _engineStatisticsPtr->SetLastError(
3968 VE_INVALID_ARGUMENT, kTraceError,
3969 "SetInitialPlayoutDelay() invalid min delay");
3970 return -1;
3971 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003972 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003973 {
3974 _engineStatisticsPtr->SetLastError(
3975 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3976 "SetInitialPlayoutDelay() failed to set min playout delay");
3977 return -1;
3978 }
3979 return 0;
3980}
3981
3982
niklase@google.com470e71d2011-07-07 08:21:25 +00003983int
3984Channel::SetMinimumPlayoutDelay(int delayMs)
3985{
3986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3987 "Channel::SetMinimumPlayoutDelay()");
3988 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3989 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3990 {
3991 _engineStatisticsPtr->SetLastError(
3992 VE_INVALID_ARGUMENT, kTraceError,
3993 "SetMinimumPlayoutDelay() invalid min delay");
3994 return -1;
3995 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003996 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003997 {
3998 _engineStatisticsPtr->SetLastError(
3999 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4000 "SetMinimumPlayoutDelay() failed to set min playout delay");
4001 return -1;
4002 }
4003 return 0;
4004}
4005
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004006void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4007 uint32_t playout_timestamp = 0;
4008
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004009 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00004010 // This can happen if this channel has not been received any RTP packet. In
4011 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004012 return;
4013 }
4014
4015 uint16_t delay_ms = 0;
4016 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4017 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4018 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4019 " delay from the ADM");
4020 _engineStatisticsPtr->SetLastError(
4021 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4022 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4023 return;
4024 }
4025
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004026 jitter_buffer_playout_timestamp_ = playout_timestamp;
4027
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004028 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00004029 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004030
4031 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4032 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4033 playout_timestamp);
4034
4035 if (rtcp) {
4036 playout_timestamp_rtcp_ = playout_timestamp;
4037 } else {
4038 playout_timestamp_rtp_ = playout_timestamp;
4039 }
4040 playout_delay_ms_ = delay_ms;
4041}
4042
4043int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4044 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4045 "Channel::GetPlayoutTimestamp()");
4046 if (playout_timestamp_rtp_ == 0) {
4047 _engineStatisticsPtr->SetLastError(
4048 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4049 "GetPlayoutTimestamp() failed to retrieve timestamp");
4050 return -1;
4051 }
4052 timestamp = playout_timestamp_rtp_;
4053 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4054 VoEId(_instanceId,_channelId),
4055 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4056 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004057}
4058
4059int
4060Channel::SetInitTimestamp(unsigned int timestamp)
4061{
4062 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4063 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004064 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004065 {
4066 _engineStatisticsPtr->SetLastError(
4067 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4068 return -1;
4069 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004070 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004071 {
4072 _engineStatisticsPtr->SetLastError(
4073 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4074 "SetInitTimestamp() failed to set timestamp");
4075 return -1;
4076 }
4077 return 0;
4078}
4079
4080int
4081Channel::SetInitSequenceNumber(short sequenceNumber)
4082{
4083 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4084 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004085 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004086 {
4087 _engineStatisticsPtr->SetLastError(
4088 VE_SENDING, kTraceError,
4089 "SetInitSequenceNumber() already sending");
4090 return -1;
4091 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004092 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004093 {
4094 _engineStatisticsPtr->SetLastError(
4095 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4096 "SetInitSequenceNumber() failed to set sequence number");
4097 return -1;
4098 }
4099 return 0;
4100}
4101
4102int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004103Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004104{
4105 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4106 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004107 *rtpRtcpModule = _rtpRtcpModule.get();
4108 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004109 return 0;
4110}
4111
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004112// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4113// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004114int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004115Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004116{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004117 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004118 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004119
4120 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004121 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004122
4123 if (_inputFilePlayerPtr == NULL)
4124 {
4125 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4126 VoEId(_instanceId, _channelId),
4127 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4128 " doesnt exist");
4129 return -1;
4130 }
4131
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004132 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004133 fileSamples,
4134 mixingFrequency) == -1)
4135 {
4136 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4137 VoEId(_instanceId, _channelId),
4138 "Channel::MixOrReplaceAudioWithFile() file mixing "
4139 "failed");
4140 return -1;
4141 }
4142 if (fileSamples == 0)
4143 {
4144 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4145 VoEId(_instanceId, _channelId),
4146 "Channel::MixOrReplaceAudioWithFile() file is ended");
4147 return 0;
4148 }
4149 }
4150
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004151 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004152
4153 if (_mixFileWithMicrophone)
4154 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004155 // Currently file stream is always mono.
4156 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004157 MixWithSat(_audioFrame.data_,
4158 _audioFrame.num_channels_,
4159 fileBuffer.get(),
4160 1,
4161 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004162 }
4163 else
4164 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004165 // Replace ACM audio with file.
4166 // Currently file stream is always mono.
4167 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004168 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00004169 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004170 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004171 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004172 mixingFrequency,
4173 AudioFrame::kNormalSpeech,
4174 AudioFrame::kVadUnknown,
4175 1);
4176
4177 }
4178 return 0;
4179}
4180
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004181int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004182Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004183 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004184{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00004185 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004186
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00004187 scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004188 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004189
4190 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004191 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004192
4193 if (_outputFilePlayerPtr == NULL)
4194 {
4195 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4196 VoEId(_instanceId, _channelId),
4197 "Channel::MixAudioWithFile() file mixing failed");
4198 return -1;
4199 }
4200
4201 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004202 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004203 fileSamples,
4204 mixingFrequency) == -1)
4205 {
4206 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4207 VoEId(_instanceId, _channelId),
4208 "Channel::MixAudioWithFile() file mixing failed");
4209 return -1;
4210 }
4211 }
4212
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004213 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004214 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004215 // Currently file stream is always mono.
4216 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004217 MixWithSat(audioFrame.data_,
4218 audioFrame.num_channels_,
4219 fileBuffer.get(),
4220 1,
4221 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004222 }
4223 else
4224 {
4225 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004226 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004227 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004228 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004229 return -1;
4230 }
4231
4232 return 0;
4233}
4234
4235int
4236Channel::InsertInbandDtmfTone()
4237{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004238 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004239 if (_inbandDtmfQueue.PendingDtmf() &&
4240 !_inbandDtmfGenerator.IsAddingTone() &&
4241 _inbandDtmfGenerator.DelaySinceLastTone() >
4242 kMinTelephoneEventSeparationMs)
4243 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004244 int8_t eventCode(0);
4245 uint16_t lengthMs(0);
4246 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004247
4248 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4249 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4250 if (_playInbandDtmfEvent)
4251 {
4252 // Add tone to output mixer using a reduced length to minimize
4253 // risk of echo.
4254 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4255 attenuationDb);
4256 }
4257 }
4258
4259 if (_inbandDtmfGenerator.IsAddingTone())
4260 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004261 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004262 _inbandDtmfGenerator.GetSampleRate(frequency);
4263
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004264 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004265 {
4266 // Update sample rate of Dtmf tone since the mixing frequency
4267 // has changed.
4268 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004269 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004270 // Reset the tone to be added taking the new sample rate into
4271 // account.
4272 _inbandDtmfGenerator.ResetTone();
4273 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004274
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004275 int16_t toneBuffer[320];
4276 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004277 // Get 10ms tone segment and set time since last tone to zero
4278 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4279 {
4280 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4281 VoEId(_instanceId, _channelId),
4282 "Channel::EncodeAndSend() inserting Dtmf failed");
4283 return -1;
4284 }
4285
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004286 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004287 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004288 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004289 sample++)
4290 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004291 for (int channel = 0;
4292 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004293 channel++)
4294 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004295 const int index = sample * _audioFrame.num_channels_ + channel;
4296 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004297 }
4298 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004299
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004300 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004301 } else
4302 {
4303 // Add 10ms to "delay-since-last-tone" counter
4304 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4305 }
4306 return 0;
4307}
4308
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004309int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004310Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4311{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004312 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004313 if (_transportPtr == NULL)
4314 {
4315 return -1;
4316 }
4317 if (!RTCP)
4318 {
4319 return _transportPtr->SendPacket(_channelId, data, len);
4320 }
4321 else
4322 {
4323 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4324 }
4325}
4326
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004327// Called for incoming RTP packets after successful RTP header parsing.
4328void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4329 uint16_t sequence_number) {
4330 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4331 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4332 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004333
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004334 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004335 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004336
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004337 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004338 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004339
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004340 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4341 // every incoming packet.
4342 uint32_t timestamp_diff_ms = (rtp_timestamp -
4343 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004344 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4345 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4346 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4347 // timestamp, the resulting difference is negative, but is set to zero.
4348 // This can happen when a network glitch causes a packet to arrive late,
4349 // and during long comfort noise periods with clock drift.
4350 timestamp_diff_ms = 0;
4351 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004352
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004353 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4354 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004355
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004356 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004357
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004358 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004359
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004360 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4361 _recPacketDelayMs = packet_delay_ms;
4362 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004363
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004364 if (_average_jitter_buffer_delay_us == 0) {
4365 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4366 return;
4367 }
4368
4369 // Filter average delay value using exponential filter (alpha is
4370 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4371 // risk of rounding error) and compensate for it in GetDelayEstimate()
4372 // later.
4373 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4374 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004375}
4376
4377void
4378Channel::RegisterReceiveCodecsToRTPModule()
4379{
4380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4381 "Channel::RegisterReceiveCodecsToRTPModule()");
4382
4383
4384 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004385 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004386
4387 for (int idx = 0; idx < nSupportedCodecs; idx++)
4388 {
4389 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004390 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004391 (rtp_receiver_->RegisterReceivePayload(
4392 codec.plname,
4393 codec.pltype,
4394 codec.plfreq,
4395 codec.channels,
4396 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004397 {
4398 WEBRTC_TRACE(
4399 kTraceWarning,
4400 kTraceVoice,
4401 VoEId(_instanceId, _channelId),
4402 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4403 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4404 codec.plname, codec.pltype, codec.plfreq,
4405 codec.channels, codec.rate);
4406 }
4407 else
4408 {
4409 WEBRTC_TRACE(
4410 kTraceInfo,
4411 kTraceVoice,
4412 VoEId(_instanceId, _channelId),
4413 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004414 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004415 "receiver",
4416 codec.plname, codec.pltype, codec.plfreq,
4417 codec.channels, codec.rate);
4418 }
4419 }
4420}
4421
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004422int Channel::SetSecondarySendCodec(const CodecInst& codec,
4423 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004424 // Sanity check for payload type.
4425 if (red_payload_type < 0 || red_payload_type > 127) {
4426 _engineStatisticsPtr->SetLastError(
4427 VE_PLTYPE_ERROR, kTraceError,
4428 "SetRedPayloadType() invalid RED payload type");
4429 return -1;
4430 }
4431
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004432 if (SetRedPayloadType(red_payload_type) < 0) {
4433 _engineStatisticsPtr->SetLastError(
4434 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4435 "SetSecondarySendCodec() Failed to register RED ACM");
4436 return -1;
4437 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004438 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004439 _engineStatisticsPtr->SetLastError(
4440 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4441 "SetSecondarySendCodec() Failed to register secondary send codec in "
4442 "ACM");
4443 return -1;
4444 }
4445
4446 return 0;
4447}
4448
4449void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004450 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004451}
4452
4453int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004454 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004455 _engineStatisticsPtr->SetLastError(
4456 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4457 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4458 return -1;
4459 }
4460 return 0;
4461}
4462
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004463// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004464int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004465 CodecInst codec;
4466 bool found_red = false;
4467
4468 // Get default RED settings from the ACM database
4469 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4470 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004471 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004472 if (!STR_CASE_CMP(codec.plname, "RED")) {
4473 found_red = true;
4474 break;
4475 }
4476 }
4477
4478 if (!found_red) {
4479 _engineStatisticsPtr->SetLastError(
4480 VE_CODEC_ERROR, kTraceError,
4481 "SetRedPayloadType() RED is not supported");
4482 return -1;
4483 }
4484
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004485 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004486 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004487 _engineStatisticsPtr->SetLastError(
4488 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4489 "SetRedPayloadType() RED registration in ACM module failed");
4490 return -1;
4491 }
4492
4493 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4494 _engineStatisticsPtr->SetLastError(
4495 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4496 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4497 return -1;
4498 }
4499 return 0;
4500}
4501
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004502int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4503 unsigned char id) {
4504 int error = 0;
4505 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4506 if (enable) {
4507 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4508 }
4509 return error;
4510}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004511
wu@webrtc.org94454b72014-06-05 20:34:08 +00004512int32_t Channel::GetPlayoutFrequency() {
4513 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4514 CodecInst current_recive_codec;
4515 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4516 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4517 // Even though the actual sampling rate for G.722 audio is
4518 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4519 // 8,000 Hz because that value was erroneously assigned in
4520 // RFC 1890 and must remain unchanged for backward compatibility.
4521 playout_frequency = 8000;
4522 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4523 // We are resampling Opus internally to 32,000 Hz until all our
4524 // DSP routines can operate at 48,000 Hz, but the RTP clock
4525 // rate for the Opus payload format is standardized to 48,000 Hz,
4526 // because that is the maximum supported decoding sampling rate.
4527 playout_frequency = 48000;
4528 }
4529 }
4530 return playout_frequency;
4531}
4532
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004533int Channel::GetRTT() const {
4534 RTCPMethod method = _rtpRtcpModule->RTCP();
4535 if (method == kRtcpOff) {
4536 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4537 VoEId(_instanceId, _channelId),
4538 "GetRTPStatistics() RTCP is disabled => valid RTT "
4539 "measurements cannot be retrieved");
4540 return 0;
4541 }
4542 std::vector<RTCPReportBlock> report_blocks;
4543 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4544 if (report_blocks.empty()) {
4545 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4546 VoEId(_instanceId, _channelId),
4547 "GetRTPStatistics() failed to measure RTT since no "
4548 "RTCP packets have been received yet");
4549 return 0;
4550 }
4551
4552 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4553 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4554 for (; it != report_blocks.end(); ++it) {
4555 if (it->remoteSSRC == remoteSSRC)
4556 break;
4557 }
4558 if (it == report_blocks.end()) {
4559 // We have not received packets with SSRC matching the report blocks.
4560 // To calculate RTT we try with the SSRC of the first report block.
4561 // This is very important for send-only channels where we don't know
4562 // the SSRC of the other end.
4563 remoteSSRC = report_blocks[0].remoteSSRC;
4564 }
4565 uint16_t rtt = 0;
4566 uint16_t avg_rtt = 0;
4567 uint16_t max_rtt= 0;
4568 uint16_t min_rtt = 0;
4569 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4570 != 0) {
4571 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4572 VoEId(_instanceId, _channelId),
4573 "GetRTPStatistics() failed to retrieve RTT from "
4574 "the RTP/RTCP module");
4575 return 0;
4576 }
4577 return static_cast<int>(rtt);
4578}
4579
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004580} // namespace voe
4581} // namespace webrtc