blob: cd275693de4826bbe10f69f17bf5037a7dee0bce [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
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000016#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000017#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
wu@webrtc.org82c4b852014-05-20 22:55:01 +000018#include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000019#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.org82c4b852014-05-20 22:55:01 +0000686 audioFrame.ntp_time_ms_ = ntp_estimator_->Estimate(audioFrame.timestamp_);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000687
688 if (!first_frame_arrived_) {
689 first_frame_arrived_ = true;
690 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
691 } else {
692 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
693 if (audioFrame.ntp_time_ms_ > 0) {
694 // Compute |capture_start_ntp_time_ms_| so that
695 // |capture_start_ntp_time_ms_| + |elapsed_time_ms| == |ntp_time_ms_|
696 CriticalSectionScoped lock(ts_stats_lock_.get());
697 uint32_t elapsed_time_ms =
698 (audioFrame.timestamp_ - capture_start_rtp_time_stamp_) /
699 (audioFrame.sample_rate_hz_ * 1000);
700 capture_start_ntp_time_ms_ = audioFrame.ntp_time_ms_ - elapsed_time_ms;
701 }
702 }
703
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 return 0;
705}
706
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000707int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000708Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000709{
710 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
711 "Channel::NeededFrequency(id=%d)", id);
712
713 int highestNeeded = 0;
714
715 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000716 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000717
718 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000719 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000721 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 }
723 else
724 {
725 highestNeeded = receiveFrequency;
726 }
727
728 // Special case, if we're playing a file on the playout side
729 // we take that frequency into consideration as well
730 // This is not needed on sending side, since the codec will
731 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000732 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000734 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000735 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 {
737 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
738 {
739 highestNeeded=_outputFilePlayerPtr->Frequency();
740 }
741 }
742 }
743
744 return(highestNeeded);
745}
746
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000747int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000748Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000749 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000750 uint32_t instanceId,
751 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000752{
753 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
754 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
755 channelId, instanceId);
756
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000757 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000758 if (channel == NULL)
759 {
760 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
761 VoEId(instanceId,channelId),
762 "Channel::CreateChannel() unable to allocate memory for"
763 " channel");
764 return -1;
765 }
766 return 0;
767}
768
769void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000770Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000771{
772 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
773 "Channel::PlayNotification(id=%d, durationMs=%d)",
774 id, durationMs);
775
776 // Not implement yet
777}
778
779void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000780Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000781{
782 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
783 "Channel::RecordNotification(id=%d, durationMs=%d)",
784 id, durationMs);
785
786 // Not implement yet
787}
788
789void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000790Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000791{
792 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
793 "Channel::PlayFileEnded(id=%d)", id);
794
795 if (id == _inputFilePlayerId)
796 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000797 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
799 VoEId(_instanceId,_channelId),
800 "Channel::PlayFileEnded() => input file player module is"
801 " shutdown");
802 }
803 else if (id == _outputFilePlayerId)
804 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000805 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
807 VoEId(_instanceId,_channelId),
808 "Channel::PlayFileEnded() => output file player module is"
809 " shutdown");
810 }
811}
812
813void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000814Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000815{
816 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
817 "Channel::RecordFileEnded(id=%d)", id);
818
819 assert(id == _outputFileRecorderId);
820
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000821 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000822
823 _outputFileRecording = false;
824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
825 VoEId(_instanceId,_channelId),
826 "Channel::RecordFileEnded() => output file recorder module is"
827 " shutdown");
828}
829
pbos@webrtc.org92135212013-05-14 08:31:39 +0000830Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000831 uint32_t instanceId,
832 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
834 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000835 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000837 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000838 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000839 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000840 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000841 rtp_receive_statistics_(ReceiveStatistics::Create(
842 Clock::GetRealTimeClock())),
843 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
844 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
845 this, this, rtp_payload_registry_.get())),
846 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000847 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000848 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 _rtpDumpIn(*RtpDump::CreateRtpDump()),
850 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000851 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000853 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000854 _inputFilePlayerPtr(NULL),
855 _outputFilePlayerPtr(NULL),
856 _outputFileRecorderPtr(NULL),
857 // Avoid conflict with other channels by adding 1024 - 1026,
858 // won't use as much as 1024 channels.
859 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
860 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
861 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000863 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
864 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000865 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 _inputExternalMediaCallbackPtr(NULL),
867 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000868 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
869 _sendTelephoneEventPayloadType(106),
wu@webrtc.org82c4b852014-05-20 22:55:01 +0000870 ntp_estimator_(new RemoteNtpTimeEstimator(Clock::GetRealTimeClock())),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000871 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000872 playout_timestamp_rtp_(0),
873 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000874 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000876 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000877 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
878 first_frame_arrived_(false),
879 capture_start_rtp_time_stamp_(0),
880 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000881 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000882 _outputMixerPtr(NULL),
883 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000884 _moduleProcessThreadPtr(NULL),
885 _audioDeviceModulePtr(NULL),
886 _voiceEngineObserverPtr(NULL),
887 _callbackCritSectPtr(NULL),
888 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _rxVadObserverPtr(NULL),
890 _oldVadDecision(-1),
891 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000893 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000894 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000895 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000896 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 _mute(false),
898 _panLeft(1.0f),
899 _panRight(1.0f),
900 _outputGain(1.0f),
901 _playOutbandDtmfEvent(false),
902 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _lastLocalTimeStamp(0),
904 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000905 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _rtpPacketTimedOut(false),
907 _rtpPacketTimeOutIsEnabled(false),
908 _rtpTimeOutSeconds(0),
909 _connectionObserver(false),
910 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000911 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000912 vie_network_(NULL),
913 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000914 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000915 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 _previousTimestamp(0),
917 _recPacketDelayMs(20),
918 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000920 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000921 restored_packet_in_use_(false),
922 bitrate_controller_(
923 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
924 true)),
925 rtcp_bandwidth_observer_(
926 bitrate_controller_->CreateRtcpBandwidthObserver()),
927 send_bitrate_observer_(new VoEBitrateObserver(this))
niklase@google.com470e71d2011-07-07 08:21:25 +0000928{
929 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
930 "Channel::Channel() - ctor");
931 _inbandDtmfQueue.ResetDtmf();
932 _inbandDtmfGenerator.Init();
933 _outputAudioLevel.Clear();
934
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000935 RtpRtcp::Configuration configuration;
936 configuration.id = VoEModuleId(instanceId, channelId);
937 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000938 configuration.outgoing_transport = this;
939 configuration.rtcp_feedback = this;
940 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000941 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000942 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000943
944 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000945
946 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
947 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
948 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000949
950 Config audioproc_config;
951 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
952 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000953}
954
955Channel::~Channel()
956{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000957 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
959 "Channel::~Channel() - dtor");
960
961 if (_outputExternalMedia)
962 {
963 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
964 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000965 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 {
967 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
968 }
969 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000970 StopPlayout();
971
972 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000973 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000974 if (_inputFilePlayerPtr)
975 {
976 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
977 _inputFilePlayerPtr->StopPlayingFile();
978 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
979 _inputFilePlayerPtr = NULL;
980 }
981 if (_outputFilePlayerPtr)
982 {
983 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
984 _outputFilePlayerPtr->StopPlayingFile();
985 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
986 _outputFilePlayerPtr = NULL;
987 }
988 if (_outputFileRecorderPtr)
989 {
990 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
991 _outputFileRecorderPtr->StopRecording();
992 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
993 _outputFileRecorderPtr = NULL;
994 }
995 }
996
997 // The order to safely shutdown modules in a channel is:
998 // 1. De-register callbacks in modules
999 // 2. De-register modules in process thread
1000 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001001 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 {
1003 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1004 VoEId(_instanceId,_channelId),
1005 "~Channel() failed to de-register transport callback"
1006 " (Audio coding module)");
1007 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001008 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 {
1010 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1011 VoEId(_instanceId,_channelId),
1012 "~Channel() failed to de-register VAD callback"
1013 " (Audio coding module)");
1014 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001016 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001017 {
1018 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1019 VoEId(_instanceId,_channelId),
1020 "~Channel() failed to deregister RTP/RTCP module");
1021 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 // End of modules shutdown
1023
1024 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001025 if (vie_network_) {
1026 vie_network_->Release();
1027 vie_network_ = NULL;
1028 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1030 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001031 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001033 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001034}
1035
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001036int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001037Channel::Init()
1038{
1039 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1040 "Channel::Init()");
1041
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001042 channel_state_.Reset();
1043
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 // --- Initial sanity
1045
1046 if ((_engineStatisticsPtr == NULL) ||
1047 (_moduleProcessThreadPtr == NULL))
1048 {
1049 WEBRTC_TRACE(kTraceError, kTraceVoice,
1050 VoEId(_instanceId,_channelId),
1051 "Channel::Init() must call SetEngineInformation() first");
1052 return -1;
1053 }
1054
1055 // --- Add modules to process thread (for periodic schedulation)
1056
1057 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001058 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001060 if (processThreadFail)
1061 {
1062 _engineStatisticsPtr->SetLastError(
1063 VE_CANNOT_INIT_CHANNEL, kTraceError,
1064 "Channel::Init() modules not registered");
1065 return -1;
1066 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001067 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001068
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001069 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001070#ifdef WEBRTC_CODEC_AVT
1071 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001072 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001073#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001074 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 {
1076 _engineStatisticsPtr->SetLastError(
1077 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1078 "Channel::Init() unable to initialize the ACM - 1");
1079 return -1;
1080 }
1081
1082 // --- RTP/RTCP module initialization
1083
1084 // Ensure that RTCP is enabled by default for the created channel.
1085 // Note that, the module will keep generating RTCP until it is explicitly
1086 // disabled by the user.
1087 // After StopListen (when no sockets exists), RTCP packets will no longer
1088 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001089 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1090 // RTCP is enabled by default.
1091 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 {
1093 _engineStatisticsPtr->SetLastError(
1094 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1095 "Channel::Init() RTP/RTCP module not initialized");
1096 return -1;
1097 }
1098
1099 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001100 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001101 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1102 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001103
1104 if (fail)
1105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_CANNOT_INIT_CHANNEL, kTraceError,
1108 "Channel::Init() callbacks not registered");
1109 return -1;
1110 }
1111
1112 // --- Register all supported codecs to the receiving side of the
1113 // RTP/RTCP module
1114
1115 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001116 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001117
1118 for (int idx = 0; idx < nSupportedCodecs; idx++)
1119 {
1120 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001121 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001122 (rtp_receiver_->RegisterReceivePayload(
1123 codec.plname,
1124 codec.pltype,
1125 codec.plfreq,
1126 codec.channels,
1127 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 {
1129 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1130 VoEId(_instanceId,_channelId),
1131 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1132 "to RTP/RTCP receiver",
1133 codec.plname, codec.pltype, codec.plfreq,
1134 codec.channels, codec.rate);
1135 }
1136 else
1137 {
1138 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1139 VoEId(_instanceId,_channelId),
1140 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1141 "the RTP/RTCP receiver",
1142 codec.plname, codec.pltype, codec.plfreq,
1143 codec.channels, codec.rate);
1144 }
1145
1146 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001147 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 {
1149 SetSendCodec(codec);
1150 }
1151
1152 // Register default PT for outband 'telephone-event'
1153 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1154 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001155 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001156 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001157 {
1158 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1159 VoEId(_instanceId,_channelId),
1160 "Channel::Init() failed to register outband "
1161 "'telephone-event' (%d/%d) correctly",
1162 codec.pltype, codec.plfreq);
1163 }
1164 }
1165
1166 if (!STR_CASE_CMP(codec.plname, "CN"))
1167 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001168 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1169 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001170 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001171 {
1172 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1173 VoEId(_instanceId,_channelId),
1174 "Channel::Init() failed to register CN (%d/%d) "
1175 "correctly - 1",
1176 codec.pltype, codec.plfreq);
1177 }
1178 }
1179#ifdef WEBRTC_CODEC_RED
1180 // Register RED to the receiving side of the ACM.
1181 // We will not receive an OnInitializeDecoder() callback for RED.
1182 if (!STR_CASE_CMP(codec.plname, "RED"))
1183 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001184 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
1186 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1187 VoEId(_instanceId,_channelId),
1188 "Channel::Init() failed to register RED (%d/%d) "
1189 "correctly",
1190 codec.pltype, codec.plfreq);
1191 }
1192 }
1193#endif
1194 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001195
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001196 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1197 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1198 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001199 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001200 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1201 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1202 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 }
1204
1205 return 0;
1206}
1207
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001208int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001209Channel::SetEngineInformation(Statistics& engineStatistics,
1210 OutputMixer& outputMixer,
1211 voe::TransmitMixer& transmitMixer,
1212 ProcessThread& moduleProcessThread,
1213 AudioDeviceModule& audioDeviceModule,
1214 VoiceEngineObserver* voiceEngineObserver,
1215 CriticalSectionWrapper* callbackCritSect)
1216{
1217 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1218 "Channel::SetEngineInformation()");
1219 _engineStatisticsPtr = &engineStatistics;
1220 _outputMixerPtr = &outputMixer;
1221 _transmitMixerPtr = &transmitMixer,
1222 _moduleProcessThreadPtr = &moduleProcessThread;
1223 _audioDeviceModulePtr = &audioDeviceModule;
1224 _voiceEngineObserverPtr = voiceEngineObserver;
1225 _callbackCritSectPtr = callbackCritSect;
1226 return 0;
1227}
1228
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001229int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001230Channel::UpdateLocalTimeStamp()
1231{
1232
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001233 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001234 return 0;
1235}
1236
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001237int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001238Channel::StartPlayout()
1239{
1240 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1241 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 {
1244 return 0;
1245 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001246
1247 if (!_externalMixing) {
1248 // Add participant as candidates for mixing.
1249 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1250 {
1251 _engineStatisticsPtr->SetLastError(
1252 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1253 "StartPlayout() failed to add participant to mixer");
1254 return -1;
1255 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 }
1257
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001258 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001259 if (RegisterFilePlayingToMixer() != 0)
1260 return -1;
1261
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 return 0;
1263}
1264
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001265int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001266Channel::StopPlayout()
1267{
1268 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1269 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001270 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 {
1272 return 0;
1273 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001274
1275 if (!_externalMixing) {
1276 // Remove participant as candidates for mixing
1277 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1278 {
1279 _engineStatisticsPtr->SetLastError(
1280 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1281 "StopPlayout() failed to remove participant from mixer");
1282 return -1;
1283 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 }
1285
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001286 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001287 _outputAudioLevel.Clear();
1288
1289 return 0;
1290}
1291
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001292int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001293Channel::StartSend()
1294{
1295 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1296 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001297 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001298 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001299 if (send_sequence_number_)
1300 SetInitSequenceNumber(send_sequence_number_);
1301
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001302 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001303 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001304 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001306 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001307
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001308 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 {
1310 _engineStatisticsPtr->SetLastError(
1311 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1312 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001313 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001314 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 return -1;
1316 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001317
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 return 0;
1319}
1320
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001321int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001322Channel::StopSend()
1323{
1324 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1325 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001326 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001328 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001329 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001330 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001331
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001332 // Store the sequence number to be able to pick up the same sequence for
1333 // the next StartSend(). This is needed for restarting device, otherwise
1334 // it might cause libSRTP to complain about packets being replayed.
1335 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1336 // CL is landed. See issue
1337 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1338 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1339
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 // Reset sending SSRC and sequence number and triggers direct transmission
1341 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001342 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1343 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001344 {
1345 _engineStatisticsPtr->SetLastError(
1346 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1347 "StartSend() RTP/RTCP failed to stop sending");
1348 }
1349
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 return 0;
1351}
1352
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001353int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001354Channel::StartReceiving()
1355{
1356 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1357 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001358 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001359 {
1360 return 0;
1361 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001362 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 _numberOfDiscardedPackets = 0;
1364 return 0;
1365}
1366
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001367int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001368Channel::StopReceiving()
1369{
1370 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1371 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001372 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 {
1374 return 0;
1375 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001376
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001377 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 return 0;
1379}
1380
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001381int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001382Channel::SetNetEQPlayoutMode(NetEqModes mode)
1383{
1384 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1385 "Channel::SetNetEQPlayoutMode()");
1386 AudioPlayoutMode playoutMode(voice);
1387 switch (mode)
1388 {
1389 case kNetEqDefault:
1390 playoutMode = voice;
1391 break;
1392 case kNetEqStreaming:
1393 playoutMode = streaming;
1394 break;
1395 case kNetEqFax:
1396 playoutMode = fax;
1397 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001398 case kNetEqOff:
1399 playoutMode = off;
1400 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001401 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001402 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 {
1404 _engineStatisticsPtr->SetLastError(
1405 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1406 "SetNetEQPlayoutMode() failed to set playout mode");
1407 return -1;
1408 }
1409 return 0;
1410}
1411
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001412int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001413Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1414{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001415 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 switch (playoutMode)
1417 {
1418 case voice:
1419 mode = kNetEqDefault;
1420 break;
1421 case streaming:
1422 mode = kNetEqStreaming;
1423 break;
1424 case fax:
1425 mode = kNetEqFax;
1426 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001427 case off:
1428 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001429 }
1430 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1431 VoEId(_instanceId,_channelId),
1432 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1433 return 0;
1434}
1435
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001436int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001437Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1438{
1439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1440 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001441 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001442
1443 if (_voiceEngineObserverPtr)
1444 {
1445 _engineStatisticsPtr->SetLastError(
1446 VE_INVALID_OPERATION, kTraceError,
1447 "RegisterVoiceEngineObserver() observer already enabled");
1448 return -1;
1449 }
1450 _voiceEngineObserverPtr = &observer;
1451 return 0;
1452}
1453
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001454int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001455Channel::DeRegisterVoiceEngineObserver()
1456{
1457 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1458 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001459 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001460
1461 if (!_voiceEngineObserverPtr)
1462 {
1463 _engineStatisticsPtr->SetLastError(
1464 VE_INVALID_OPERATION, kTraceWarning,
1465 "DeRegisterVoiceEngineObserver() observer already disabled");
1466 return 0;
1467 }
1468 _voiceEngineObserverPtr = NULL;
1469 return 0;
1470}
1471
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001472int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001473Channel::GetSendCodec(CodecInst& codec)
1474{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001475 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001476}
1477
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001478int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001479Channel::GetRecCodec(CodecInst& codec)
1480{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001481 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001482}
1483
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001484int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001485Channel::SetSendCodec(const CodecInst& codec)
1486{
1487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "Channel::SetSendCodec()");
1489
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001490 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001491 {
1492 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1493 "SetSendCodec() failed to register codec to ACM");
1494 return -1;
1495 }
1496
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001497 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001498 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001499 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1500 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 {
1502 WEBRTC_TRACE(
1503 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1504 "SetSendCodec() failed to register codec to"
1505 " RTP/RTCP module");
1506 return -1;
1507 }
1508 }
1509
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001510 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 {
1512 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1513 "SetSendCodec() failed to set audio packet size");
1514 return -1;
1515 }
1516
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001517 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1518 codec.rate, 0, 0);
1519
niklase@google.com470e71d2011-07-07 08:21:25 +00001520 return 0;
1521}
1522
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001523void
1524Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1525 const uint8_t fraction_lost, // 0 - 255.
1526 const uint32_t rtt) {
1527 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1528 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1529 bitrate_bps, fraction_lost, rtt);
1530 // Normalizes rate to 0 - 100.
1531 if (audio_coding_->SetPacketLossRate(100 * fraction_lost / 255) != 0) {
1532 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1533 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1534 assert(false); // This should not happen.
1535 }
1536}
1537
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001538int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001539Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1540{
1541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1542 "Channel::SetVADStatus(mode=%d)", mode);
1543 // To disable VAD, DTX must be disabled too
1544 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001545 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001546 {
1547 _engineStatisticsPtr->SetLastError(
1548 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1549 "SetVADStatus() failed to set VAD");
1550 return -1;
1551 }
1552 return 0;
1553}
1554
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001555int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001556Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1557{
1558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1559 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001560 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001561 {
1562 _engineStatisticsPtr->SetLastError(
1563 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1564 "GetVADStatus() failed to get VAD status");
1565 return -1;
1566 }
1567 disabledDTX = !disabledDTX;
1568 return 0;
1569}
1570
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001571int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001572Channel::SetRecPayloadType(const CodecInst& codec)
1573{
1574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1575 "Channel::SetRecPayloadType()");
1576
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001577 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001578 {
1579 _engineStatisticsPtr->SetLastError(
1580 VE_ALREADY_PLAYING, kTraceError,
1581 "SetRecPayloadType() unable to set PT while playing");
1582 return -1;
1583 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001584 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001585 {
1586 _engineStatisticsPtr->SetLastError(
1587 VE_ALREADY_LISTENING, kTraceError,
1588 "SetRecPayloadType() unable to set PT while listening");
1589 return -1;
1590 }
1591
1592 if (codec.pltype == -1)
1593 {
1594 // De-register the selected codec (RTP/RTCP module and ACM)
1595
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001596 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001597 CodecInst rxCodec = codec;
1598
1599 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001600 rtp_payload_registry_->ReceivePayloadType(
1601 rxCodec.plname,
1602 rxCodec.plfreq,
1603 rxCodec.channels,
1604 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1605 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 rxCodec.pltype = pltype;
1607
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001608 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001609 {
1610 _engineStatisticsPtr->SetLastError(
1611 VE_RTP_RTCP_MODULE_ERROR,
1612 kTraceError,
1613 "SetRecPayloadType() RTP/RTCP-module deregistration "
1614 "failed");
1615 return -1;
1616 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001617 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001618 {
1619 _engineStatisticsPtr->SetLastError(
1620 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1621 "SetRecPayloadType() ACM deregistration failed - 1");
1622 return -1;
1623 }
1624 return 0;
1625 }
1626
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001627 if (rtp_receiver_->RegisterReceivePayload(
1628 codec.plname,
1629 codec.pltype,
1630 codec.plfreq,
1631 codec.channels,
1632 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001633 {
1634 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001635 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1636 if (rtp_receiver_->RegisterReceivePayload(
1637 codec.plname,
1638 codec.pltype,
1639 codec.plfreq,
1640 codec.channels,
1641 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001642 {
1643 _engineStatisticsPtr->SetLastError(
1644 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1645 "SetRecPayloadType() RTP/RTCP-module registration failed");
1646 return -1;
1647 }
1648 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001649 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001650 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001651 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1652 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001653 {
1654 _engineStatisticsPtr->SetLastError(
1655 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1656 "SetRecPayloadType() ACM registration failed - 1");
1657 return -1;
1658 }
1659 }
1660 return 0;
1661}
1662
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001663int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001664Channel::GetRecPayloadType(CodecInst& codec)
1665{
1666 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1667 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001668 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001669 if (rtp_payload_registry_->ReceivePayloadType(
1670 codec.plname,
1671 codec.plfreq,
1672 codec.channels,
1673 (codec.rate < 0) ? 0 : codec.rate,
1674 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001675 {
1676 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001677 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001678 "GetRecPayloadType() failed to retrieve RX payload type");
1679 return -1;
1680 }
1681 codec.pltype = payloadType;
1682 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1683 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1684 return 0;
1685}
1686
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001687int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001688Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1689{
1690 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1691 "Channel::SetSendCNPayloadType()");
1692
1693 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001694 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001695 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001696 if (frequency == kFreq32000Hz)
1697 samplingFreqHz = 32000;
1698 else if (frequency == kFreq16000Hz)
1699 samplingFreqHz = 16000;
1700
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001701 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001702 {
1703 _engineStatisticsPtr->SetLastError(
1704 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1705 "SetSendCNPayloadType() failed to retrieve default CN codec "
1706 "settings");
1707 return -1;
1708 }
1709
1710 // Modify the payload type (must be set to dynamic range)
1711 codec.pltype = type;
1712
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001713 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001714 {
1715 _engineStatisticsPtr->SetLastError(
1716 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1717 "SetSendCNPayloadType() failed to register CN to ACM");
1718 return -1;
1719 }
1720
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001721 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001722 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001723 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1724 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001725 {
1726 _engineStatisticsPtr->SetLastError(
1727 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1728 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1729 "module");
1730 return -1;
1731 }
1732 }
1733 return 0;
1734}
1735
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001736int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001737{
1738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1739 "Channel::RegisterExternalTransport()");
1740
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001741 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001742
niklase@google.com470e71d2011-07-07 08:21:25 +00001743 if (_externalTransport)
1744 {
1745 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1746 kTraceError,
1747 "RegisterExternalTransport() external transport already enabled");
1748 return -1;
1749 }
1750 _externalTransport = true;
1751 _transportPtr = &transport;
1752 return 0;
1753}
1754
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001755int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001756Channel::DeRegisterExternalTransport()
1757{
1758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1759 "Channel::DeRegisterExternalTransport()");
1760
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001761 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001762
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 if (!_transportPtr)
1764 {
1765 _engineStatisticsPtr->SetLastError(
1766 VE_INVALID_OPERATION, kTraceWarning,
1767 "DeRegisterExternalTransport() external transport already "
1768 "disabled");
1769 return 0;
1770 }
1771 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001772 _transportPtr = NULL;
1773 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1774 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001775 return 0;
1776}
1777
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001778int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1779 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001780 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1781 "Channel::ReceivedRTPPacket()");
1782
1783 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001784 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001785
1786 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001787 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1788 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001789 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1790 VoEId(_instanceId,_channelId),
1791 "Channel::SendPacket() RTP dump to input file failed");
1792 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001793 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001794 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001795 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1796 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1797 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001798 return -1;
1799 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001800 header.payload_type_frequency =
1801 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001802 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001803 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001804 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001805 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001806 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001807 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001808
1809 // Forward any packets to ViE bandwidth estimator, if enabled.
1810 {
1811 CriticalSectionScoped cs(&_callbackCritSect);
1812 if (vie_network_) {
1813 int64_t arrival_time_ms;
1814 if (packet_time.timestamp != -1) {
1815 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1816 } else {
1817 arrival_time_ms = TickTime::MillisecondTimestamp();
1818 }
1819 int payload_length = length - header.headerLength;
1820 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1821 payload_length, header);
1822 }
1823 }
1824
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001825 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001826}
1827
1828bool Channel::ReceivePacket(const uint8_t* packet,
1829 int packet_length,
1830 const RTPHeader& header,
1831 bool in_order) {
1832 if (rtp_payload_registry_->IsEncapsulated(header)) {
1833 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001834 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001835 const uint8_t* payload = packet + header.headerLength;
1836 int payload_length = packet_length - header.headerLength;
1837 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001838 PayloadUnion payload_specific;
1839 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001840 &payload_specific)) {
1841 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001842 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001843 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1844 payload_specific, in_order);
1845}
1846
1847bool Channel::HandleEncapsulation(const uint8_t* packet,
1848 int packet_length,
1849 const RTPHeader& header) {
1850 if (!rtp_payload_registry_->IsRtx(header))
1851 return false;
1852
1853 // Remove the RTX header and parse the original RTP header.
1854 if (packet_length < header.headerLength)
1855 return false;
1856 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1857 return false;
1858 if (restored_packet_in_use_) {
1859 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1860 "Multiple RTX headers detected, dropping packet");
1861 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001862 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001863 uint8_t* restored_packet_ptr = restored_packet_;
1864 if (!rtp_payload_registry_->RestoreOriginalPacket(
1865 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1866 header)) {
1867 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1868 "Incoming RTX packet: invalid RTP header");
1869 return false;
1870 }
1871 restored_packet_in_use_ = true;
1872 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1873 restored_packet_in_use_ = false;
1874 return ret;
1875}
1876
1877bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1878 StreamStatistician* statistician =
1879 rtp_receive_statistics_->GetStatistician(header.ssrc);
1880 if (!statistician)
1881 return false;
1882 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001883}
1884
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001885bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1886 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001887 // Retransmissions are handled separately if RTX is enabled.
1888 if (rtp_payload_registry_->RtxEnabled())
1889 return false;
1890 StreamStatistician* statistician =
1891 rtp_receive_statistics_->GetStatistician(header.ssrc);
1892 if (!statistician)
1893 return false;
1894 // Check if this is a retransmission.
1895 uint16_t min_rtt = 0;
1896 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001897 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001898 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001899}
1900
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001901int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001902 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1903 "Channel::ReceivedRTCPPacket()");
1904 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001905 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001906
1907 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001908 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1909 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001910 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1911 VoEId(_instanceId,_channelId),
1912 "Channel::SendPacket() RTCP dump to input file failed");
1913 }
1914
1915 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001916 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1917 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001918 _engineStatisticsPtr->SetLastError(
1919 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1920 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1921 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001922
1923 ntp_estimator_->UpdateRtcpTimestamp(rtp_receiver_->SSRC(),
1924 _rtpRtcpModule.get());
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001925 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001926}
1927
niklase@google.com470e71d2011-07-07 08:21:25 +00001928int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001929 bool loop,
1930 FileFormats format,
1931 int startPosition,
1932 float volumeScaling,
1933 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001934 const CodecInst* codecInst)
1935{
1936 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1937 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1938 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1939 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1940 startPosition, stopPosition);
1941
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001942 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001943 {
1944 _engineStatisticsPtr->SetLastError(
1945 VE_ALREADY_PLAYING, kTraceError,
1946 "StartPlayingFileLocally() is already playing");
1947 return -1;
1948 }
1949
niklase@google.com470e71d2011-07-07 08:21:25 +00001950 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001951 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001952
1953 if (_outputFilePlayerPtr)
1954 {
1955 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1956 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1957 _outputFilePlayerPtr = NULL;
1958 }
1959
1960 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1961 _outputFilePlayerId, (const FileFormats)format);
1962
1963 if (_outputFilePlayerPtr == NULL)
1964 {
1965 _engineStatisticsPtr->SetLastError(
1966 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001967 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001968 return -1;
1969 }
1970
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001971 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001972
1973 if (_outputFilePlayerPtr->StartPlayingFile(
1974 fileName,
1975 loop,
1976 startPosition,
1977 volumeScaling,
1978 notificationTime,
1979 stopPosition,
1980 (const CodecInst*)codecInst) != 0)
1981 {
1982 _engineStatisticsPtr->SetLastError(
1983 VE_BAD_FILE, kTraceError,
1984 "StartPlayingFile() failed to start file playout");
1985 _outputFilePlayerPtr->StopPlayingFile();
1986 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1987 _outputFilePlayerPtr = NULL;
1988 return -1;
1989 }
1990 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001991 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001993
1994 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001995 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001996
1997 return 0;
1998}
1999
2000int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002001 FileFormats format,
2002 int startPosition,
2003 float volumeScaling,
2004 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002005 const CodecInst* codecInst)
2006{
2007 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2008 "Channel::StartPlayingFileLocally(format=%d,"
2009 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2010 format, volumeScaling, startPosition, stopPosition);
2011
2012 if(stream == NULL)
2013 {
2014 _engineStatisticsPtr->SetLastError(
2015 VE_BAD_FILE, kTraceError,
2016 "StartPlayingFileLocally() NULL as input stream");
2017 return -1;
2018 }
2019
2020
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002021 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002022 {
2023 _engineStatisticsPtr->SetLastError(
2024 VE_ALREADY_PLAYING, kTraceError,
2025 "StartPlayingFileLocally() is already playing");
2026 return -1;
2027 }
2028
niklase@google.com470e71d2011-07-07 08:21:25 +00002029 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002030 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002031
2032 // Destroy the old instance
2033 if (_outputFilePlayerPtr)
2034 {
2035 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2036 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2037 _outputFilePlayerPtr = NULL;
2038 }
2039
2040 // Create the instance
2041 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2042 _outputFilePlayerId,
2043 (const FileFormats)format);
2044
2045 if (_outputFilePlayerPtr == NULL)
2046 {
2047 _engineStatisticsPtr->SetLastError(
2048 VE_INVALID_ARGUMENT, kTraceError,
2049 "StartPlayingFileLocally() filePlayer format isnot correct");
2050 return -1;
2051 }
2052
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002053 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002054
2055 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2056 volumeScaling,
2057 notificationTime,
2058 stopPosition, codecInst) != 0)
2059 {
2060 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2061 "StartPlayingFile() failed to "
2062 "start file playout");
2063 _outputFilePlayerPtr->StopPlayingFile();
2064 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2065 _outputFilePlayerPtr = NULL;
2066 return -1;
2067 }
2068 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002069 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002070 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002071
2072 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002073 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002074
niklase@google.com470e71d2011-07-07 08:21:25 +00002075 return 0;
2076}
2077
2078int Channel::StopPlayingFileLocally()
2079{
2080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2081 "Channel::StopPlayingFileLocally()");
2082
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002083 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002084 {
2085 _engineStatisticsPtr->SetLastError(
2086 VE_INVALID_OPERATION, kTraceWarning,
2087 "StopPlayingFileLocally() isnot playing");
2088 return 0;
2089 }
2090
niklase@google.com470e71d2011-07-07 08:21:25 +00002091 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002092 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002093
2094 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2095 {
2096 _engineStatisticsPtr->SetLastError(
2097 VE_STOP_RECORDING_FAILED, kTraceError,
2098 "StopPlayingFile() could not stop playing");
2099 return -1;
2100 }
2101 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2102 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2103 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002104 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002105 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002106 // _fileCritSect cannot be taken while calling
2107 // SetAnonymousMixibilityStatus. Refer to comments in
2108 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002109 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2110 {
2111 _engineStatisticsPtr->SetLastError(
2112 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002113 "StopPlayingFile() failed to stop participant from playing as"
2114 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002115 return -1;
2116 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002117
2118 return 0;
2119}
2120
2121int Channel::IsPlayingFileLocally() const
2122{
2123 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2124 "Channel::IsPlayingFileLocally()");
2125
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002126 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002127}
2128
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002129int Channel::RegisterFilePlayingToMixer()
2130{
2131 // Return success for not registering for file playing to mixer if:
2132 // 1. playing file before playout is started on that channel.
2133 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002134 if (!channel_state_.Get().playing ||
2135 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002136 {
2137 return 0;
2138 }
2139
2140 // |_fileCritSect| cannot be taken while calling
2141 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2142 // frames can be pulled by the mixer. Since the frames are generated from
2143 // the file, _fileCritSect will be taken. This would result in a deadlock.
2144 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2145 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002146 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002147 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002148 _engineStatisticsPtr->SetLastError(
2149 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2150 "StartPlayingFile() failed to add participant as file to mixer");
2151 _outputFilePlayerPtr->StopPlayingFile();
2152 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2153 _outputFilePlayerPtr = NULL;
2154 return -1;
2155 }
2156
2157 return 0;
2158}
2159
niklase@google.com470e71d2011-07-07 08:21:25 +00002160int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002161 bool loop,
2162 FileFormats format,
2163 int startPosition,
2164 float volumeScaling,
2165 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002166 const CodecInst* codecInst)
2167{
2168 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2169 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2170 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2171 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2172 startPosition, stopPosition);
2173
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002174 CriticalSectionScoped cs(&_fileCritSect);
2175
2176 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002177 {
2178 _engineStatisticsPtr->SetLastError(
2179 VE_ALREADY_PLAYING, kTraceWarning,
2180 "StartPlayingFileAsMicrophone() filePlayer is playing");
2181 return 0;
2182 }
2183
niklase@google.com470e71d2011-07-07 08:21:25 +00002184 // Destroy the old instance
2185 if (_inputFilePlayerPtr)
2186 {
2187 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2188 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2189 _inputFilePlayerPtr = NULL;
2190 }
2191
2192 // Create the instance
2193 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2194 _inputFilePlayerId, (const FileFormats)format);
2195
2196 if (_inputFilePlayerPtr == NULL)
2197 {
2198 _engineStatisticsPtr->SetLastError(
2199 VE_INVALID_ARGUMENT, kTraceError,
2200 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2201 return -1;
2202 }
2203
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002204 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002205
2206 if (_inputFilePlayerPtr->StartPlayingFile(
2207 fileName,
2208 loop,
2209 startPosition,
2210 volumeScaling,
2211 notificationTime,
2212 stopPosition,
2213 (const CodecInst*)codecInst) != 0)
2214 {
2215 _engineStatisticsPtr->SetLastError(
2216 VE_BAD_FILE, kTraceError,
2217 "StartPlayingFile() failed to start file playout");
2218 _inputFilePlayerPtr->StopPlayingFile();
2219 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2220 _inputFilePlayerPtr = NULL;
2221 return -1;
2222 }
2223 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002224 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002225
2226 return 0;
2227}
2228
2229int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002230 FileFormats format,
2231 int startPosition,
2232 float volumeScaling,
2233 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002234 const CodecInst* codecInst)
2235{
2236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2237 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2238 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2239 format, volumeScaling, startPosition, stopPosition);
2240
2241 if(stream == NULL)
2242 {
2243 _engineStatisticsPtr->SetLastError(
2244 VE_BAD_FILE, kTraceError,
2245 "StartPlayingFileAsMicrophone NULL as input stream");
2246 return -1;
2247 }
2248
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002249 CriticalSectionScoped cs(&_fileCritSect);
2250
2251 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002252 {
2253 _engineStatisticsPtr->SetLastError(
2254 VE_ALREADY_PLAYING, kTraceWarning,
2255 "StartPlayingFileAsMicrophone() is playing");
2256 return 0;
2257 }
2258
niklase@google.com470e71d2011-07-07 08:21:25 +00002259 // Destroy the old instance
2260 if (_inputFilePlayerPtr)
2261 {
2262 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2263 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2264 _inputFilePlayerPtr = NULL;
2265 }
2266
2267 // Create the instance
2268 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2269 _inputFilePlayerId, (const FileFormats)format);
2270
2271 if (_inputFilePlayerPtr == NULL)
2272 {
2273 _engineStatisticsPtr->SetLastError(
2274 VE_INVALID_ARGUMENT, kTraceError,
2275 "StartPlayingInputFile() filePlayer format isnot correct");
2276 return -1;
2277 }
2278
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002279 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002280
2281 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2282 volumeScaling, notificationTime,
2283 stopPosition, codecInst) != 0)
2284 {
2285 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2286 "StartPlayingFile() failed to start "
2287 "file playout");
2288 _inputFilePlayerPtr->StopPlayingFile();
2289 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2290 _inputFilePlayerPtr = NULL;
2291 return -1;
2292 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002293
niklase@google.com470e71d2011-07-07 08:21:25 +00002294 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002295 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002296
2297 return 0;
2298}
2299
2300int Channel::StopPlayingFileAsMicrophone()
2301{
2302 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2303 "Channel::StopPlayingFileAsMicrophone()");
2304
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002305 CriticalSectionScoped cs(&_fileCritSect);
2306
2307 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002308 {
2309 _engineStatisticsPtr->SetLastError(
2310 VE_INVALID_OPERATION, kTraceWarning,
2311 "StopPlayingFileAsMicrophone() isnot playing");
2312 return 0;
2313 }
2314
niklase@google.com470e71d2011-07-07 08:21:25 +00002315 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2316 {
2317 _engineStatisticsPtr->SetLastError(
2318 VE_STOP_RECORDING_FAILED, kTraceError,
2319 "StopPlayingFile() could not stop playing");
2320 return -1;
2321 }
2322 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2323 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2324 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002325 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002326
2327 return 0;
2328}
2329
2330int Channel::IsPlayingFileAsMicrophone() const
2331{
2332 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2333 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002334 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002335}
2336
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002337int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002338 const CodecInst* codecInst)
2339{
2340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2341 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2342
2343 if (_outputFileRecording)
2344 {
2345 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2346 "StartRecordingPlayout() is already recording");
2347 return 0;
2348 }
2349
2350 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002351 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002352 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2353
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002354 if ((codecInst != NULL) &&
2355 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002356 {
2357 _engineStatisticsPtr->SetLastError(
2358 VE_BAD_ARGUMENT, kTraceError,
2359 "StartRecordingPlayout() invalid compression");
2360 return(-1);
2361 }
2362 if(codecInst == NULL)
2363 {
2364 format = kFileFormatPcm16kHzFile;
2365 codecInst=&dummyCodec;
2366 }
2367 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2368 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2369 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2370 {
2371 format = kFileFormatWavFile;
2372 }
2373 else
2374 {
2375 format = kFileFormatCompressedFile;
2376 }
2377
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002378 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002379
2380 // Destroy the old instance
2381 if (_outputFileRecorderPtr)
2382 {
2383 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2384 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2385 _outputFileRecorderPtr = NULL;
2386 }
2387
2388 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2389 _outputFileRecorderId, (const FileFormats)format);
2390 if (_outputFileRecorderPtr == NULL)
2391 {
2392 _engineStatisticsPtr->SetLastError(
2393 VE_INVALID_ARGUMENT, kTraceError,
2394 "StartRecordingPlayout() fileRecorder format isnot correct");
2395 return -1;
2396 }
2397
2398 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2399 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2400 {
2401 _engineStatisticsPtr->SetLastError(
2402 VE_BAD_FILE, kTraceError,
2403 "StartRecordingAudioFile() failed to start file recording");
2404 _outputFileRecorderPtr->StopRecording();
2405 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2406 _outputFileRecorderPtr = NULL;
2407 return -1;
2408 }
2409 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2410 _outputFileRecording = true;
2411
2412 return 0;
2413}
2414
2415int Channel::StartRecordingPlayout(OutStream* stream,
2416 const CodecInst* codecInst)
2417{
2418 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2419 "Channel::StartRecordingPlayout()");
2420
2421 if (_outputFileRecording)
2422 {
2423 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2424 "StartRecordingPlayout() is already recording");
2425 return 0;
2426 }
2427
2428 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002429 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002430 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2431
2432 if (codecInst != NULL && codecInst->channels != 1)
2433 {
2434 _engineStatisticsPtr->SetLastError(
2435 VE_BAD_ARGUMENT, kTraceError,
2436 "StartRecordingPlayout() invalid compression");
2437 return(-1);
2438 }
2439 if(codecInst == NULL)
2440 {
2441 format = kFileFormatPcm16kHzFile;
2442 codecInst=&dummyCodec;
2443 }
2444 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2445 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2446 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2447 {
2448 format = kFileFormatWavFile;
2449 }
2450 else
2451 {
2452 format = kFileFormatCompressedFile;
2453 }
2454
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002455 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002456
2457 // Destroy the old instance
2458 if (_outputFileRecorderPtr)
2459 {
2460 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2461 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2462 _outputFileRecorderPtr = NULL;
2463 }
2464
2465 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2466 _outputFileRecorderId, (const FileFormats)format);
2467 if (_outputFileRecorderPtr == NULL)
2468 {
2469 _engineStatisticsPtr->SetLastError(
2470 VE_INVALID_ARGUMENT, kTraceError,
2471 "StartRecordingPlayout() fileRecorder format isnot correct");
2472 return -1;
2473 }
2474
2475 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2476 notificationTime) != 0)
2477 {
2478 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2479 "StartRecordingPlayout() failed to "
2480 "start file recording");
2481 _outputFileRecorderPtr->StopRecording();
2482 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2483 _outputFileRecorderPtr = NULL;
2484 return -1;
2485 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002486
niklase@google.com470e71d2011-07-07 08:21:25 +00002487 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2488 _outputFileRecording = true;
2489
2490 return 0;
2491}
2492
2493int Channel::StopRecordingPlayout()
2494{
2495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2496 "Channel::StopRecordingPlayout()");
2497
2498 if (!_outputFileRecording)
2499 {
2500 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2501 "StopRecordingPlayout() isnot recording");
2502 return -1;
2503 }
2504
2505
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002506 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002507
2508 if (_outputFileRecorderPtr->StopRecording() != 0)
2509 {
2510 _engineStatisticsPtr->SetLastError(
2511 VE_STOP_RECORDING_FAILED, kTraceError,
2512 "StopRecording() could not stop recording");
2513 return(-1);
2514 }
2515 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2516 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2517 _outputFileRecorderPtr = NULL;
2518 _outputFileRecording = false;
2519
2520 return 0;
2521}
2522
2523void
2524Channel::SetMixWithMicStatus(bool mix)
2525{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002526 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002527 _mixFileWithMicrophone=mix;
2528}
2529
2530int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002531Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002532{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002533 int8_t currentLevel = _outputAudioLevel.Level();
2534 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002535 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2536 VoEId(_instanceId,_channelId),
2537 "GetSpeechOutputLevel() => level=%u", level);
2538 return 0;
2539}
2540
2541int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002542Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002543{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002544 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2545 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002546 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2547 VoEId(_instanceId,_channelId),
2548 "GetSpeechOutputLevelFullRange() => level=%u", level);
2549 return 0;
2550}
2551
2552int
2553Channel::SetMute(bool enable)
2554{
wu@webrtc.org63420662013-10-17 18:28:55 +00002555 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002556 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2557 "Channel::SetMute(enable=%d)", enable);
2558 _mute = enable;
2559 return 0;
2560}
2561
2562bool
2563Channel::Mute() const
2564{
wu@webrtc.org63420662013-10-17 18:28:55 +00002565 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002566 return _mute;
2567}
2568
2569int
2570Channel::SetOutputVolumePan(float left, float right)
2571{
wu@webrtc.org63420662013-10-17 18:28:55 +00002572 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2574 "Channel::SetOutputVolumePan()");
2575 _panLeft = left;
2576 _panRight = right;
2577 return 0;
2578}
2579
2580int
2581Channel::GetOutputVolumePan(float& left, float& right) const
2582{
wu@webrtc.org63420662013-10-17 18:28:55 +00002583 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002584 left = _panLeft;
2585 right = _panRight;
2586 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2587 VoEId(_instanceId,_channelId),
2588 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2589 return 0;
2590}
2591
2592int
2593Channel::SetChannelOutputVolumeScaling(float scaling)
2594{
wu@webrtc.org63420662013-10-17 18:28:55 +00002595 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2597 "Channel::SetChannelOutputVolumeScaling()");
2598 _outputGain = scaling;
2599 return 0;
2600}
2601
2602int
2603Channel::GetChannelOutputVolumeScaling(float& scaling) const
2604{
wu@webrtc.org63420662013-10-17 18:28:55 +00002605 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002606 scaling = _outputGain;
2607 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2608 VoEId(_instanceId,_channelId),
2609 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2610 return 0;
2611}
2612
niklase@google.com470e71d2011-07-07 08:21:25 +00002613int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002614 int lengthMs, int attenuationDb,
2615 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002616{
2617 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2618 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2619 playDtmfEvent);
2620
2621 _playOutbandDtmfEvent = playDtmfEvent;
2622
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002623 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002624 attenuationDb) != 0)
2625 {
2626 _engineStatisticsPtr->SetLastError(
2627 VE_SEND_DTMF_FAILED,
2628 kTraceWarning,
2629 "SendTelephoneEventOutband() failed to send event");
2630 return -1;
2631 }
2632 return 0;
2633}
2634
2635int Channel::SendTelephoneEventInband(unsigned char eventCode,
2636 int lengthMs,
2637 int attenuationDb,
2638 bool playDtmfEvent)
2639{
2640 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2641 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2642 playDtmfEvent);
2643
2644 _playInbandDtmfEvent = playDtmfEvent;
2645 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2646
2647 return 0;
2648}
2649
2650int
2651Channel::SetDtmfPlayoutStatus(bool enable)
2652{
2653 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2654 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002655 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002656 {
2657 _engineStatisticsPtr->SetLastError(
2658 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2659 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2660 return -1;
2661 }
2662 return 0;
2663}
2664
2665bool
2666Channel::DtmfPlayoutStatus() const
2667{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002668 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002669}
2670
2671int
2672Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2673{
2674 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2675 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002676 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002677 {
2678 _engineStatisticsPtr->SetLastError(
2679 VE_INVALID_ARGUMENT, kTraceError,
2680 "SetSendTelephoneEventPayloadType() invalid type");
2681 return -1;
2682 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002683 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002684 codec.plfreq = 8000;
2685 codec.pltype = type;
2686 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002687 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002688 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002689 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2690 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2691 _engineStatisticsPtr->SetLastError(
2692 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2693 "SetSendTelephoneEventPayloadType() failed to register send"
2694 "payload type");
2695 return -1;
2696 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002697 }
2698 _sendTelephoneEventPayloadType = type;
2699 return 0;
2700}
2701
2702int
2703Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2704{
2705 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2706 "Channel::GetSendTelephoneEventPayloadType()");
2707 type = _sendTelephoneEventPayloadType;
2708 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2709 VoEId(_instanceId,_channelId),
2710 "GetSendTelephoneEventPayloadType() => type=%u", type);
2711 return 0;
2712}
2713
niklase@google.com470e71d2011-07-07 08:21:25 +00002714int
2715Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2716{
2717 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2718 "Channel::UpdateRxVadDetection()");
2719
2720 int vadDecision = 1;
2721
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002722 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002723
2724 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2725 {
2726 OnRxVadDetected(vadDecision);
2727 _oldVadDecision = vadDecision;
2728 }
2729
2730 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2731 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2732 vadDecision);
2733 return 0;
2734}
2735
2736int
2737Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2738{
2739 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2740 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002741 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002742
2743 if (_rxVadObserverPtr)
2744 {
2745 _engineStatisticsPtr->SetLastError(
2746 VE_INVALID_OPERATION, kTraceError,
2747 "RegisterRxVadObserver() observer already enabled");
2748 return -1;
2749 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002750 _rxVadObserverPtr = &observer;
2751 _RxVadDetection = true;
2752 return 0;
2753}
2754
2755int
2756Channel::DeRegisterRxVadObserver()
2757{
2758 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2759 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002760 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002761
2762 if (!_rxVadObserverPtr)
2763 {
2764 _engineStatisticsPtr->SetLastError(
2765 VE_INVALID_OPERATION, kTraceWarning,
2766 "DeRegisterRxVadObserver() observer already disabled");
2767 return 0;
2768 }
2769 _rxVadObserverPtr = NULL;
2770 _RxVadDetection = false;
2771 return 0;
2772}
2773
2774int
2775Channel::VoiceActivityIndicator(int &activity)
2776{
2777 activity = _sendFrameType;
2778
2779 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002780 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002781 return 0;
2782}
2783
2784#ifdef WEBRTC_VOICE_ENGINE_AGC
2785
2786int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002787Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002788{
2789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2790 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2791 (int)enable, (int)mode);
2792
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002793 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002794 switch (mode)
2795 {
2796 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 break;
2798 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002799 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002800 break;
2801 case kAgcFixedDigital:
2802 agcMode = GainControl::kFixedDigital;
2803 break;
2804 case kAgcAdaptiveDigital:
2805 agcMode =GainControl::kAdaptiveDigital;
2806 break;
2807 default:
2808 _engineStatisticsPtr->SetLastError(
2809 VE_INVALID_ARGUMENT, kTraceError,
2810 "SetRxAgcStatus() invalid Agc mode");
2811 return -1;
2812 }
2813
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002814 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002815 {
2816 _engineStatisticsPtr->SetLastError(
2817 VE_APM_ERROR, kTraceError,
2818 "SetRxAgcStatus() failed to set Agc mode");
2819 return -1;
2820 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002821 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002822 {
2823 _engineStatisticsPtr->SetLastError(
2824 VE_APM_ERROR, kTraceError,
2825 "SetRxAgcStatus() failed to set Agc state");
2826 return -1;
2827 }
2828
2829 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002830 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002831
2832 return 0;
2833}
2834
2835int
2836Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2837{
2838 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2839 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2840
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002841 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002842 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002843 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002844
2845 enabled = enable;
2846
2847 switch (agcMode)
2848 {
2849 case GainControl::kFixedDigital:
2850 mode = kAgcFixedDigital;
2851 break;
2852 case GainControl::kAdaptiveDigital:
2853 mode = kAgcAdaptiveDigital;
2854 break;
2855 default:
2856 _engineStatisticsPtr->SetLastError(
2857 VE_APM_ERROR, kTraceError,
2858 "GetRxAgcStatus() invalid Agc mode");
2859 return -1;
2860 }
2861
2862 return 0;
2863}
2864
2865int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002866Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002867{
2868 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2869 "Channel::SetRxAgcConfig()");
2870
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002871 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002872 config.targetLeveldBOv) != 0)
2873 {
2874 _engineStatisticsPtr->SetLastError(
2875 VE_APM_ERROR, kTraceError,
2876 "SetRxAgcConfig() failed to set target peak |level|"
2877 "(or envelope) of the Agc");
2878 return -1;
2879 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002880 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002881 config.digitalCompressionGaindB) != 0)
2882 {
2883 _engineStatisticsPtr->SetLastError(
2884 VE_APM_ERROR, kTraceError,
2885 "SetRxAgcConfig() failed to set the range in |gain| the"
2886 " digital compression stage may apply");
2887 return -1;
2888 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002889 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002890 config.limiterEnable) != 0)
2891 {
2892 _engineStatisticsPtr->SetLastError(
2893 VE_APM_ERROR, kTraceError,
2894 "SetRxAgcConfig() failed to set hard limiter to the signal");
2895 return -1;
2896 }
2897
2898 return 0;
2899}
2900
2901int
2902Channel::GetRxAgcConfig(AgcConfig& config)
2903{
2904 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2905 "Channel::GetRxAgcConfig(config=%?)");
2906
2907 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002908 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002909 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002910 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002911 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002912 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002913
2914 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2915 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2916 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2917 " limiterEnable=%d",
2918 config.targetLeveldBOv,
2919 config.digitalCompressionGaindB,
2920 config.limiterEnable);
2921
2922 return 0;
2923}
2924
2925#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2926
2927#ifdef WEBRTC_VOICE_ENGINE_NR
2928
2929int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002930Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002931{
2932 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2933 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2934 (int)enable, (int)mode);
2935
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002936 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002937 switch (mode)
2938 {
2939
2940 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 break;
2942 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002943 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002944 break;
2945 case kNsConference:
2946 nsLevel = NoiseSuppression::kHigh;
2947 break;
2948 case kNsLowSuppression:
2949 nsLevel = NoiseSuppression::kLow;
2950 break;
2951 case kNsModerateSuppression:
2952 nsLevel = NoiseSuppression::kModerate;
2953 break;
2954 case kNsHighSuppression:
2955 nsLevel = NoiseSuppression::kHigh;
2956 break;
2957 case kNsVeryHighSuppression:
2958 nsLevel = NoiseSuppression::kVeryHigh;
2959 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002960 }
2961
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002962 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002963 != 0)
2964 {
2965 _engineStatisticsPtr->SetLastError(
2966 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002967 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002968 return -1;
2969 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002970 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002971 {
2972 _engineStatisticsPtr->SetLastError(
2973 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002974 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002975 return -1;
2976 }
2977
2978 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002979 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002980
2981 return 0;
2982}
2983
2984int
2985Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2986{
2987 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2988 "Channel::GetRxNsStatus(enable=?, mode=?)");
2989
2990 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002991 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002992 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002993 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002994
2995 enabled = enable;
2996
2997 switch (ncLevel)
2998 {
2999 case NoiseSuppression::kLow:
3000 mode = kNsLowSuppression;
3001 break;
3002 case NoiseSuppression::kModerate:
3003 mode = kNsModerateSuppression;
3004 break;
3005 case NoiseSuppression::kHigh:
3006 mode = kNsHighSuppression;
3007 break;
3008 case NoiseSuppression::kVeryHigh:
3009 mode = kNsVeryHighSuppression;
3010 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003011 }
3012
3013 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3014 VoEId(_instanceId,_channelId),
3015 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3016 return 0;
3017}
3018
3019#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3020
3021int
niklase@google.com470e71d2011-07-07 08:21:25 +00003022Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3023{
3024 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3025 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003026 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003027
3028 if (_rtcpObserverPtr)
3029 {
3030 _engineStatisticsPtr->SetLastError(
3031 VE_INVALID_OPERATION, kTraceError,
3032 "RegisterRTCPObserver() observer already enabled");
3033 return -1;
3034 }
3035
3036 _rtcpObserverPtr = &observer;
3037 _rtcpObserver = true;
3038
3039 return 0;
3040}
3041
3042int
3043Channel::DeRegisterRTCPObserver()
3044{
3045 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3046 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003047 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003048
3049 if (!_rtcpObserverPtr)
3050 {
3051 _engineStatisticsPtr->SetLastError(
3052 VE_INVALID_OPERATION, kTraceWarning,
3053 "DeRegisterRTCPObserver() observer already disabled");
3054 return 0;
3055 }
3056
3057 _rtcpObserver = false;
3058 _rtcpObserverPtr = NULL;
3059
3060 return 0;
3061}
3062
3063int
3064Channel::SetLocalSSRC(unsigned int ssrc)
3065{
3066 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3067 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003068 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003069 {
3070 _engineStatisticsPtr->SetLastError(
3071 VE_ALREADY_SENDING, kTraceError,
3072 "SetLocalSSRC() already sending");
3073 return -1;
3074 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003075 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003076 {
3077 _engineStatisticsPtr->SetLastError(
3078 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3079 "SetLocalSSRC() failed to set SSRC");
3080 return -1;
3081 }
3082 return 0;
3083}
3084
3085int
3086Channel::GetLocalSSRC(unsigned int& ssrc)
3087{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003088 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003089 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3090 VoEId(_instanceId,_channelId),
3091 "GetLocalSSRC() => ssrc=%lu", ssrc);
3092 return 0;
3093}
3094
3095int
3096Channel::GetRemoteSSRC(unsigned int& ssrc)
3097{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003098 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003099 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3100 VoEId(_instanceId,_channelId),
3101 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3102 return 0;
3103}
3104
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003105int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003106 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003107 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003108}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003109
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003110int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3111 unsigned char id) {
3112 rtp_header_parser_->DeregisterRtpHeaderExtension(
3113 kRtpExtensionAudioLevel);
3114 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3115 kRtpExtensionAudioLevel, id)) {
3116 return -1;
3117 }
3118 return 0;
3119}
3120
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003121int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3122 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3123}
3124
3125int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3126 rtp_header_parser_->DeregisterRtpHeaderExtension(
3127 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003128 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3129 kRtpExtensionAbsoluteSendTime, id)) {
3130 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003131 }
3132 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003133}
3134
3135int
3136Channel::SetRTCPStatus(bool enable)
3137{
3138 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3139 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003140 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003141 kRtcpCompound : kRtcpOff) != 0)
3142 {
3143 _engineStatisticsPtr->SetLastError(
3144 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3145 "SetRTCPStatus() failed to set RTCP status");
3146 return -1;
3147 }
3148 return 0;
3149}
3150
3151int
3152Channel::GetRTCPStatus(bool& enabled)
3153{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003154 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003155 enabled = (method != kRtcpOff);
3156 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3157 VoEId(_instanceId,_channelId),
3158 "GetRTCPStatus() => enabled=%d", enabled);
3159 return 0;
3160}
3161
3162int
3163Channel::SetRTCP_CNAME(const char cName[256])
3164{
3165 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3166 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003167 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003168 {
3169 _engineStatisticsPtr->SetLastError(
3170 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3171 "SetRTCP_CNAME() failed to set RTCP CNAME");
3172 return -1;
3173 }
3174 return 0;
3175}
3176
3177int
3178Channel::GetRTCP_CNAME(char cName[256])
3179{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003180 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003181 {
3182 _engineStatisticsPtr->SetLastError(
3183 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3184 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3185 return -1;
3186 }
3187 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3188 VoEId(_instanceId, _channelId),
3189 "GetRTCP_CNAME() => cName=%s", cName);
3190 return 0;
3191}
3192
3193int
3194Channel::GetRemoteRTCP_CNAME(char cName[256])
3195{
3196 if (cName == NULL)
3197 {
3198 _engineStatisticsPtr->SetLastError(
3199 VE_INVALID_ARGUMENT, kTraceError,
3200 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3201 return -1;
3202 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003203 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003204 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003205 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003206 {
3207 _engineStatisticsPtr->SetLastError(
3208 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3209 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3210 return -1;
3211 }
3212 strcpy(cName, cname);
3213 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3214 VoEId(_instanceId, _channelId),
3215 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3216 return 0;
3217}
3218
3219int
3220Channel::GetRemoteRTCPData(
3221 unsigned int& NTPHigh,
3222 unsigned int& NTPLow,
3223 unsigned int& timestamp,
3224 unsigned int& playoutTimestamp,
3225 unsigned int* jitter,
3226 unsigned short* fractionLost)
3227{
3228 // --- Information from sender info in received Sender Reports
3229
3230 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003231 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003232 {
3233 _engineStatisticsPtr->SetLastError(
3234 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003235 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003236 "side");
3237 return -1;
3238 }
3239
3240 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3241 // and octet count)
3242 NTPHigh = senderInfo.NTPseconds;
3243 NTPLow = senderInfo.NTPfraction;
3244 timestamp = senderInfo.RTPtimeStamp;
3245
3246 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3247 VoEId(_instanceId, _channelId),
3248 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3249 "timestamp=%lu",
3250 NTPHigh, NTPLow, timestamp);
3251
3252 // --- Locally derived information
3253
3254 // This value is updated on each incoming RTCP packet (0 when no packet
3255 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003256 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003257
3258 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3259 VoEId(_instanceId, _channelId),
3260 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003261 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003262
3263 if (NULL != jitter || NULL != fractionLost)
3264 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003265 // Get all RTCP receiver report blocks that have been received on this
3266 // channel. If we receive RTP packets from a remote source we know the
3267 // remote SSRC and use the report block from him.
3268 // Otherwise use the first report block.
3269 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003270 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003271 remote_stats.empty()) {
3272 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3273 VoEId(_instanceId, _channelId),
3274 "GetRemoteRTCPData() failed to measure statistics due"
3275 " to lack of received RTP and/or RTCP packets");
3276 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003278
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003279 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003280 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3281 for (; it != remote_stats.end(); ++it) {
3282 if (it->remoteSSRC == remoteSSRC)
3283 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003284 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003285
3286 if (it == remote_stats.end()) {
3287 // If we have not received any RTCP packets from this SSRC it probably
3288 // means that we have not received any RTP packets.
3289 // Use the first received report block instead.
3290 it = remote_stats.begin();
3291 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003292 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003293
xians@webrtc.org79af7342012-01-31 12:22:14 +00003294 if (jitter) {
3295 *jitter = it->jitter;
3296 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3297 VoEId(_instanceId, _channelId),
3298 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3299 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003300
xians@webrtc.org79af7342012-01-31 12:22:14 +00003301 if (fractionLost) {
3302 *fractionLost = it->fractionLost;
3303 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3304 VoEId(_instanceId, _channelId),
3305 "GetRemoteRTCPData() => fractionLost = %lu",
3306 *fractionLost);
3307 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003308 }
3309 return 0;
3310}
3311
3312int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003313Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003314 unsigned int name,
3315 const char* data,
3316 unsigned short dataLengthInBytes)
3317{
3318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3319 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003320 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003321 {
3322 _engineStatisticsPtr->SetLastError(
3323 VE_NOT_SENDING, kTraceError,
3324 "SendApplicationDefinedRTCPPacket() not sending");
3325 return -1;
3326 }
3327 if (NULL == data)
3328 {
3329 _engineStatisticsPtr->SetLastError(
3330 VE_INVALID_ARGUMENT, kTraceError,
3331 "SendApplicationDefinedRTCPPacket() invalid data value");
3332 return -1;
3333 }
3334 if (dataLengthInBytes % 4 != 0)
3335 {
3336 _engineStatisticsPtr->SetLastError(
3337 VE_INVALID_ARGUMENT, kTraceError,
3338 "SendApplicationDefinedRTCPPacket() invalid length value");
3339 return -1;
3340 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003341 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003342 if (status == kRtcpOff)
3343 {
3344 _engineStatisticsPtr->SetLastError(
3345 VE_RTCP_ERROR, kTraceError,
3346 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3347 return -1;
3348 }
3349
3350 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003351 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003352 subType,
3353 name,
3354 (const unsigned char*) data,
3355 dataLengthInBytes) != 0)
3356 {
3357 _engineStatisticsPtr->SetLastError(
3358 VE_SEND_ERROR, kTraceError,
3359 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3360 return -1;
3361 }
3362 return 0;
3363}
3364
3365int
3366Channel::GetRTPStatistics(
3367 unsigned int& averageJitterMs,
3368 unsigned int& maxJitterMs,
3369 unsigned int& discardedPackets)
3370{
niklase@google.com470e71d2011-07-07 08:21:25 +00003371 // The jitter statistics is updated for each received RTP packet and is
3372 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003373 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3374 // If RTCP is off, there is no timed thread in the RTCP module regularly
3375 // generating new stats, trigger the update manually here instead.
3376 StreamStatistician* statistician =
3377 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3378 if (statistician) {
3379 // Don't use returned statistics, use data from proxy instead so that
3380 // max jitter can be fetched atomically.
3381 RtcpStatistics s;
3382 statistician->GetStatistics(&s, true);
3383 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003384 }
3385
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003386 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003387 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003388 if (playoutFrequency > 0) {
3389 // Scale RTP statistics given the current playout frequency
3390 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3391 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003392 }
3393
3394 discardedPackets = _numberOfDiscardedPackets;
3395
3396 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3397 VoEId(_instanceId, _channelId),
3398 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003399 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003400 averageJitterMs, maxJitterMs, discardedPackets);
3401 return 0;
3402}
3403
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003404int Channel::GetRemoteRTCPReportBlocks(
3405 std::vector<ReportBlock>* report_blocks) {
3406 if (report_blocks == NULL) {
3407 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3408 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3409 return -1;
3410 }
3411
3412 // Get the report blocks from the latest received RTCP Sender or Receiver
3413 // Report. Each element in the vector contains the sender's SSRC and a
3414 // report block according to RFC 3550.
3415 std::vector<RTCPReportBlock> rtcp_report_blocks;
3416 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3417 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3418 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3419 return -1;
3420 }
3421
3422 if (rtcp_report_blocks.empty())
3423 return 0;
3424
3425 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3426 for (; it != rtcp_report_blocks.end(); ++it) {
3427 ReportBlock report_block;
3428 report_block.sender_SSRC = it->remoteSSRC;
3429 report_block.source_SSRC = it->sourceSSRC;
3430 report_block.fraction_lost = it->fractionLost;
3431 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3432 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3433 report_block.interarrival_jitter = it->jitter;
3434 report_block.last_SR_timestamp = it->lastSR;
3435 report_block.delay_since_last_SR = it->delaySinceLastSR;
3436 report_blocks->push_back(report_block);
3437 }
3438 return 0;
3439}
3440
niklase@google.com470e71d2011-07-07 08:21:25 +00003441int
3442Channel::GetRTPStatistics(CallStatistics& stats)
3443{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003444 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003445
3446 // The jitter statistics is updated for each received RTP packet and is
3447 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003448 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003449 StreamStatistician* statistician =
3450 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3451 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003452 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3453 _engineStatisticsPtr->SetLastError(
3454 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3455 "GetRTPStatistics() failed to read RTP statistics from the "
3456 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003457 }
3458
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003459 stats.fractionLost = statistics.fraction_lost;
3460 stats.cumulativeLost = statistics.cumulative_lost;
3461 stats.extendedMax = statistics.extended_max_sequence_number;
3462 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003463
3464 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3465 VoEId(_instanceId, _channelId),
3466 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003467 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003468 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3469 stats.jitterSamples);
3470
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003471 // --- RTT
niklase@google.com470e71d2011-07-07 08:21:25 +00003472
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003473 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003474 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003475 if (method == kRtcpOff)
3476 {
3477 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3478 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003479 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003480 "measurements cannot be retrieved");
3481 } else
3482 {
3483 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003484 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003485 if (remoteSSRC > 0)
3486 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003487 uint16_t avgRTT(0);
3488 uint16_t maxRTT(0);
3489 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003490
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003491 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003492 != 0)
3493 {
3494 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3495 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003496 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003497 "the RTP/RTCP module");
3498 }
3499 } else
3500 {
3501 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3502 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003503 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 "RTP packets have been received yet");
3505 }
3506 }
3507
3508 stats.rttMs = static_cast<int> (RTT);
3509
3510 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3511 VoEId(_instanceId, _channelId),
3512 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3513
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003514 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003515
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003516 uint32_t bytesSent(0);
3517 uint32_t packetsSent(0);
3518 uint32_t bytesReceived(0);
3519 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003520
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003521 if (statistician) {
3522 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3523 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003524
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003525 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003526 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003527 {
3528 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3529 VoEId(_instanceId, _channelId),
3530 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003531 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003532 }
3533
3534 stats.bytesSent = bytesSent;
3535 stats.packetsSent = packetsSent;
3536 stats.bytesReceived = bytesReceived;
3537 stats.packetsReceived = packetsReceived;
3538
3539 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3540 VoEId(_instanceId, _channelId),
3541 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003542 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003543 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3544 stats.packetsReceived);
3545
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003546 // --- Timestamps
3547 {
3548 CriticalSectionScoped lock(ts_stats_lock_.get());
3549 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3550 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003551 return 0;
3552}
3553
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003554int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003555 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003556 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003557
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003558 if (enable) {
3559 if (redPayloadtype < 0 || redPayloadtype > 127) {
3560 _engineStatisticsPtr->SetLastError(
3561 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003562 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003563 return -1;
3564 }
3565
3566 if (SetRedPayloadType(redPayloadtype) < 0) {
3567 _engineStatisticsPtr->SetLastError(
3568 VE_CODEC_ERROR, kTraceError,
3569 "SetSecondarySendCodec() Failed to register RED ACM");
3570 return -1;
3571 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003572 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003573
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003574 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003575 _engineStatisticsPtr->SetLastError(
3576 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003577 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003578 return -1;
3579 }
3580 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003581}
3582
3583int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003584Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003585{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003586 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003587 if (enabled)
3588 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003589 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003590 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003591 {
3592 _engineStatisticsPtr->SetLastError(
3593 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003594 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003595 "module");
3596 return -1;
3597 }
3598 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3599 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003600 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003601 enabled, redPayloadtype);
3602 return 0;
3603 }
3604 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3605 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003606 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003607 return 0;
3608}
3609
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003610int Channel::SetCodecFECStatus(bool enable) {
3611 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3612 "Channel::SetCodecFECStatus()");
3613
3614 if (audio_coding_->SetCodecFEC(enable) != 0) {
3615 _engineStatisticsPtr->SetLastError(
3616 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3617 "SetCodecFECStatus() failed to set FEC state");
3618 return -1;
3619 }
3620 return 0;
3621}
3622
3623bool Channel::GetCodecFECStatus() {
3624 bool enabled = audio_coding_->CodecFEC();
3625 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3626 VoEId(_instanceId, _channelId),
3627 "GetCodecFECStatus() => enabled=%d", enabled);
3628 return enabled;
3629}
3630
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003631void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3632 // None of these functions can fail.
3633 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003634 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3635 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003636 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003637 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003638 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003639 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003640}
3641
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003642// Called when we are missing one or more packets.
3643int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003644 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3645}
3646
niklase@google.com470e71d2011-07-07 08:21:25 +00003647int
niklase@google.com470e71d2011-07-07 08:21:25 +00003648Channel::StartRTPDump(const char fileNameUTF8[1024],
3649 RTPDirections direction)
3650{
3651 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3652 "Channel::StartRTPDump()");
3653 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3654 {
3655 _engineStatisticsPtr->SetLastError(
3656 VE_INVALID_ARGUMENT, kTraceError,
3657 "StartRTPDump() invalid RTP direction");
3658 return -1;
3659 }
3660 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3661 &_rtpDumpIn : &_rtpDumpOut;
3662 if (rtpDumpPtr == NULL)
3663 {
3664 assert(false);
3665 return -1;
3666 }
3667 if (rtpDumpPtr->IsActive())
3668 {
3669 rtpDumpPtr->Stop();
3670 }
3671 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3672 {
3673 _engineStatisticsPtr->SetLastError(
3674 VE_BAD_FILE, kTraceError,
3675 "StartRTPDump() failed to create file");
3676 return -1;
3677 }
3678 return 0;
3679}
3680
3681int
3682Channel::StopRTPDump(RTPDirections direction)
3683{
3684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3685 "Channel::StopRTPDump()");
3686 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3687 {
3688 _engineStatisticsPtr->SetLastError(
3689 VE_INVALID_ARGUMENT, kTraceError,
3690 "StopRTPDump() invalid RTP direction");
3691 return -1;
3692 }
3693 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3694 &_rtpDumpIn : &_rtpDumpOut;
3695 if (rtpDumpPtr == NULL)
3696 {
3697 assert(false);
3698 return -1;
3699 }
3700 if (!rtpDumpPtr->IsActive())
3701 {
3702 return 0;
3703 }
3704 return rtpDumpPtr->Stop();
3705}
3706
3707bool
3708Channel::RTPDumpIsActive(RTPDirections direction)
3709{
3710 if ((direction != kRtpIncoming) &&
3711 (direction != kRtpOutgoing))
3712 {
3713 _engineStatisticsPtr->SetLastError(
3714 VE_INVALID_ARGUMENT, kTraceError,
3715 "RTPDumpIsActive() invalid RTP direction");
3716 return false;
3717 }
3718 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3719 &_rtpDumpIn : &_rtpDumpOut;
3720 return rtpDumpPtr->IsActive();
3721}
3722
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003723void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3724 int video_channel) {
3725 CriticalSectionScoped cs(&_callbackCritSect);
3726 if (vie_network_) {
3727 vie_network_->Release();
3728 vie_network_ = NULL;
3729 }
3730 video_channel_ = -1;
3731
3732 if (vie_network != NULL && video_channel != -1) {
3733 vie_network_ = vie_network;
3734 video_channel_ = video_channel;
3735 }
3736}
3737
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003738uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003739Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003740{
3741 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003742 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003743 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003744 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 return 0;
3746}
3747
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003748void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003749 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003750 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003751 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003752 CodecInst codec;
3753 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003754
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003755 if (!mono_recording_audio_.get()) {
3756 // Temporary space for DownConvertToCodecFormat.
3757 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003758 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003759 DownConvertToCodecFormat(audio_data,
3760 number_of_frames,
3761 number_of_channels,
3762 sample_rate,
3763 codec.channels,
3764 codec.plfreq,
3765 mono_recording_audio_.get(),
3766 &input_resampler_,
3767 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003768}
3769
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003770uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003771Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003772{
3773 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3774 "Channel::PrepareEncodeAndSend()");
3775
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003776 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003777 {
3778 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3779 "Channel::PrepareEncodeAndSend() invalid audio frame");
3780 return -1;
3781 }
3782
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003783 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003784 {
3785 MixOrReplaceAudioWithFile(mixingFrequency);
3786 }
3787
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003788 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3789 if (is_muted) {
3790 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003791 }
3792
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003793 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003794 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003795 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003796 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003797 if (_inputExternalMediaCallbackPtr)
3798 {
3799 _inputExternalMediaCallbackPtr->Process(
3800 _channelId,
3801 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003802 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003803 _audioFrame.samples_per_channel_,
3804 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003805 isStereo);
3806 }
3807 }
3808
3809 InsertInbandDtmfTone();
3810
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003811 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003812 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003813 if (is_muted) {
3814 rms_level_.ProcessMuted(length);
3815 } else {
3816 rms_level_.Process(_audioFrame.data_, length);
3817 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003818 }
3819
niklase@google.com470e71d2011-07-07 08:21:25 +00003820 return 0;
3821}
3822
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003823uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003824Channel::EncodeAndSend()
3825{
3826 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3827 "Channel::EncodeAndSend()");
3828
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003829 assert(_audioFrame.num_channels_ <= 2);
3830 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003831 {
3832 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3833 "Channel::EncodeAndSend() invalid audio frame");
3834 return -1;
3835 }
3836
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003837 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003838
3839 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3840
3841 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003842 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003843 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003844 {
3845 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3846 "Channel::EncodeAndSend() ACM encoding failed");
3847 return -1;
3848 }
3849
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003850 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003851
3852 // --- Encode if complete frame is ready
3853
3854 // This call will trigger AudioPacketizationCallback::SendData if encoding
3855 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003856 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003857}
3858
3859int Channel::RegisterExternalMediaProcessing(
3860 ProcessingTypes type,
3861 VoEMediaProcess& processObject)
3862{
3863 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3864 "Channel::RegisterExternalMediaProcessing()");
3865
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003866 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003867
3868 if (kPlaybackPerChannel == type)
3869 {
3870 if (_outputExternalMediaCallbackPtr)
3871 {
3872 _engineStatisticsPtr->SetLastError(
3873 VE_INVALID_OPERATION, kTraceError,
3874 "Channel::RegisterExternalMediaProcessing() "
3875 "output external media already enabled");
3876 return -1;
3877 }
3878 _outputExternalMediaCallbackPtr = &processObject;
3879 _outputExternalMedia = true;
3880 }
3881 else if (kRecordingPerChannel == type)
3882 {
3883 if (_inputExternalMediaCallbackPtr)
3884 {
3885 _engineStatisticsPtr->SetLastError(
3886 VE_INVALID_OPERATION, kTraceError,
3887 "Channel::RegisterExternalMediaProcessing() "
3888 "output external media already enabled");
3889 return -1;
3890 }
3891 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003892 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003893 }
3894 return 0;
3895}
3896
3897int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3898{
3899 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3900 "Channel::DeRegisterExternalMediaProcessing()");
3901
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003902 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003903
3904 if (kPlaybackPerChannel == type)
3905 {
3906 if (!_outputExternalMediaCallbackPtr)
3907 {
3908 _engineStatisticsPtr->SetLastError(
3909 VE_INVALID_OPERATION, kTraceWarning,
3910 "Channel::DeRegisterExternalMediaProcessing() "
3911 "output external media already disabled");
3912 return 0;
3913 }
3914 _outputExternalMedia = false;
3915 _outputExternalMediaCallbackPtr = NULL;
3916 }
3917 else if (kRecordingPerChannel == type)
3918 {
3919 if (!_inputExternalMediaCallbackPtr)
3920 {
3921 _engineStatisticsPtr->SetLastError(
3922 VE_INVALID_OPERATION, kTraceWarning,
3923 "Channel::DeRegisterExternalMediaProcessing() "
3924 "input external media already disabled");
3925 return 0;
3926 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003927 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003928 _inputExternalMediaCallbackPtr = NULL;
3929 }
3930
3931 return 0;
3932}
3933
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003934int Channel::SetExternalMixing(bool enabled) {
3935 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3936 "Channel::SetExternalMixing(enabled=%d)", enabled);
3937
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003938 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003939 {
3940 _engineStatisticsPtr->SetLastError(
3941 VE_INVALID_OPERATION, kTraceError,
3942 "Channel::SetExternalMixing() "
3943 "external mixing cannot be changed while playing.");
3944 return -1;
3945 }
3946
3947 _externalMixing = enabled;
3948
3949 return 0;
3950}
3951
niklase@google.com470e71d2011-07-07 08:21:25 +00003952int
niklase@google.com470e71d2011-07-07 08:21:25 +00003953Channel::GetNetworkStatistics(NetworkStatistics& stats)
3954{
3955 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3956 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003957 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003958 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003959 if (return_value >= 0) {
3960 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3961 }
3962 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003963}
3964
wu@webrtc.org24301a62013-12-13 19:17:43 +00003965void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3966 audio_coding_->GetDecodingCallStatistics(stats);
3967}
3968
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003969bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3970 int* playout_buffer_delay_ms) const {
3971 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003972 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003973 "Channel::GetDelayEstimate() no valid estimate.");
3974 return false;
3975 }
3976 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3977 _recPacketDelayMs;
3978 *playout_buffer_delay_ms = playout_delay_ms_;
3979 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3980 "Channel::GetDelayEstimate()");
3981 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003982}
3983
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003984int Channel::SetInitialPlayoutDelay(int delay_ms)
3985{
3986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3987 "Channel::SetInitialPlayoutDelay()");
3988 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3989 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3990 {
3991 _engineStatisticsPtr->SetLastError(
3992 VE_INVALID_ARGUMENT, kTraceError,
3993 "SetInitialPlayoutDelay() invalid min delay");
3994 return -1;
3995 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003996 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003997 {
3998 _engineStatisticsPtr->SetLastError(
3999 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4000 "SetInitialPlayoutDelay() failed to set min playout delay");
4001 return -1;
4002 }
4003 return 0;
4004}
4005
4006
niklase@google.com470e71d2011-07-07 08:21:25 +00004007int
4008Channel::SetMinimumPlayoutDelay(int delayMs)
4009{
4010 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4011 "Channel::SetMinimumPlayoutDelay()");
4012 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4013 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4014 {
4015 _engineStatisticsPtr->SetLastError(
4016 VE_INVALID_ARGUMENT, kTraceError,
4017 "SetMinimumPlayoutDelay() invalid min delay");
4018 return -1;
4019 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004020 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004021 {
4022 _engineStatisticsPtr->SetLastError(
4023 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4024 "SetMinimumPlayoutDelay() failed to set min playout delay");
4025 return -1;
4026 }
4027 return 0;
4028}
4029
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004030void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4031 uint32_t playout_timestamp = 0;
4032
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004033 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004034 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4035 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4036 " timestamp from the ACM");
4037 _engineStatisticsPtr->SetLastError(
4038 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4039 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4040 return;
4041 }
4042
4043 uint16_t delay_ms = 0;
4044 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4045 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4046 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4047 " delay from the ADM");
4048 _engineStatisticsPtr->SetLastError(
4049 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4050 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4051 return;
4052 }
4053
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004054 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004055 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004056 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004057 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4058 playout_frequency = 8000;
4059 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4060 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004061 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004062 }
4063
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004064 jitter_buffer_playout_timestamp_ = playout_timestamp;
4065
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004066 // Remove the playout delay.
4067 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4068
4069 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4070 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4071 playout_timestamp);
4072
4073 if (rtcp) {
4074 playout_timestamp_rtcp_ = playout_timestamp;
4075 } else {
4076 playout_timestamp_rtp_ = playout_timestamp;
4077 }
4078 playout_delay_ms_ = delay_ms;
4079}
4080
4081int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4082 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4083 "Channel::GetPlayoutTimestamp()");
4084 if (playout_timestamp_rtp_ == 0) {
4085 _engineStatisticsPtr->SetLastError(
4086 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4087 "GetPlayoutTimestamp() failed to retrieve timestamp");
4088 return -1;
4089 }
4090 timestamp = playout_timestamp_rtp_;
4091 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4092 VoEId(_instanceId,_channelId),
4093 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4094 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004095}
4096
4097int
4098Channel::SetInitTimestamp(unsigned int timestamp)
4099{
4100 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4101 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004102 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004103 {
4104 _engineStatisticsPtr->SetLastError(
4105 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4106 return -1;
4107 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004108 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004109 {
4110 _engineStatisticsPtr->SetLastError(
4111 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4112 "SetInitTimestamp() failed to set timestamp");
4113 return -1;
4114 }
4115 return 0;
4116}
4117
4118int
4119Channel::SetInitSequenceNumber(short sequenceNumber)
4120{
4121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4122 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004123 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004124 {
4125 _engineStatisticsPtr->SetLastError(
4126 VE_SENDING, kTraceError,
4127 "SetInitSequenceNumber() already sending");
4128 return -1;
4129 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004130 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004131 {
4132 _engineStatisticsPtr->SetLastError(
4133 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4134 "SetInitSequenceNumber() failed to set sequence number");
4135 return -1;
4136 }
4137 return 0;
4138}
4139
4140int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004141Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004142{
4143 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4144 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004145 *rtpRtcpModule = _rtpRtcpModule.get();
4146 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004147 return 0;
4148}
4149
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004150// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4151// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004152int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004153Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004154{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004155 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004156 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004157
4158 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004159 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004160
4161 if (_inputFilePlayerPtr == NULL)
4162 {
4163 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4164 VoEId(_instanceId, _channelId),
4165 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4166 " doesnt exist");
4167 return -1;
4168 }
4169
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004170 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004171 fileSamples,
4172 mixingFrequency) == -1)
4173 {
4174 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4175 VoEId(_instanceId, _channelId),
4176 "Channel::MixOrReplaceAudioWithFile() file mixing "
4177 "failed");
4178 return -1;
4179 }
4180 if (fileSamples == 0)
4181 {
4182 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4183 VoEId(_instanceId, _channelId),
4184 "Channel::MixOrReplaceAudioWithFile() file is ended");
4185 return 0;
4186 }
4187 }
4188
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004189 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004190
4191 if (_mixFileWithMicrophone)
4192 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004193 // Currently file stream is always mono.
4194 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004195 MixWithSat(_audioFrame.data_,
4196 _audioFrame.num_channels_,
4197 fileBuffer.get(),
4198 1,
4199 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004200 }
4201 else
4202 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004203 // Replace ACM audio with file.
4204 // Currently file stream is always mono.
4205 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004206 _audioFrame.UpdateFrame(_channelId,
4207 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004208 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004209 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004210 mixingFrequency,
4211 AudioFrame::kNormalSpeech,
4212 AudioFrame::kVadUnknown,
4213 1);
4214
4215 }
4216 return 0;
4217}
4218
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004219int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004220Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004221 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004222{
4223 assert(mixingFrequency <= 32000);
4224
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004225 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004226 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004227
4228 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004229 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004230
4231 if (_outputFilePlayerPtr == NULL)
4232 {
4233 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4234 VoEId(_instanceId, _channelId),
4235 "Channel::MixAudioWithFile() file mixing failed");
4236 return -1;
4237 }
4238
4239 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004240 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004241 fileSamples,
4242 mixingFrequency) == -1)
4243 {
4244 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4245 VoEId(_instanceId, _channelId),
4246 "Channel::MixAudioWithFile() file mixing failed");
4247 return -1;
4248 }
4249 }
4250
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004251 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004252 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004253 // Currently file stream is always mono.
4254 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004255 MixWithSat(audioFrame.data_,
4256 audioFrame.num_channels_,
4257 fileBuffer.get(),
4258 1,
4259 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004260 }
4261 else
4262 {
4263 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004264 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004265 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004266 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004267 return -1;
4268 }
4269
4270 return 0;
4271}
4272
4273int
4274Channel::InsertInbandDtmfTone()
4275{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004276 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004277 if (_inbandDtmfQueue.PendingDtmf() &&
4278 !_inbandDtmfGenerator.IsAddingTone() &&
4279 _inbandDtmfGenerator.DelaySinceLastTone() >
4280 kMinTelephoneEventSeparationMs)
4281 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004282 int8_t eventCode(0);
4283 uint16_t lengthMs(0);
4284 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004285
4286 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4287 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4288 if (_playInbandDtmfEvent)
4289 {
4290 // Add tone to output mixer using a reduced length to minimize
4291 // risk of echo.
4292 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4293 attenuationDb);
4294 }
4295 }
4296
4297 if (_inbandDtmfGenerator.IsAddingTone())
4298 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004299 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004300 _inbandDtmfGenerator.GetSampleRate(frequency);
4301
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004302 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004303 {
4304 // Update sample rate of Dtmf tone since the mixing frequency
4305 // has changed.
4306 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004307 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004308 // Reset the tone to be added taking the new sample rate into
4309 // account.
4310 _inbandDtmfGenerator.ResetTone();
4311 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004313 int16_t toneBuffer[320];
4314 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004315 // Get 10ms tone segment and set time since last tone to zero
4316 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4317 {
4318 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4319 VoEId(_instanceId, _channelId),
4320 "Channel::EncodeAndSend() inserting Dtmf failed");
4321 return -1;
4322 }
4323
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004324 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004325 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004326 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004327 sample++)
4328 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004329 for (int channel = 0;
4330 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004331 channel++)
4332 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004333 const int index = sample * _audioFrame.num_channels_ + channel;
4334 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004335 }
4336 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004337
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004338 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004339 } else
4340 {
4341 // Add 10ms to "delay-since-last-tone" counter
4342 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4343 }
4344 return 0;
4345}
4346
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004347int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004348Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4349{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004350 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004351 if (_transportPtr == NULL)
4352 {
4353 return -1;
4354 }
4355 if (!RTCP)
4356 {
4357 return _transportPtr->SendPacket(_channelId, data, len);
4358 }
4359 else
4360 {
4361 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4362 }
4363}
4364
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004365// Called for incoming RTP packets after successful RTP header parsing.
4366void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4367 uint16_t sequence_number) {
4368 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4369 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4370 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004371
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004372 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004373 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004374
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004375 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004376 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004377 return;
4378 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004379
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004380 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004381 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004382
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004383 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4384 // Even though the actual sampling rate for G.722 audio is
4385 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4386 // 8,000 Hz because that value was erroneously assigned in
4387 // RFC 1890 and must remain unchanged for backward compatibility.
4388 rtp_receive_frequency = 8000;
4389 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4390 // We are resampling Opus internally to 32,000 Hz until all our
4391 // DSP routines can operate at 48,000 Hz, but the RTP clock
4392 // rate for the Opus payload format is standardized to 48,000 Hz,
4393 // because that is the maximum supported decoding sampling rate.
4394 rtp_receive_frequency = 48000;
4395 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004396
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004397 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4398 // every incoming packet.
4399 uint32_t timestamp_diff_ms = (rtp_timestamp -
4400 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004401 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4402 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4403 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4404 // timestamp, the resulting difference is negative, but is set to zero.
4405 // This can happen when a network glitch causes a packet to arrive late,
4406 // and during long comfort noise periods with clock drift.
4407 timestamp_diff_ms = 0;
4408 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004409
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004410 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4411 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004412
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004413 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004414
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004415 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004416
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004417 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4418 _recPacketDelayMs = packet_delay_ms;
4419 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004420
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004421 if (_average_jitter_buffer_delay_us == 0) {
4422 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4423 return;
4424 }
4425
4426 // Filter average delay value using exponential filter (alpha is
4427 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4428 // risk of rounding error) and compensate for it in GetDelayEstimate()
4429 // later.
4430 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4431 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004432}
4433
4434void
4435Channel::RegisterReceiveCodecsToRTPModule()
4436{
4437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4438 "Channel::RegisterReceiveCodecsToRTPModule()");
4439
4440
4441 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004442 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004443
4444 for (int idx = 0; idx < nSupportedCodecs; idx++)
4445 {
4446 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004447 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004448 (rtp_receiver_->RegisterReceivePayload(
4449 codec.plname,
4450 codec.pltype,
4451 codec.plfreq,
4452 codec.channels,
4453 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004454 {
4455 WEBRTC_TRACE(
4456 kTraceWarning,
4457 kTraceVoice,
4458 VoEId(_instanceId, _channelId),
4459 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4460 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4461 codec.plname, codec.pltype, codec.plfreq,
4462 codec.channels, codec.rate);
4463 }
4464 else
4465 {
4466 WEBRTC_TRACE(
4467 kTraceInfo,
4468 kTraceVoice,
4469 VoEId(_instanceId, _channelId),
4470 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004471 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004472 "receiver",
4473 codec.plname, codec.pltype, codec.plfreq,
4474 codec.channels, codec.rate);
4475 }
4476 }
4477}
4478
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004479int Channel::SetSecondarySendCodec(const CodecInst& codec,
4480 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004481 // Sanity check for payload type.
4482 if (red_payload_type < 0 || red_payload_type > 127) {
4483 _engineStatisticsPtr->SetLastError(
4484 VE_PLTYPE_ERROR, kTraceError,
4485 "SetRedPayloadType() invalid RED payload type");
4486 return -1;
4487 }
4488
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004489 if (SetRedPayloadType(red_payload_type) < 0) {
4490 _engineStatisticsPtr->SetLastError(
4491 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4492 "SetSecondarySendCodec() Failed to register RED ACM");
4493 return -1;
4494 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004495 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004496 _engineStatisticsPtr->SetLastError(
4497 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4498 "SetSecondarySendCodec() Failed to register secondary send codec in "
4499 "ACM");
4500 return -1;
4501 }
4502
4503 return 0;
4504}
4505
4506void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004507 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004508}
4509
4510int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004511 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004512 _engineStatisticsPtr->SetLastError(
4513 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4514 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4515 return -1;
4516 }
4517 return 0;
4518}
4519
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004520// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004521int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004522 CodecInst codec;
4523 bool found_red = false;
4524
4525 // Get default RED settings from the ACM database
4526 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4527 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004528 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004529 if (!STR_CASE_CMP(codec.plname, "RED")) {
4530 found_red = true;
4531 break;
4532 }
4533 }
4534
4535 if (!found_red) {
4536 _engineStatisticsPtr->SetLastError(
4537 VE_CODEC_ERROR, kTraceError,
4538 "SetRedPayloadType() RED is not supported");
4539 return -1;
4540 }
4541
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004542 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004543 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004544 _engineStatisticsPtr->SetLastError(
4545 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4546 "SetRedPayloadType() RED registration in ACM module failed");
4547 return -1;
4548 }
4549
4550 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4551 _engineStatisticsPtr->SetLastError(
4552 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4553 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4554 return -1;
4555 }
4556 return 0;
4557}
4558
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004559int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4560 unsigned char id) {
4561 int error = 0;
4562 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4563 if (enable) {
4564 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4565 }
4566 return error;
4567}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004568
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004569} // namespace voe
4570} // namespace webrtc