blob: c52fd98419ff6131135d18483b2d9fb17d5fa3e1 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
wu@webrtc.org94454b72014-06-05 20:34:08 +000013#include "webrtc/base/timeutils.h"
minyue@webrtc.orge509f942013-09-12 17:03:00 +000014#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000015#include "webrtc/modules/audio_device/include/audio_device.h"
16#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000017#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000018#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
19#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
21#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000022#include "webrtc/modules/utility/interface/audio_frame_operations.h"
23#include "webrtc/modules/utility/interface/process_thread.h"
24#include "webrtc/modules/utility/interface/rtp_dump.h"
25#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
26#include "webrtc/system_wrappers/interface/logging.h"
27#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000028#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000029#include "webrtc/voice_engine/include/voe_base.h"
30#include "webrtc/voice_engine/include/voe_external_media.h"
31#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
32#include "webrtc/voice_engine/output_mixer.h"
33#include "webrtc/voice_engine/statistics.h"
34#include "webrtc/voice_engine/transmit_mixer.h"
35#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37#if defined(_WIN32)
38#include <Qos.h>
39#endif
40
andrew@webrtc.org50419b02012-11-14 19:07:54 +000041namespace webrtc {
42namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000043
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000044// Extend the default RTCP statistics struct with max_jitter, defined as the
45// maximum jitter value seen in an RTCP report block.
46struct ChannelStatistics : public RtcpStatistics {
47 ChannelStatistics() : rtcp(), max_jitter(0) {}
48
49 RtcpStatistics rtcp;
50 uint32_t max_jitter;
51};
52
53// Statistics callback, called at each generation of a new RTCP report block.
54class StatisticsProxy : public RtcpStatisticsCallback {
55 public:
56 StatisticsProxy(uint32_t ssrc)
57 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
58 ssrc_(ssrc) {}
59 virtual ~StatisticsProxy() {}
60
61 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
62 uint32_t ssrc) OVERRIDE {
63 if (ssrc != ssrc_)
64 return;
65
66 CriticalSectionScoped cs(stats_lock_.get());
67 stats_.rtcp = statistics;
68 if (statistics.jitter > stats_.max_jitter) {
69 stats_.max_jitter = statistics.jitter;
70 }
71 }
72
73 void ResetStatistics() {
74 CriticalSectionScoped cs(stats_lock_.get());
75 stats_ = ChannelStatistics();
76 }
77
78 ChannelStatistics GetStats() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 return stats_;
81 }
82
83 private:
84 // StatisticsUpdated calls are triggered from threads in the RTP module,
85 // while GetStats calls can be triggered from the public voice engine API,
86 // hence synchronization is needed.
87 scoped_ptr<CriticalSectionWrapper> stats_lock_;
88 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000092class VoEBitrateObserver : public BitrateObserver {
93 public:
94 explicit VoEBitrateObserver(Channel* owner)
95 : owner_(owner) {}
96 virtual ~VoEBitrateObserver() {}
97
98 // Implements BitrateObserver.
99 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
100 const uint8_t fraction_lost,
101 const uint32_t rtt) OVERRIDE {
102 // |fraction_lost| has a scale of 0 - 255.
103 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
104 }
105
106 private:
107 Channel* owner_;
108};
109
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000110int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000111Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000112 uint8_t payloadType,
113 uint32_t timeStamp,
114 const uint8_t* payloadData,
115 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 const RTPFragmentationHeader* fragmentation)
117{
118 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
119 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
120 " payloadSize=%u, fragmentation=0x%x)",
121 frameType, payloadType, timeStamp, payloadSize, fragmentation);
122
123 if (_includeAudioLevelIndication)
124 {
125 // Store current audio level in the RTP/RTCP module.
126 // The level will be used in combination with voice-activity state
127 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000128 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 }
130
131 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
132 // packetization.
133 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000134 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000135 payloadType,
136 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000137 // Leaving the time when this frame was
138 // received from the capture device as
139 // undefined for voice for now.
140 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 payloadData,
142 payloadSize,
143 fragmentation) == -1)
144 {
145 _engineStatisticsPtr->SetLastError(
146 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
147 "Channel::SendData() failed to send data to RTP/RTCP module");
148 return -1;
149 }
150
151 _lastLocalTimeStamp = timeStamp;
152 _lastPayloadType = payloadType;
153
154 return 0;
155}
156
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000157int32_t
158Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000159{
160 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
161 "Channel::InFrameType(frameType=%d)", frameType);
162
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000163 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 // 1 indicates speech
165 _sendFrameType = (frameType == 1) ? 1 : 0;
166 return 0;
167}
168
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000169int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000170Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000171{
172 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
173 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
174
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000175 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 if (_rxVadObserverPtr)
177 {
178 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
179 }
180
181 return 0;
182}
183
184int
185Channel::SendPacket(int channel, const void *data, int len)
186{
187 channel = VoEChannelId(channel);
188 assert(channel == _channelId);
189
190 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
191 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
192
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000193 CriticalSectionScoped cs(&_callbackCritSect);
194
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 if (_transportPtr == NULL)
196 {
197 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
198 "Channel::SendPacket() failed to send RTP packet due to"
199 " invalid transport object");
200 return -1;
201 }
202
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000203 uint8_t* bufferToSendPtr = (uint8_t*)data;
204 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205
206 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000207 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000208 {
209 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
210 VoEId(_instanceId,_channelId),
211 "Channel::SendPacket() RTP dump to output file failed");
212 }
213
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000214 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
215 bufferLength);
216 if (n < 0) {
217 std::string transport_name =
218 _externalTransport ? "external transport" : "WebRtc sockets";
219 WEBRTC_TRACE(kTraceError, kTraceVoice,
220 VoEId(_instanceId,_channelId),
221 "Channel::SendPacket() RTP transmission using %s failed",
222 transport_name.c_str());
223 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000225 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226}
227
228int
229Channel::SendRTCPPacket(int channel, const void *data, int len)
230{
231 channel = VoEChannelId(channel);
232 assert(channel == _channelId);
233
234 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
235 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
236
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000237 CriticalSectionScoped cs(&_callbackCritSect);
238 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000240 WEBRTC_TRACE(kTraceError, kTraceVoice,
241 VoEId(_instanceId,_channelId),
242 "Channel::SendRTCPPacket() failed to send RTCP packet"
243 " due to invalid transport object");
244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000245 }
246
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000247 uint8_t* bufferToSendPtr = (uint8_t*)data;
248 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
250 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000251 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000252 {
253 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
254 VoEId(_instanceId,_channelId),
255 "Channel::SendPacket() RTCP dump to output file failed");
256 }
257
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000258 int n = _transportPtr->SendRTCPPacket(channel,
259 bufferToSendPtr,
260 bufferLength);
261 if (n < 0) {
262 std::string transport_name =
263 _externalTransport ? "external transport" : "WebRtc sockets";
264 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
265 VoEId(_instanceId,_channelId),
266 "Channel::SendRTCPPacket() transmission using %s failed",
267 transport_name.c_str());
268 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000269 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000270 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271}
272
273void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000274Channel::OnPlayTelephoneEvent(int32_t id,
275 uint8_t event,
276 uint16_t lengthMs,
277 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000278{
279 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
280 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000281 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
283 if (!_playOutbandDtmfEvent || (event > 15))
284 {
285 // Ignore callback since feedback is disabled or event is not a
286 // Dtmf tone event.
287 return;
288 }
289
290 assert(_outputMixerPtr != NULL);
291
292 // Start playing out the Dtmf tone (if playout is enabled).
293 // Reduce length of tone with 80ms to the reduce risk of echo.
294 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
295}
296
297void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000298Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000299{
300 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
301 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000302 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000303
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000304 // Update ssrc so that NTP for AV sync can be updated.
305 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000306}
307
pbos@webrtc.org92135212013-05-14 08:31:39 +0000308void Channel::OnIncomingCSRCChanged(int32_t id,
309 uint32_t CSRC,
310 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000311{
312 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
313 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
314 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000315}
316
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000317void Channel::ResetStatistics(uint32_t ssrc) {
318 StreamStatistician* statistician =
319 rtp_receive_statistics_->GetStatistician(ssrc);
320 if (statistician) {
321 statistician->ResetStatistics();
322 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000323 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000324}
325
niklase@google.com470e71d2011-07-07 08:21:25 +0000326void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000327Channel::OnApplicationDataReceived(int32_t id,
328 uint8_t subType,
329 uint32_t name,
330 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000331 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000332{
333 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
334 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
335 " name=%u, length=%u)",
336 id, subType, name, length);
337
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000338 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000339 assert(channel == _channelId);
340
341 if (_rtcpObserver)
342 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000343 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 if (_rtcpObserverPtr)
346 {
347 _rtcpObserverPtr->OnApplicationDataReceived(channel,
348 subType,
349 name,
350 data,
351 length);
352 }
353 }
354}
355
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000356int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000357Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000358 int32_t id,
359 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000360 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000361 int frequency,
362 uint8_t channels,
363 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000364{
365 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
366 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
367 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
368 id, payloadType, payloadName, frequency, channels, rate);
369
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000370 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000371
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000372 CodecInst receiveCodec = {0};
373 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000374
375 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000376 receiveCodec.plfreq = frequency;
377 receiveCodec.channels = channels;
378 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000379 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000380
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000381 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 receiveCodec.pacsize = dummyCodec.pacsize;
383
384 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000385 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 {
387 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000388 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 "Channel::OnInitializeDecoder() invalid codec ("
390 "pt=%d, name=%s) received - 1", payloadType, payloadName);
391 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
392 return -1;
393 }
394
395 return 0;
396}
397
398void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000399Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000400{
401 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
402 "Channel::OnPacketTimeout(id=%d)", id);
403
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000404 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 if (_voiceEngineObserverPtr)
406 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000407 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000409 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 assert(channel == _channelId);
411 // Ensure that next OnReceivedPacket() callback will trigger
412 // a VE_PACKET_RECEIPT_RESTARTED callback.
413 _rtpPacketTimedOut = true;
414 // Deliver callback to the observer
415 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
416 VoEId(_instanceId,_channelId),
417 "Channel::OnPacketTimeout() => "
418 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
419 _voiceEngineObserverPtr->CallbackOnError(channel,
420 VE_RECEIVE_PACKET_TIMEOUT);
421 }
422 }
423}
424
425void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000426Channel::OnReceivedPacket(int32_t id,
427 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000428{
429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
430 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
431 id, packetType);
432
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000433 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000434
435 // Notify only for the case when we have restarted an RTP session.
436 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
437 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000438 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 if (_voiceEngineObserverPtr)
440 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000441 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000442 assert(channel == _channelId);
443 // Reset timeout mechanism
444 _rtpPacketTimedOut = false;
445 // Deliver callback to the observer
446 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
447 VoEId(_instanceId,_channelId),
448 "Channel::OnPacketTimeout() =>"
449 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
450 _voiceEngineObserverPtr->CallbackOnError(
451 channel,
452 VE_PACKET_RECEIPT_RESTARTED);
453 }
454 }
455}
456
457void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000458Channel::OnPeriodicDeadOrAlive(int32_t id,
459 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000460{
461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
462 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
463
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000464 {
465 CriticalSectionScoped cs(&_callbackCritSect);
466 if (!_connectionObserver)
467 return;
468 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000469
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000470 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 assert(channel == _channelId);
472
473 // Use Alive as default to limit risk of false Dead detections
474 bool isAlive(true);
475
476 // Always mark the connection as Dead when the module reports kRtpDead
477 if (kRtpDead == alive)
478 {
479 isAlive = false;
480 }
481
482 // It is possible that the connection is alive even if no RTP packet has
483 // been received for a long time since the other side might use VAD/DTX
484 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000485 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 {
487 // Detect Alive for all NetEQ states except for the case when we are
488 // in PLC_CNG state.
489 // PLC_CNG <=> background noise only due to long expand or error.
490 // Note that, the case where the other side stops sending during CNG
491 // state will be detected as Alive. Dead is is not set until after
492 // missing RTCP packets for at least twelve seconds (handled
493 // internally by the RTP/RTCP module).
494 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
495 }
496
niklase@google.com470e71d2011-07-07 08:21:25 +0000497 // Send callback to the registered observer
498 if (_connectionObserver)
499 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000500 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 if (_connectionObserverPtr)
502 {
503 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
504 }
505 }
506}
507
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000508int32_t
509Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000510 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 const WebRtcRTPHeader* rtpHeader)
512{
513 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
514 "Channel::OnReceivedPayloadData(payloadSize=%d,"
515 " payloadType=%u, audioChannel=%u)",
516 payloadSize,
517 rtpHeader->header.payloadType,
518 rtpHeader->type.Audio.channel);
519
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000520 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 {
522 // Avoid inserting into NetEQ when we are not playing. Count the
523 // packet as discarded.
524 WEBRTC_TRACE(kTraceStream, kTraceVoice,
525 VoEId(_instanceId, _channelId),
526 "received packet is discarded since playing is not"
527 " activated");
528 _numberOfDiscardedPackets++;
529 return 0;
530 }
531
532 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000533 if (audio_coding_->IncomingPacket(payloadData,
534 payloadSize,
535 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000536 {
537 _engineStatisticsPtr->SetLastError(
538 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
539 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
540 return -1;
541 }
542
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000543 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 UpdatePacketDelay(rtpHeader->header.timestamp,
545 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000546
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000547 uint16_t round_trip_time = 0;
548 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
549 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000550
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000551 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000552 round_trip_time);
553 if (!nack_list.empty()) {
554 // Can't use nack_list.data() since it's not supported by all
555 // compilers.
556 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558 return 0;
559}
560
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000561bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
562 int rtp_packet_length) {
563 RTPHeader header;
564 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
565 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
566 "IncomingPacket invalid RTP header");
567 return false;
568 }
569 header.payload_type_frequency =
570 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
571 if (header.payload_type_frequency < 0)
572 return false;
573 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
574}
575
pbos@webrtc.org92135212013-05-14 08:31:39 +0000576int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000577{
578 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
579 "Channel::GetAudioFrame(id=%d)", id);
580
581 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000582 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
583 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 {
585 WEBRTC_TRACE(kTraceError, kTraceVoice,
586 VoEId(_instanceId,_channelId),
587 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000588 // In all likelihood, the audio in this frame is garbage. We return an
589 // error so that the audio mixer module doesn't add it to the mix. As
590 // a result, it won't be played out and the actions skipped here are
591 // irrelevant.
592 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 }
594
595 if (_RxVadDetection)
596 {
597 UpdateRxVadDetection(audioFrame);
598 }
599
600 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000601 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000603 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000604
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000605 ChannelState::State state = channel_state_.Get();
606
607 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000608 int err = rx_audioproc_->ProcessStream(&audioFrame);
609 if (err) {
610 LOG(LS_ERROR) << "ProcessStream() error: " << err;
611 assert(false);
612 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 }
614
wu@webrtc.org63420662013-10-17 18:28:55 +0000615 float output_gain = 1.0f;
616 float left_pan = 1.0f;
617 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000619 CriticalSectionScoped cs(&volume_settings_critsect_);
620 output_gain = _outputGain;
621 left_pan = _panLeft;
622 right_pan= _panRight;
623 }
624
625 // Output volume scaling
626 if (output_gain < 0.99f || output_gain > 1.01f)
627 {
628 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 }
630
631 // Scale left and/or right channel(s) if stereo and master balance is
632 // active
633
wu@webrtc.org63420662013-10-17 18:28:55 +0000634 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000636 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 {
638 // Emulate stereo mode since panning is active.
639 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000640 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 }
642 // For true stereo mode (when we are receiving a stereo signal), no
643 // action is needed.
644
645 // Do the panning operation (the audio frame contains stereo at this
646 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000647 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000648 }
649
650 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000651 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000653 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 }
655
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 // External media
657 if (_outputExternalMedia)
658 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000659 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000660 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 if (_outputExternalMediaCallbackPtr)
662 {
663 _outputExternalMediaCallbackPtr->Process(
664 _channelId,
665 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000666 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000667 audioFrame.samples_per_channel_,
668 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 isStereo);
670 }
671 }
672
673 // Record playout if enabled
674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000675 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000676
677 if (_outputFileRecording && _outputFileRecorderPtr)
678 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000679 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000680 }
681 }
682
683 // Measure audio level (0-9)
684 _outputAudioLevel.ComputeLevel(audioFrame);
685
wu@webrtc.org94454b72014-06-05 20:34:08 +0000686 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
687 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000688 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000689 }
690
691 if (capture_start_rtp_time_stamp_ >= 0) {
692 // audioFrame.timestamp_ should be valid from now on.
693
694 // Compute elapsed time.
695 int64_t unwrap_timestamp =
696 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
697 audioFrame.elapsed_time_ms_ =
698 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
699 (GetPlayoutFrequency() / 1000);
700
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000701 {
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000702 CriticalSectionScoped lock(ts_stats_lock_.get());
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000703 // Compute ntp time.
704 audioFrame.ntp_time_ms_ = ntp_estimator_.Estimate(
705 audioFrame.timestamp_);
706 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
707 if (audioFrame.ntp_time_ms_ > 0) {
708 // Compute |capture_start_ntp_time_ms_| so that
709 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
710 capture_start_ntp_time_ms_ =
711 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
712 }
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000713 }
714 }
715
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 return 0;
717}
718
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000719int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000720Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000721{
722 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
723 "Channel::NeededFrequency(id=%d)", id);
724
725 int highestNeeded = 0;
726
727 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000728 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000729
730 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000731 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000733 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 }
735 else
736 {
737 highestNeeded = receiveFrequency;
738 }
739
740 // Special case, if we're playing a file on the playout side
741 // we take that frequency into consideration as well
742 // This is not needed on sending side, since the codec will
743 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000744 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000745 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000746 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000747 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000748 {
749 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
750 {
751 highestNeeded=_outputFilePlayerPtr->Frequency();
752 }
753 }
754 }
755
756 return(highestNeeded);
757}
758
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000759int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000760Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000761 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000762 uint32_t instanceId,
763 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000764{
765 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
766 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
767 channelId, instanceId);
768
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000769 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000770 if (channel == NULL)
771 {
772 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
773 VoEId(instanceId,channelId),
774 "Channel::CreateChannel() unable to allocate memory for"
775 " channel");
776 return -1;
777 }
778 return 0;
779}
780
781void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000782Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000783{
784 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
785 "Channel::PlayNotification(id=%d, durationMs=%d)",
786 id, durationMs);
787
788 // Not implement yet
789}
790
791void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000792Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000793{
794 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
795 "Channel::RecordNotification(id=%d, durationMs=%d)",
796 id, durationMs);
797
798 // Not implement yet
799}
800
801void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000802Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000803{
804 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
805 "Channel::PlayFileEnded(id=%d)", id);
806
807 if (id == _inputFilePlayerId)
808 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000809 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
811 VoEId(_instanceId,_channelId),
812 "Channel::PlayFileEnded() => input file player module is"
813 " shutdown");
814 }
815 else if (id == _outputFilePlayerId)
816 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000817 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000818 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
819 VoEId(_instanceId,_channelId),
820 "Channel::PlayFileEnded() => output file player module is"
821 " shutdown");
822 }
823}
824
825void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000826Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000827{
828 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
829 "Channel::RecordFileEnded(id=%d)", id);
830
831 assert(id == _outputFileRecorderId);
832
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000833 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000834
835 _outputFileRecording = false;
836 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
837 VoEId(_instanceId,_channelId),
838 "Channel::RecordFileEnded() => output file recorder module is"
839 " shutdown");
840}
841
pbos@webrtc.org92135212013-05-14 08:31:39 +0000842Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000843 uint32_t instanceId,
844 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000845 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
846 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000847 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000849 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000850 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000851 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000852 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000853 rtp_receive_statistics_(ReceiveStatistics::Create(
854 Clock::GetRealTimeClock())),
855 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
856 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
857 this, this, rtp_payload_registry_.get())),
858 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000859 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000860 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 _rtpDumpIn(*RtpDump::CreateRtpDump()),
862 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000865 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 _inputFilePlayerPtr(NULL),
867 _outputFilePlayerPtr(NULL),
868 _outputFileRecorderPtr(NULL),
869 // Avoid conflict with other channels by adding 1024 - 1026,
870 // won't use as much as 1024 channels.
871 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
872 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
873 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
876 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 _inputExternalMediaCallbackPtr(NULL),
879 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000880 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
881 _sendTelephoneEventPayloadType(106),
stefan@webrtc.org8e24d872014-09-02 18:58:24 +0000882 ntp_estimator_(Clock::GetRealTimeClock()),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000883 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000884 playout_timestamp_rtp_(0),
885 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000886 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000887 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000888 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000889 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000890 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
891 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000892 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000893 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000894 _outputMixerPtr(NULL),
895 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000896 _moduleProcessThreadPtr(NULL),
897 _audioDeviceModulePtr(NULL),
898 _voiceEngineObserverPtr(NULL),
899 _callbackCritSectPtr(NULL),
900 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000901 _rxVadObserverPtr(NULL),
902 _oldVadDecision(-1),
903 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000905 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000906 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000907 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000908 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 _mute(false),
910 _panLeft(1.0f),
911 _panRight(1.0f),
912 _outputGain(1.0f),
913 _playOutbandDtmfEvent(false),
914 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 _lastLocalTimeStamp(0),
916 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000917 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _rtpPacketTimedOut(false),
919 _rtpPacketTimeOutIsEnabled(false),
920 _rtpTimeOutSeconds(0),
921 _connectionObserver(false),
922 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000924 vie_network_(NULL),
925 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000926 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000927 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000928 _previousTimestamp(0),
929 _recPacketDelayMs(20),
930 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000932 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000933 restored_packet_in_use_(false),
934 bitrate_controller_(
935 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
936 true)),
937 rtcp_bandwidth_observer_(
938 bitrate_controller_->CreateRtcpBandwidthObserver()),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000939 send_bitrate_observer_(new VoEBitrateObserver(this)),
940 network_predictor_(new NetworkPredictor(Clock::GetRealTimeClock()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000941{
942 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
943 "Channel::Channel() - ctor");
944 _inbandDtmfQueue.ResetDtmf();
945 _inbandDtmfGenerator.Init();
946 _outputAudioLevel.Clear();
947
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000948 RtpRtcp::Configuration configuration;
949 configuration.id = VoEModuleId(instanceId, channelId);
950 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000951 configuration.outgoing_transport = this;
952 configuration.rtcp_feedback = this;
953 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000954 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000955 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000956
957 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000958
959 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
960 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
961 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000962
963 Config audioproc_config;
964 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
965 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000966}
967
968Channel::~Channel()
969{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000970 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000971 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
972 "Channel::~Channel() - dtor");
973
974 if (_outputExternalMedia)
975 {
976 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
977 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000978 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000979 {
980 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
981 }
982 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 StopPlayout();
984
985 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000986 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000987 if (_inputFilePlayerPtr)
988 {
989 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
990 _inputFilePlayerPtr->StopPlayingFile();
991 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
992 _inputFilePlayerPtr = NULL;
993 }
994 if (_outputFilePlayerPtr)
995 {
996 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
997 _outputFilePlayerPtr->StopPlayingFile();
998 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
999 _outputFilePlayerPtr = NULL;
1000 }
1001 if (_outputFileRecorderPtr)
1002 {
1003 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1004 _outputFileRecorderPtr->StopRecording();
1005 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1006 _outputFileRecorderPtr = NULL;
1007 }
1008 }
1009
1010 // The order to safely shutdown modules in a channel is:
1011 // 1. De-register callbacks in modules
1012 // 2. De-register modules in process thread
1013 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001014 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
1016 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1017 VoEId(_instanceId,_channelId),
1018 "~Channel() failed to de-register transport callback"
1019 " (Audio coding module)");
1020 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001021 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 {
1023 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "~Channel() failed to de-register VAD callback"
1026 " (Audio coding module)");
1027 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001028 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001029 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 {
1031 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1032 VoEId(_instanceId,_channelId),
1033 "~Channel() failed to deregister RTP/RTCP module");
1034 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 // End of modules shutdown
1036
1037 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001038 if (vie_network_) {
1039 vie_network_->Release();
1040 vie_network_ = NULL;
1041 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1043 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001046 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001047}
1048
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001049int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001050Channel::Init()
1051{
1052 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1053 "Channel::Init()");
1054
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001055 channel_state_.Reset();
1056
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 // --- Initial sanity
1058
1059 if ((_engineStatisticsPtr == NULL) ||
1060 (_moduleProcessThreadPtr == NULL))
1061 {
1062 WEBRTC_TRACE(kTraceError, kTraceVoice,
1063 VoEId(_instanceId,_channelId),
1064 "Channel::Init() must call SetEngineInformation() first");
1065 return -1;
1066 }
1067
1068 // --- Add modules to process thread (for periodic schedulation)
1069
1070 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001071 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 if (processThreadFail)
1074 {
1075 _engineStatisticsPtr->SetLastError(
1076 VE_CANNOT_INIT_CHANNEL, kTraceError,
1077 "Channel::Init() modules not registered");
1078 return -1;
1079 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001080 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001081
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001082 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001083#ifdef WEBRTC_CODEC_AVT
1084 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001085 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001086#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001087 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 {
1089 _engineStatisticsPtr->SetLastError(
1090 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1091 "Channel::Init() unable to initialize the ACM - 1");
1092 return -1;
1093 }
1094
1095 // --- RTP/RTCP module initialization
1096
1097 // Ensure that RTCP is enabled by default for the created channel.
1098 // Note that, the module will keep generating RTCP until it is explicitly
1099 // disabled by the user.
1100 // After StopListen (when no sockets exists), RTCP packets will no longer
1101 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001102 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1103 // RTCP is enabled by default.
1104 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 {
1106 _engineStatisticsPtr->SetLastError(
1107 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1108 "Channel::Init() RTP/RTCP module not initialized");
1109 return -1;
1110 }
1111
1112 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001113 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001114 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1115 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001116
1117 if (fail)
1118 {
1119 _engineStatisticsPtr->SetLastError(
1120 VE_CANNOT_INIT_CHANNEL, kTraceError,
1121 "Channel::Init() callbacks not registered");
1122 return -1;
1123 }
1124
1125 // --- Register all supported codecs to the receiving side of the
1126 // RTP/RTCP module
1127
1128 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001129 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001130
1131 for (int idx = 0; idx < nSupportedCodecs; idx++)
1132 {
1133 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001134 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001135 (rtp_receiver_->RegisterReceivePayload(
1136 codec.plname,
1137 codec.pltype,
1138 codec.plfreq,
1139 codec.channels,
1140 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 {
1142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1143 VoEId(_instanceId,_channelId),
1144 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1145 "to RTP/RTCP receiver",
1146 codec.plname, codec.pltype, codec.plfreq,
1147 codec.channels, codec.rate);
1148 }
1149 else
1150 {
1151 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1152 VoEId(_instanceId,_channelId),
1153 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1154 "the RTP/RTCP receiver",
1155 codec.plname, codec.pltype, codec.plfreq,
1156 codec.channels, codec.rate);
1157 }
1158
1159 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001160 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 {
1162 SetSendCodec(codec);
1163 }
1164
1165 // Register default PT for outband 'telephone-event'
1166 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1167 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001168 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001169 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001170 {
1171 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1172 VoEId(_instanceId,_channelId),
1173 "Channel::Init() failed to register outband "
1174 "'telephone-event' (%d/%d) correctly",
1175 codec.pltype, codec.plfreq);
1176 }
1177 }
1178
1179 if (!STR_CASE_CMP(codec.plname, "CN"))
1180 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001181 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1182 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001183 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001184 {
1185 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1186 VoEId(_instanceId,_channelId),
1187 "Channel::Init() failed to register CN (%d/%d) "
1188 "correctly - 1",
1189 codec.pltype, codec.plfreq);
1190 }
1191 }
1192#ifdef WEBRTC_CODEC_RED
1193 // Register RED to the receiving side of the ACM.
1194 // We will not receive an OnInitializeDecoder() callback for RED.
1195 if (!STR_CASE_CMP(codec.plname, "RED"))
1196 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001197 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001198 {
1199 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1200 VoEId(_instanceId,_channelId),
1201 "Channel::Init() failed to register RED (%d/%d) "
1202 "correctly",
1203 codec.pltype, codec.plfreq);
1204 }
1205 }
1206#endif
1207 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001208
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001209 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1210 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1211 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001213 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1214 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1215 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001216 }
1217
1218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::SetEngineInformation(Statistics& engineStatistics,
1223 OutputMixer& outputMixer,
1224 voe::TransmitMixer& transmitMixer,
1225 ProcessThread& moduleProcessThread,
1226 AudioDeviceModule& audioDeviceModule,
1227 VoiceEngineObserver* voiceEngineObserver,
1228 CriticalSectionWrapper* callbackCritSect)
1229{
1230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1231 "Channel::SetEngineInformation()");
1232 _engineStatisticsPtr = &engineStatistics;
1233 _outputMixerPtr = &outputMixer;
1234 _transmitMixerPtr = &transmitMixer,
1235 _moduleProcessThreadPtr = &moduleProcessThread;
1236 _audioDeviceModulePtr = &audioDeviceModule;
1237 _voiceEngineObserverPtr = voiceEngineObserver;
1238 _callbackCritSectPtr = callbackCritSect;
1239 return 0;
1240}
1241
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001242int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001243Channel::UpdateLocalTimeStamp()
1244{
1245
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001246 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 return 0;
1248}
1249
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001250int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001251Channel::StartPlayout()
1252{
1253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1254 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001255 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 {
1257 return 0;
1258 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001259
1260 if (!_externalMixing) {
1261 // Add participant as candidates for mixing.
1262 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1263 {
1264 _engineStatisticsPtr->SetLastError(
1265 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1266 "StartPlayout() failed to add participant to mixer");
1267 return -1;
1268 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 }
1270
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001271 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001272 if (RegisterFilePlayingToMixer() != 0)
1273 return -1;
1274
niklase@google.com470e71d2011-07-07 08:21:25 +00001275 return 0;
1276}
1277
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001278int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001279Channel::StopPlayout()
1280{
1281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1282 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001283 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 {
1285 return 0;
1286 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001287
1288 if (!_externalMixing) {
1289 // Remove participant as candidates for mixing
1290 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1291 {
1292 _engineStatisticsPtr->SetLastError(
1293 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1294 "StopPlayout() failed to remove participant from mixer");
1295 return -1;
1296 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 }
1298
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001299 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 _outputAudioLevel.Clear();
1301
1302 return 0;
1303}
1304
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001305int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001306Channel::StartSend()
1307{
1308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1309 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001310 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001311 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001312 if (send_sequence_number_)
1313 SetInitSequenceNumber(send_sequence_number_);
1314
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001315 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001316 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001317 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001319 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001320
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001321 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001322 {
1323 _engineStatisticsPtr->SetLastError(
1324 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1325 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001326 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001327 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 return -1;
1329 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001330
niklase@google.com470e71d2011-07-07 08:21:25 +00001331 return 0;
1332}
1333
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001334int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001335Channel::StopSend()
1336{
1337 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1338 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001339 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001341 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001342 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001343 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001344
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001345 // Store the sequence number to be able to pick up the same sequence for
1346 // the next StartSend(). This is needed for restarting device, otherwise
1347 // it might cause libSRTP to complain about packets being replayed.
1348 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1349 // CL is landed. See issue
1350 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1351 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1352
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 // Reset sending SSRC and sequence number and triggers direct transmission
1354 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001355 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1356 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001357 {
1358 _engineStatisticsPtr->SetLastError(
1359 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1360 "StartSend() RTP/RTCP failed to stop sending");
1361 }
1362
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 return 0;
1364}
1365
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001366int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001367Channel::StartReceiving()
1368{
1369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1370 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001371 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 {
1373 return 0;
1374 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001375 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 _numberOfDiscardedPackets = 0;
1377 return 0;
1378}
1379
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001380int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001381Channel::StopReceiving()
1382{
1383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1384 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001385 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001386 {
1387 return 0;
1388 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001389
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001390 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 return 0;
1392}
1393
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001394int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001395Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1396{
1397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1398 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001399 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001400
1401 if (_voiceEngineObserverPtr)
1402 {
1403 _engineStatisticsPtr->SetLastError(
1404 VE_INVALID_OPERATION, kTraceError,
1405 "RegisterVoiceEngineObserver() observer already enabled");
1406 return -1;
1407 }
1408 _voiceEngineObserverPtr = &observer;
1409 return 0;
1410}
1411
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001412int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001413Channel::DeRegisterVoiceEngineObserver()
1414{
1415 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1416 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001417 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001418
1419 if (!_voiceEngineObserverPtr)
1420 {
1421 _engineStatisticsPtr->SetLastError(
1422 VE_INVALID_OPERATION, kTraceWarning,
1423 "DeRegisterVoiceEngineObserver() observer already disabled");
1424 return 0;
1425 }
1426 _voiceEngineObserverPtr = NULL;
1427 return 0;
1428}
1429
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001430int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001431Channel::GetSendCodec(CodecInst& codec)
1432{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001433 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001434}
1435
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001436int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001437Channel::GetRecCodec(CodecInst& codec)
1438{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001439 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001440}
1441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001442int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001443Channel::SetSendCodec(const CodecInst& codec)
1444{
1445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1446 "Channel::SetSendCodec()");
1447
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001448 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
1450 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1451 "SetSendCodec() failed to register codec to ACM");
1452 return -1;
1453 }
1454
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001455 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001456 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001457 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1458 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 {
1460 WEBRTC_TRACE(
1461 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1462 "SetSendCodec() failed to register codec to"
1463 " RTP/RTCP module");
1464 return -1;
1465 }
1466 }
1467
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001468 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001469 {
1470 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "SetSendCodec() failed to set audio packet size");
1472 return -1;
1473 }
1474
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001475 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1476 codec.rate, 0, 0);
1477
niklase@google.com470e71d2011-07-07 08:21:25 +00001478 return 0;
1479}
1480
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001481void
1482Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1483 const uint8_t fraction_lost, // 0 - 255.
1484 const uint32_t rtt) {
1485 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1486 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1487 bitrate_bps, fraction_lost, rtt);
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001488 // |fraction_lost| from BitrateObserver is short time observation of packet
1489 // loss rate from past. We use network predictor to make a more reasonable
1490 // loss rate estimation.
1491 network_predictor_->UpdatePacketLossRate(fraction_lost);
1492 uint8_t loss_rate = network_predictor_->GetLossRate();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001493 // Normalizes rate to 0 - 100.
minyue@webrtc.org74aaf292014-07-16 21:28:26 +00001494 if (audio_coding_->SetPacketLossRate(100 * loss_rate / 255) != 0) {
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001495 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1496 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1497 assert(false); // This should not happen.
1498 }
1499}
1500
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001501int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001502Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1503{
1504 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1505 "Channel::SetVADStatus(mode=%d)", mode);
1506 // To disable VAD, DTX must be disabled too
1507 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001508 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001509 {
1510 _engineStatisticsPtr->SetLastError(
1511 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1512 "SetVADStatus() failed to set VAD");
1513 return -1;
1514 }
1515 return 0;
1516}
1517
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001518int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001519Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1520{
1521 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1522 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001523 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
1525 _engineStatisticsPtr->SetLastError(
1526 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1527 "GetVADStatus() failed to get VAD status");
1528 return -1;
1529 }
1530 disabledDTX = !disabledDTX;
1531 return 0;
1532}
1533
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001534int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001535Channel::SetRecPayloadType(const CodecInst& codec)
1536{
1537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1538 "Channel::SetRecPayloadType()");
1539
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001540 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001541 {
1542 _engineStatisticsPtr->SetLastError(
1543 VE_ALREADY_PLAYING, kTraceError,
1544 "SetRecPayloadType() unable to set PT while playing");
1545 return -1;
1546 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001547 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001548 {
1549 _engineStatisticsPtr->SetLastError(
1550 VE_ALREADY_LISTENING, kTraceError,
1551 "SetRecPayloadType() unable to set PT while listening");
1552 return -1;
1553 }
1554
1555 if (codec.pltype == -1)
1556 {
1557 // De-register the selected codec (RTP/RTCP module and ACM)
1558
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001559 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001560 CodecInst rxCodec = codec;
1561
1562 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001563 rtp_payload_registry_->ReceivePayloadType(
1564 rxCodec.plname,
1565 rxCodec.plfreq,
1566 rxCodec.channels,
1567 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1568 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001569 rxCodec.pltype = pltype;
1570
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001571 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001572 {
1573 _engineStatisticsPtr->SetLastError(
1574 VE_RTP_RTCP_MODULE_ERROR,
1575 kTraceError,
1576 "SetRecPayloadType() RTP/RTCP-module deregistration "
1577 "failed");
1578 return -1;
1579 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001580 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001581 {
1582 _engineStatisticsPtr->SetLastError(
1583 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1584 "SetRecPayloadType() ACM deregistration failed - 1");
1585 return -1;
1586 }
1587 return 0;
1588 }
1589
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001590 if (rtp_receiver_->RegisterReceivePayload(
1591 codec.plname,
1592 codec.pltype,
1593 codec.plfreq,
1594 codec.channels,
1595 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 {
1597 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001598 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1599 if (rtp_receiver_->RegisterReceivePayload(
1600 codec.plname,
1601 codec.pltype,
1602 codec.plfreq,
1603 codec.channels,
1604 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001605 {
1606 _engineStatisticsPtr->SetLastError(
1607 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1608 "SetRecPayloadType() RTP/RTCP-module registration failed");
1609 return -1;
1610 }
1611 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001612 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001613 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001614 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1615 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001616 {
1617 _engineStatisticsPtr->SetLastError(
1618 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1619 "SetRecPayloadType() ACM registration failed - 1");
1620 return -1;
1621 }
1622 }
1623 return 0;
1624}
1625
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001626int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001627Channel::GetRecPayloadType(CodecInst& codec)
1628{
1629 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1630 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001631 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001632 if (rtp_payload_registry_->ReceivePayloadType(
1633 codec.plname,
1634 codec.plfreq,
1635 codec.channels,
1636 (codec.rate < 0) ? 0 : codec.rate,
1637 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001638 {
1639 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001640 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001641 "GetRecPayloadType() failed to retrieve RX payload type");
1642 return -1;
1643 }
1644 codec.pltype = payloadType;
1645 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1646 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1647 return 0;
1648}
1649
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001650int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001651Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1652{
1653 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1654 "Channel::SetSendCNPayloadType()");
1655
1656 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001657 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001658 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001659 if (frequency == kFreq32000Hz)
1660 samplingFreqHz = 32000;
1661 else if (frequency == kFreq16000Hz)
1662 samplingFreqHz = 16000;
1663
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001664 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001665 {
1666 _engineStatisticsPtr->SetLastError(
1667 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1668 "SetSendCNPayloadType() failed to retrieve default CN codec "
1669 "settings");
1670 return -1;
1671 }
1672
1673 // Modify the payload type (must be set to dynamic range)
1674 codec.pltype = type;
1675
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001676 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001677 {
1678 _engineStatisticsPtr->SetLastError(
1679 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1680 "SetSendCNPayloadType() failed to register CN to ACM");
1681 return -1;
1682 }
1683
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001684 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001685 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001686 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1687 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001688 {
1689 _engineStatisticsPtr->SetLastError(
1690 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1691 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1692 "module");
1693 return -1;
1694 }
1695 }
1696 return 0;
1697}
1698
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001699int Channel::SetOpusMaxPlaybackRate(int frequency_hz) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001700 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001701 "Channel::SetOpusMaxPlaybackRate()");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001702
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001703 if (audio_coding_->SetOpusMaxPlaybackRate(frequency_hz) != 0) {
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001704 _engineStatisticsPtr->SetLastError(
1705 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgadee8f92014-09-03 12:28:06 +00001706 "SetOpusMaxPlaybackRate() failed to set maximum playback rate");
minyue@webrtc.org6aac93b2014-08-12 08:13:33 +00001707 return -1;
1708 }
1709 return 0;
1710}
1711
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001712int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001713{
1714 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1715 "Channel::RegisterExternalTransport()");
1716
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001717 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001718
niklase@google.com470e71d2011-07-07 08:21:25 +00001719 if (_externalTransport)
1720 {
1721 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1722 kTraceError,
1723 "RegisterExternalTransport() external transport already enabled");
1724 return -1;
1725 }
1726 _externalTransport = true;
1727 _transportPtr = &transport;
1728 return 0;
1729}
1730
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001731int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001732Channel::DeRegisterExternalTransport()
1733{
1734 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1735 "Channel::DeRegisterExternalTransport()");
1736
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001737 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001738
niklase@google.com470e71d2011-07-07 08:21:25 +00001739 if (!_transportPtr)
1740 {
1741 _engineStatisticsPtr->SetLastError(
1742 VE_INVALID_OPERATION, kTraceWarning,
1743 "DeRegisterExternalTransport() external transport already "
1744 "disabled");
1745 return 0;
1746 }
1747 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001748 _transportPtr = NULL;
1749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1750 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001751 return 0;
1752}
1753
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001754int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1755 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001756 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1757 "Channel::ReceivedRTPPacket()");
1758
1759 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001760 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001761
1762 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001763 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1764 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001765 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1766 VoEId(_instanceId,_channelId),
1767 "Channel::SendPacket() RTP dump to input file failed");
1768 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001769 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001770 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001771 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1772 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1773 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001774 return -1;
1775 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001776 header.payload_type_frequency =
1777 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001778 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001779 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001780 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001781 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001782 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001783 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001784
1785 // Forward any packets to ViE bandwidth estimator, if enabled.
1786 {
1787 CriticalSectionScoped cs(&_callbackCritSect);
1788 if (vie_network_) {
1789 int64_t arrival_time_ms;
1790 if (packet_time.timestamp != -1) {
1791 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1792 } else {
1793 arrival_time_ms = TickTime::MillisecondTimestamp();
1794 }
1795 int payload_length = length - header.headerLength;
1796 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1797 payload_length, header);
1798 }
1799 }
1800
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001801 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001802}
1803
1804bool Channel::ReceivePacket(const uint8_t* packet,
1805 int packet_length,
1806 const RTPHeader& header,
1807 bool in_order) {
1808 if (rtp_payload_registry_->IsEncapsulated(header)) {
1809 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001810 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001811 const uint8_t* payload = packet + header.headerLength;
1812 int payload_length = packet_length - header.headerLength;
1813 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001814 PayloadUnion payload_specific;
1815 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001816 &payload_specific)) {
1817 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001818 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001819 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1820 payload_specific, in_order);
1821}
1822
1823bool Channel::HandleEncapsulation(const uint8_t* packet,
1824 int packet_length,
1825 const RTPHeader& header) {
1826 if (!rtp_payload_registry_->IsRtx(header))
1827 return false;
1828
1829 // Remove the RTX header and parse the original RTP header.
1830 if (packet_length < header.headerLength)
1831 return false;
1832 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1833 return false;
1834 if (restored_packet_in_use_) {
1835 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1836 "Multiple RTX headers detected, dropping packet");
1837 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001838 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001839 uint8_t* restored_packet_ptr = restored_packet_;
1840 if (!rtp_payload_registry_->RestoreOriginalPacket(
1841 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1842 header)) {
1843 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1844 "Incoming RTX packet: invalid RTP header");
1845 return false;
1846 }
1847 restored_packet_in_use_ = true;
1848 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1849 restored_packet_in_use_ = false;
1850 return ret;
1851}
1852
1853bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1854 StreamStatistician* statistician =
1855 rtp_receive_statistics_->GetStatistician(header.ssrc);
1856 if (!statistician)
1857 return false;
1858 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001859}
1860
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001861bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1862 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001863 // Retransmissions are handled separately if RTX is enabled.
1864 if (rtp_payload_registry_->RtxEnabled())
1865 return false;
1866 StreamStatistician* statistician =
1867 rtp_receive_statistics_->GetStatistician(header.ssrc);
1868 if (!statistician)
1869 return false;
1870 // Check if this is a retransmission.
1871 uint16_t min_rtt = 0;
1872 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001873 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001874 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001875}
1876
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001877int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001878 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1879 "Channel::ReceivedRTCPPacket()");
1880 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001881 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001882
1883 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001884 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1885 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001886 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1887 VoEId(_instanceId,_channelId),
1888 "Channel::SendPacket() RTCP dump to input file failed");
1889 }
1890
1891 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001892 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1893 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001894 _engineStatisticsPtr->SetLastError(
1895 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1896 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1897 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001898
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001899 {
1900 CriticalSectionScoped lock(ts_stats_lock_.get());
minyue@webrtc.org2c0cdbc2014-10-09 10:52:43 +00001901 uint16_t rtt = GetRTT();
1902 if (rtt == 0) {
1903 // Waiting for valid RTT.
1904 return 0;
1905 }
1906 uint32_t ntp_secs = 0;
1907 uint32_t ntp_frac = 0;
1908 uint32_t rtp_timestamp = 0;
1909 if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL,
1910 &rtp_timestamp)) {
1911 // Waiting for RTCP.
1912 return 0;
1913 }
1914 ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp);
stefan@webrtc.org8e24d872014-09-02 18:58:24 +00001915 }
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001916 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001917}
1918
niklase@google.com470e71d2011-07-07 08:21:25 +00001919int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001920 bool loop,
1921 FileFormats format,
1922 int startPosition,
1923 float volumeScaling,
1924 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001925 const CodecInst* codecInst)
1926{
1927 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1928 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1929 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1930 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1931 startPosition, stopPosition);
1932
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001933 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001934 {
1935 _engineStatisticsPtr->SetLastError(
1936 VE_ALREADY_PLAYING, kTraceError,
1937 "StartPlayingFileLocally() is already playing");
1938 return -1;
1939 }
1940
niklase@google.com470e71d2011-07-07 08:21:25 +00001941 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001942 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001943
1944 if (_outputFilePlayerPtr)
1945 {
1946 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1947 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1948 _outputFilePlayerPtr = NULL;
1949 }
1950
1951 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1952 _outputFilePlayerId, (const FileFormats)format);
1953
1954 if (_outputFilePlayerPtr == NULL)
1955 {
1956 _engineStatisticsPtr->SetLastError(
1957 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001958 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001959 return -1;
1960 }
1961
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001962 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001963
1964 if (_outputFilePlayerPtr->StartPlayingFile(
1965 fileName,
1966 loop,
1967 startPosition,
1968 volumeScaling,
1969 notificationTime,
1970 stopPosition,
1971 (const CodecInst*)codecInst) != 0)
1972 {
1973 _engineStatisticsPtr->SetLastError(
1974 VE_BAD_FILE, kTraceError,
1975 "StartPlayingFile() failed to start file playout");
1976 _outputFilePlayerPtr->StopPlayingFile();
1977 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1978 _outputFilePlayerPtr = NULL;
1979 return -1;
1980 }
1981 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001982 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001983 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001984
1985 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001986 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001987
1988 return 0;
1989}
1990
1991int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001992 FileFormats format,
1993 int startPosition,
1994 float volumeScaling,
1995 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001996 const CodecInst* codecInst)
1997{
1998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1999 "Channel::StartPlayingFileLocally(format=%d,"
2000 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2001 format, volumeScaling, startPosition, stopPosition);
2002
2003 if(stream == NULL)
2004 {
2005 _engineStatisticsPtr->SetLastError(
2006 VE_BAD_FILE, kTraceError,
2007 "StartPlayingFileLocally() NULL as input stream");
2008 return -1;
2009 }
2010
2011
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002012 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002013 {
2014 _engineStatisticsPtr->SetLastError(
2015 VE_ALREADY_PLAYING, kTraceError,
2016 "StartPlayingFileLocally() is already playing");
2017 return -1;
2018 }
2019
niklase@google.com470e71d2011-07-07 08:21:25 +00002020 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002021 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002022
2023 // Destroy the old instance
2024 if (_outputFilePlayerPtr)
2025 {
2026 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2027 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2028 _outputFilePlayerPtr = NULL;
2029 }
2030
2031 // Create the instance
2032 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2033 _outputFilePlayerId,
2034 (const FileFormats)format);
2035
2036 if (_outputFilePlayerPtr == NULL)
2037 {
2038 _engineStatisticsPtr->SetLastError(
2039 VE_INVALID_ARGUMENT, kTraceError,
2040 "StartPlayingFileLocally() filePlayer format isnot correct");
2041 return -1;
2042 }
2043
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002044 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002045
2046 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2047 volumeScaling,
2048 notificationTime,
2049 stopPosition, codecInst) != 0)
2050 {
2051 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2052 "StartPlayingFile() failed to "
2053 "start file playout");
2054 _outputFilePlayerPtr->StopPlayingFile();
2055 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2056 _outputFilePlayerPtr = NULL;
2057 return -1;
2058 }
2059 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002060 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002061 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002062
2063 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002064 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002065
niklase@google.com470e71d2011-07-07 08:21:25 +00002066 return 0;
2067}
2068
2069int Channel::StopPlayingFileLocally()
2070{
2071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2072 "Channel::StopPlayingFileLocally()");
2073
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002074 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002075 {
2076 _engineStatisticsPtr->SetLastError(
2077 VE_INVALID_OPERATION, kTraceWarning,
2078 "StopPlayingFileLocally() isnot playing");
2079 return 0;
2080 }
2081
niklase@google.com470e71d2011-07-07 08:21:25 +00002082 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002083 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002084
2085 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2086 {
2087 _engineStatisticsPtr->SetLastError(
2088 VE_STOP_RECORDING_FAILED, kTraceError,
2089 "StopPlayingFile() could not stop playing");
2090 return -1;
2091 }
2092 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2093 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2094 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002095 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002096 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002097 // _fileCritSect cannot be taken while calling
2098 // SetAnonymousMixibilityStatus. Refer to comments in
2099 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002100 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2101 {
2102 _engineStatisticsPtr->SetLastError(
2103 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002104 "StopPlayingFile() failed to stop participant from playing as"
2105 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002106 return -1;
2107 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002108
2109 return 0;
2110}
2111
2112int Channel::IsPlayingFileLocally() const
2113{
2114 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2115 "Channel::IsPlayingFileLocally()");
2116
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002117 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002118}
2119
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002120int Channel::RegisterFilePlayingToMixer()
2121{
2122 // Return success for not registering for file playing to mixer if:
2123 // 1. playing file before playout is started on that channel.
2124 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002125 if (!channel_state_.Get().playing ||
2126 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002127 {
2128 return 0;
2129 }
2130
2131 // |_fileCritSect| cannot be taken while calling
2132 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2133 // frames can be pulled by the mixer. Since the frames are generated from
2134 // the file, _fileCritSect will be taken. This would result in a deadlock.
2135 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2136 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002137 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002138 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002139 _engineStatisticsPtr->SetLastError(
2140 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2141 "StartPlayingFile() failed to add participant as file to mixer");
2142 _outputFilePlayerPtr->StopPlayingFile();
2143 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2144 _outputFilePlayerPtr = NULL;
2145 return -1;
2146 }
2147
2148 return 0;
2149}
2150
niklase@google.com470e71d2011-07-07 08:21:25 +00002151int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002152 bool loop,
2153 FileFormats format,
2154 int startPosition,
2155 float volumeScaling,
2156 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002157 const CodecInst* codecInst)
2158{
2159 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2160 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2161 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2162 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2163 startPosition, stopPosition);
2164
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002165 CriticalSectionScoped cs(&_fileCritSect);
2166
2167 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002168 {
2169 _engineStatisticsPtr->SetLastError(
2170 VE_ALREADY_PLAYING, kTraceWarning,
2171 "StartPlayingFileAsMicrophone() filePlayer is playing");
2172 return 0;
2173 }
2174
niklase@google.com470e71d2011-07-07 08:21:25 +00002175 // Destroy the old instance
2176 if (_inputFilePlayerPtr)
2177 {
2178 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2179 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2180 _inputFilePlayerPtr = NULL;
2181 }
2182
2183 // Create the instance
2184 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2185 _inputFilePlayerId, (const FileFormats)format);
2186
2187 if (_inputFilePlayerPtr == NULL)
2188 {
2189 _engineStatisticsPtr->SetLastError(
2190 VE_INVALID_ARGUMENT, kTraceError,
2191 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2192 return -1;
2193 }
2194
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002195 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002196
2197 if (_inputFilePlayerPtr->StartPlayingFile(
2198 fileName,
2199 loop,
2200 startPosition,
2201 volumeScaling,
2202 notificationTime,
2203 stopPosition,
2204 (const CodecInst*)codecInst) != 0)
2205 {
2206 _engineStatisticsPtr->SetLastError(
2207 VE_BAD_FILE, kTraceError,
2208 "StartPlayingFile() failed to start file playout");
2209 _inputFilePlayerPtr->StopPlayingFile();
2210 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2211 _inputFilePlayerPtr = NULL;
2212 return -1;
2213 }
2214 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002215 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002216
2217 return 0;
2218}
2219
2220int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002221 FileFormats format,
2222 int startPosition,
2223 float volumeScaling,
2224 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002225 const CodecInst* codecInst)
2226{
2227 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2228 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2229 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2230 format, volumeScaling, startPosition, stopPosition);
2231
2232 if(stream == NULL)
2233 {
2234 _engineStatisticsPtr->SetLastError(
2235 VE_BAD_FILE, kTraceError,
2236 "StartPlayingFileAsMicrophone NULL as input stream");
2237 return -1;
2238 }
2239
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002240 CriticalSectionScoped cs(&_fileCritSect);
2241
2242 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002243 {
2244 _engineStatisticsPtr->SetLastError(
2245 VE_ALREADY_PLAYING, kTraceWarning,
2246 "StartPlayingFileAsMicrophone() is playing");
2247 return 0;
2248 }
2249
niklase@google.com470e71d2011-07-07 08:21:25 +00002250 // Destroy the old instance
2251 if (_inputFilePlayerPtr)
2252 {
2253 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2254 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2255 _inputFilePlayerPtr = NULL;
2256 }
2257
2258 // Create the instance
2259 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2260 _inputFilePlayerId, (const FileFormats)format);
2261
2262 if (_inputFilePlayerPtr == NULL)
2263 {
2264 _engineStatisticsPtr->SetLastError(
2265 VE_INVALID_ARGUMENT, kTraceError,
2266 "StartPlayingInputFile() filePlayer format isnot correct");
2267 return -1;
2268 }
2269
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002270 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002271
2272 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2273 volumeScaling, notificationTime,
2274 stopPosition, codecInst) != 0)
2275 {
2276 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2277 "StartPlayingFile() failed to start "
2278 "file playout");
2279 _inputFilePlayerPtr->StopPlayingFile();
2280 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2281 _inputFilePlayerPtr = NULL;
2282 return -1;
2283 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002284
niklase@google.com470e71d2011-07-07 08:21:25 +00002285 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002286 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002287
2288 return 0;
2289}
2290
2291int Channel::StopPlayingFileAsMicrophone()
2292{
2293 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2294 "Channel::StopPlayingFileAsMicrophone()");
2295
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002296 CriticalSectionScoped cs(&_fileCritSect);
2297
2298 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002299 {
2300 _engineStatisticsPtr->SetLastError(
2301 VE_INVALID_OPERATION, kTraceWarning,
2302 "StopPlayingFileAsMicrophone() isnot playing");
2303 return 0;
2304 }
2305
niklase@google.com470e71d2011-07-07 08:21:25 +00002306 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2307 {
2308 _engineStatisticsPtr->SetLastError(
2309 VE_STOP_RECORDING_FAILED, kTraceError,
2310 "StopPlayingFile() could not stop playing");
2311 return -1;
2312 }
2313 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2314 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2315 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002316 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002317
2318 return 0;
2319}
2320
2321int Channel::IsPlayingFileAsMicrophone() const
2322{
2323 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2324 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002325 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002326}
2327
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002328int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002329 const CodecInst* codecInst)
2330{
2331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2332 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2333
2334 if (_outputFileRecording)
2335 {
2336 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2337 "StartRecordingPlayout() is already recording");
2338 return 0;
2339 }
2340
2341 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002342 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002343 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2344
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002345 if ((codecInst != NULL) &&
2346 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002347 {
2348 _engineStatisticsPtr->SetLastError(
2349 VE_BAD_ARGUMENT, kTraceError,
2350 "StartRecordingPlayout() invalid compression");
2351 return(-1);
2352 }
2353 if(codecInst == NULL)
2354 {
2355 format = kFileFormatPcm16kHzFile;
2356 codecInst=&dummyCodec;
2357 }
2358 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2359 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2360 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2361 {
2362 format = kFileFormatWavFile;
2363 }
2364 else
2365 {
2366 format = kFileFormatCompressedFile;
2367 }
2368
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002369 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002370
2371 // Destroy the old instance
2372 if (_outputFileRecorderPtr)
2373 {
2374 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2375 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2376 _outputFileRecorderPtr = NULL;
2377 }
2378
2379 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2380 _outputFileRecorderId, (const FileFormats)format);
2381 if (_outputFileRecorderPtr == NULL)
2382 {
2383 _engineStatisticsPtr->SetLastError(
2384 VE_INVALID_ARGUMENT, kTraceError,
2385 "StartRecordingPlayout() fileRecorder format isnot correct");
2386 return -1;
2387 }
2388
2389 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2390 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2391 {
2392 _engineStatisticsPtr->SetLastError(
2393 VE_BAD_FILE, kTraceError,
2394 "StartRecordingAudioFile() failed to start file recording");
2395 _outputFileRecorderPtr->StopRecording();
2396 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2397 _outputFileRecorderPtr = NULL;
2398 return -1;
2399 }
2400 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2401 _outputFileRecording = true;
2402
2403 return 0;
2404}
2405
2406int Channel::StartRecordingPlayout(OutStream* stream,
2407 const CodecInst* codecInst)
2408{
2409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2410 "Channel::StartRecordingPlayout()");
2411
2412 if (_outputFileRecording)
2413 {
2414 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2415 "StartRecordingPlayout() is already recording");
2416 return 0;
2417 }
2418
2419 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002420 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002421 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2422
2423 if (codecInst != NULL && codecInst->channels != 1)
2424 {
2425 _engineStatisticsPtr->SetLastError(
2426 VE_BAD_ARGUMENT, kTraceError,
2427 "StartRecordingPlayout() invalid compression");
2428 return(-1);
2429 }
2430 if(codecInst == NULL)
2431 {
2432 format = kFileFormatPcm16kHzFile;
2433 codecInst=&dummyCodec;
2434 }
2435 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2436 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2437 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2438 {
2439 format = kFileFormatWavFile;
2440 }
2441 else
2442 {
2443 format = kFileFormatCompressedFile;
2444 }
2445
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002446 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002447
2448 // Destroy the old instance
2449 if (_outputFileRecorderPtr)
2450 {
2451 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2452 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2453 _outputFileRecorderPtr = NULL;
2454 }
2455
2456 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2457 _outputFileRecorderId, (const FileFormats)format);
2458 if (_outputFileRecorderPtr == NULL)
2459 {
2460 _engineStatisticsPtr->SetLastError(
2461 VE_INVALID_ARGUMENT, kTraceError,
2462 "StartRecordingPlayout() fileRecorder format isnot correct");
2463 return -1;
2464 }
2465
2466 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2467 notificationTime) != 0)
2468 {
2469 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2470 "StartRecordingPlayout() failed to "
2471 "start file recording");
2472 _outputFileRecorderPtr->StopRecording();
2473 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2474 _outputFileRecorderPtr = NULL;
2475 return -1;
2476 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002477
niklase@google.com470e71d2011-07-07 08:21:25 +00002478 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2479 _outputFileRecording = true;
2480
2481 return 0;
2482}
2483
2484int Channel::StopRecordingPlayout()
2485{
2486 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2487 "Channel::StopRecordingPlayout()");
2488
2489 if (!_outputFileRecording)
2490 {
2491 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2492 "StopRecordingPlayout() isnot recording");
2493 return -1;
2494 }
2495
2496
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002497 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002498
2499 if (_outputFileRecorderPtr->StopRecording() != 0)
2500 {
2501 _engineStatisticsPtr->SetLastError(
2502 VE_STOP_RECORDING_FAILED, kTraceError,
2503 "StopRecording() could not stop recording");
2504 return(-1);
2505 }
2506 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2507 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2508 _outputFileRecorderPtr = NULL;
2509 _outputFileRecording = false;
2510
2511 return 0;
2512}
2513
2514void
2515Channel::SetMixWithMicStatus(bool mix)
2516{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002517 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002518 _mixFileWithMicrophone=mix;
2519}
2520
2521int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002522Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002523{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002524 int8_t currentLevel = _outputAudioLevel.Level();
2525 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002526 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2527 VoEId(_instanceId,_channelId),
2528 "GetSpeechOutputLevel() => level=%u", level);
2529 return 0;
2530}
2531
2532int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002533Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002534{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002535 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2536 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002537 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2538 VoEId(_instanceId,_channelId),
2539 "GetSpeechOutputLevelFullRange() => level=%u", level);
2540 return 0;
2541}
2542
2543int
2544Channel::SetMute(bool enable)
2545{
wu@webrtc.org63420662013-10-17 18:28:55 +00002546 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2548 "Channel::SetMute(enable=%d)", enable);
2549 _mute = enable;
2550 return 0;
2551}
2552
2553bool
2554Channel::Mute() const
2555{
wu@webrtc.org63420662013-10-17 18:28:55 +00002556 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002557 return _mute;
2558}
2559
2560int
2561Channel::SetOutputVolumePan(float left, float right)
2562{
wu@webrtc.org63420662013-10-17 18:28:55 +00002563 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002564 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2565 "Channel::SetOutputVolumePan()");
2566 _panLeft = left;
2567 _panRight = right;
2568 return 0;
2569}
2570
2571int
2572Channel::GetOutputVolumePan(float& left, float& right) const
2573{
wu@webrtc.org63420662013-10-17 18:28:55 +00002574 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002575 left = _panLeft;
2576 right = _panRight;
2577 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2578 VoEId(_instanceId,_channelId),
2579 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2580 return 0;
2581}
2582
2583int
2584Channel::SetChannelOutputVolumeScaling(float scaling)
2585{
wu@webrtc.org63420662013-10-17 18:28:55 +00002586 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2588 "Channel::SetChannelOutputVolumeScaling()");
2589 _outputGain = scaling;
2590 return 0;
2591}
2592
2593int
2594Channel::GetChannelOutputVolumeScaling(float& scaling) const
2595{
wu@webrtc.org63420662013-10-17 18:28:55 +00002596 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002597 scaling = _outputGain;
2598 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2599 VoEId(_instanceId,_channelId),
2600 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2601 return 0;
2602}
2603
niklase@google.com470e71d2011-07-07 08:21:25 +00002604int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002605 int lengthMs, int attenuationDb,
2606 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002607{
2608 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2609 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2610 playDtmfEvent);
2611
2612 _playOutbandDtmfEvent = playDtmfEvent;
2613
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002614 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002615 attenuationDb) != 0)
2616 {
2617 _engineStatisticsPtr->SetLastError(
2618 VE_SEND_DTMF_FAILED,
2619 kTraceWarning,
2620 "SendTelephoneEventOutband() failed to send event");
2621 return -1;
2622 }
2623 return 0;
2624}
2625
2626int Channel::SendTelephoneEventInband(unsigned char eventCode,
2627 int lengthMs,
2628 int attenuationDb,
2629 bool playDtmfEvent)
2630{
2631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2632 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2633 playDtmfEvent);
2634
2635 _playInbandDtmfEvent = playDtmfEvent;
2636 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2637
2638 return 0;
2639}
2640
2641int
niklase@google.com470e71d2011-07-07 08:21:25 +00002642Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2643{
2644 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2645 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002646 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002647 {
2648 _engineStatisticsPtr->SetLastError(
2649 VE_INVALID_ARGUMENT, kTraceError,
2650 "SetSendTelephoneEventPayloadType() invalid type");
2651 return -1;
2652 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002653 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002654 codec.plfreq = 8000;
2655 codec.pltype = type;
2656 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002657 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002658 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002659 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2660 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2661 _engineStatisticsPtr->SetLastError(
2662 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2663 "SetSendTelephoneEventPayloadType() failed to register send"
2664 "payload type");
2665 return -1;
2666 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002667 }
2668 _sendTelephoneEventPayloadType = type;
2669 return 0;
2670}
2671
2672int
2673Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2674{
2675 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2676 "Channel::GetSendTelephoneEventPayloadType()");
2677 type = _sendTelephoneEventPayloadType;
2678 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2679 VoEId(_instanceId,_channelId),
2680 "GetSendTelephoneEventPayloadType() => type=%u", type);
2681 return 0;
2682}
2683
niklase@google.com470e71d2011-07-07 08:21:25 +00002684int
2685Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2686{
2687 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2688 "Channel::UpdateRxVadDetection()");
2689
2690 int vadDecision = 1;
2691
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002692 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002693
2694 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2695 {
2696 OnRxVadDetected(vadDecision);
2697 _oldVadDecision = vadDecision;
2698 }
2699
2700 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2701 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2702 vadDecision);
2703 return 0;
2704}
2705
2706int
2707Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2708{
2709 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2710 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002711 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002712
2713 if (_rxVadObserverPtr)
2714 {
2715 _engineStatisticsPtr->SetLastError(
2716 VE_INVALID_OPERATION, kTraceError,
2717 "RegisterRxVadObserver() observer already enabled");
2718 return -1;
2719 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002720 _rxVadObserverPtr = &observer;
2721 _RxVadDetection = true;
2722 return 0;
2723}
2724
2725int
2726Channel::DeRegisterRxVadObserver()
2727{
2728 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2729 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002730 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002731
2732 if (!_rxVadObserverPtr)
2733 {
2734 _engineStatisticsPtr->SetLastError(
2735 VE_INVALID_OPERATION, kTraceWarning,
2736 "DeRegisterRxVadObserver() observer already disabled");
2737 return 0;
2738 }
2739 _rxVadObserverPtr = NULL;
2740 _RxVadDetection = false;
2741 return 0;
2742}
2743
2744int
2745Channel::VoiceActivityIndicator(int &activity)
2746{
2747 activity = _sendFrameType;
2748
2749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002750 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002751 return 0;
2752}
2753
2754#ifdef WEBRTC_VOICE_ENGINE_AGC
2755
2756int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002757Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002758{
2759 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2760 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2761 (int)enable, (int)mode);
2762
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002763 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002764 switch (mode)
2765 {
2766 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002767 break;
2768 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002769 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002770 break;
2771 case kAgcFixedDigital:
2772 agcMode = GainControl::kFixedDigital;
2773 break;
2774 case kAgcAdaptiveDigital:
2775 agcMode =GainControl::kAdaptiveDigital;
2776 break;
2777 default:
2778 _engineStatisticsPtr->SetLastError(
2779 VE_INVALID_ARGUMENT, kTraceError,
2780 "SetRxAgcStatus() invalid Agc mode");
2781 return -1;
2782 }
2783
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002784 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002785 {
2786 _engineStatisticsPtr->SetLastError(
2787 VE_APM_ERROR, kTraceError,
2788 "SetRxAgcStatus() failed to set Agc mode");
2789 return -1;
2790 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002791 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002792 {
2793 _engineStatisticsPtr->SetLastError(
2794 VE_APM_ERROR, kTraceError,
2795 "SetRxAgcStatus() failed to set Agc state");
2796 return -1;
2797 }
2798
2799 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002800 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002801
2802 return 0;
2803}
2804
2805int
2806Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2807{
2808 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2809 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2810
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002811 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002812 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002813 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002814
2815 enabled = enable;
2816
2817 switch (agcMode)
2818 {
2819 case GainControl::kFixedDigital:
2820 mode = kAgcFixedDigital;
2821 break;
2822 case GainControl::kAdaptiveDigital:
2823 mode = kAgcAdaptiveDigital;
2824 break;
2825 default:
2826 _engineStatisticsPtr->SetLastError(
2827 VE_APM_ERROR, kTraceError,
2828 "GetRxAgcStatus() invalid Agc mode");
2829 return -1;
2830 }
2831
2832 return 0;
2833}
2834
2835int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002836Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002837{
2838 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2839 "Channel::SetRxAgcConfig()");
2840
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002841 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002842 config.targetLeveldBOv) != 0)
2843 {
2844 _engineStatisticsPtr->SetLastError(
2845 VE_APM_ERROR, kTraceError,
2846 "SetRxAgcConfig() failed to set target peak |level|"
2847 "(or envelope) of the Agc");
2848 return -1;
2849 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002850 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002851 config.digitalCompressionGaindB) != 0)
2852 {
2853 _engineStatisticsPtr->SetLastError(
2854 VE_APM_ERROR, kTraceError,
2855 "SetRxAgcConfig() failed to set the range in |gain| the"
2856 " digital compression stage may apply");
2857 return -1;
2858 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002859 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002860 config.limiterEnable) != 0)
2861 {
2862 _engineStatisticsPtr->SetLastError(
2863 VE_APM_ERROR, kTraceError,
2864 "SetRxAgcConfig() failed to set hard limiter to the signal");
2865 return -1;
2866 }
2867
2868 return 0;
2869}
2870
2871int
2872Channel::GetRxAgcConfig(AgcConfig& config)
2873{
2874 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2875 "Channel::GetRxAgcConfig(config=%?)");
2876
2877 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002878 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002879 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002880 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002881 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002882 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002883
2884 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2885 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2886 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2887 " limiterEnable=%d",
2888 config.targetLeveldBOv,
2889 config.digitalCompressionGaindB,
2890 config.limiterEnable);
2891
2892 return 0;
2893}
2894
2895#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2896
2897#ifdef WEBRTC_VOICE_ENGINE_NR
2898
2899int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002900Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002901{
2902 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2903 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2904 (int)enable, (int)mode);
2905
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002906 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002907 switch (mode)
2908 {
2909
2910 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002911 break;
2912 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002913 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002914 break;
2915 case kNsConference:
2916 nsLevel = NoiseSuppression::kHigh;
2917 break;
2918 case kNsLowSuppression:
2919 nsLevel = NoiseSuppression::kLow;
2920 break;
2921 case kNsModerateSuppression:
2922 nsLevel = NoiseSuppression::kModerate;
2923 break;
2924 case kNsHighSuppression:
2925 nsLevel = NoiseSuppression::kHigh;
2926 break;
2927 case kNsVeryHighSuppression:
2928 nsLevel = NoiseSuppression::kVeryHigh;
2929 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002930 }
2931
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002932 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002933 != 0)
2934 {
2935 _engineStatisticsPtr->SetLastError(
2936 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002937 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002938 return -1;
2939 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002940 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 {
2942 _engineStatisticsPtr->SetLastError(
2943 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002944 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002945 return -1;
2946 }
2947
2948 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002949 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002950
2951 return 0;
2952}
2953
2954int
2955Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2956{
2957 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2958 "Channel::GetRxNsStatus(enable=?, mode=?)");
2959
2960 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002961 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002962 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002963 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002964
2965 enabled = enable;
2966
2967 switch (ncLevel)
2968 {
2969 case NoiseSuppression::kLow:
2970 mode = kNsLowSuppression;
2971 break;
2972 case NoiseSuppression::kModerate:
2973 mode = kNsModerateSuppression;
2974 break;
2975 case NoiseSuppression::kHigh:
2976 mode = kNsHighSuppression;
2977 break;
2978 case NoiseSuppression::kVeryHigh:
2979 mode = kNsVeryHighSuppression;
2980 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002981 }
2982
2983 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2984 VoEId(_instanceId,_channelId),
2985 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2986 return 0;
2987}
2988
2989#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2990
2991int
niklase@google.com470e71d2011-07-07 08:21:25 +00002992Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
2993{
2994 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2995 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002996 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002997
2998 if (_rtcpObserverPtr)
2999 {
3000 _engineStatisticsPtr->SetLastError(
3001 VE_INVALID_OPERATION, kTraceError,
3002 "RegisterRTCPObserver() observer already enabled");
3003 return -1;
3004 }
3005
3006 _rtcpObserverPtr = &observer;
3007 _rtcpObserver = true;
3008
3009 return 0;
3010}
3011
3012int
3013Channel::DeRegisterRTCPObserver()
3014{
3015 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3016 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003017 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003018
3019 if (!_rtcpObserverPtr)
3020 {
3021 _engineStatisticsPtr->SetLastError(
3022 VE_INVALID_OPERATION, kTraceWarning,
3023 "DeRegisterRTCPObserver() observer already disabled");
3024 return 0;
3025 }
3026
3027 _rtcpObserver = false;
3028 _rtcpObserverPtr = NULL;
3029
3030 return 0;
3031}
3032
3033int
3034Channel::SetLocalSSRC(unsigned int ssrc)
3035{
3036 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3037 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003038 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003039 {
3040 _engineStatisticsPtr->SetLastError(
3041 VE_ALREADY_SENDING, kTraceError,
3042 "SetLocalSSRC() already sending");
3043 return -1;
3044 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00003045 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00003046 return 0;
3047}
3048
3049int
3050Channel::GetLocalSSRC(unsigned int& ssrc)
3051{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003052 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003053 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3054 VoEId(_instanceId,_channelId),
3055 "GetLocalSSRC() => ssrc=%lu", ssrc);
3056 return 0;
3057}
3058
3059int
3060Channel::GetRemoteSSRC(unsigned int& ssrc)
3061{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003062 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003063 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3064 VoEId(_instanceId,_channelId),
3065 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3066 return 0;
3067}
3068
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003069int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003070 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003071 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003072}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003073
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003074int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3075 unsigned char id) {
3076 rtp_header_parser_->DeregisterRtpHeaderExtension(
3077 kRtpExtensionAudioLevel);
3078 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3079 kRtpExtensionAudioLevel, id)) {
3080 return -1;
3081 }
3082 return 0;
3083}
3084
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003085int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3086 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3087}
3088
3089int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3090 rtp_header_parser_->DeregisterRtpHeaderExtension(
3091 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003092 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3093 kRtpExtensionAbsoluteSendTime, id)) {
3094 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003095 }
3096 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003097}
3098
3099int
3100Channel::SetRTCPStatus(bool enable)
3101{
3102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3103 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003104 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003105 kRtcpCompound : kRtcpOff) != 0)
3106 {
3107 _engineStatisticsPtr->SetLastError(
3108 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3109 "SetRTCPStatus() failed to set RTCP status");
3110 return -1;
3111 }
3112 return 0;
3113}
3114
3115int
3116Channel::GetRTCPStatus(bool& enabled)
3117{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003118 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003119 enabled = (method != kRtcpOff);
3120 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3121 VoEId(_instanceId,_channelId),
3122 "GetRTCPStatus() => enabled=%d", enabled);
3123 return 0;
3124}
3125
3126int
3127Channel::SetRTCP_CNAME(const char cName[256])
3128{
3129 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3130 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003131 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003132 {
3133 _engineStatisticsPtr->SetLastError(
3134 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3135 "SetRTCP_CNAME() failed to set RTCP CNAME");
3136 return -1;
3137 }
3138 return 0;
3139}
3140
3141int
niklase@google.com470e71d2011-07-07 08:21:25 +00003142Channel::GetRemoteRTCP_CNAME(char cName[256])
3143{
3144 if (cName == NULL)
3145 {
3146 _engineStatisticsPtr->SetLastError(
3147 VE_INVALID_ARGUMENT, kTraceError,
3148 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3149 return -1;
3150 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003151 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003152 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003153 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003154 {
3155 _engineStatisticsPtr->SetLastError(
3156 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3157 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3158 return -1;
3159 }
3160 strcpy(cName, cname);
3161 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3162 VoEId(_instanceId, _channelId),
3163 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3164 return 0;
3165}
3166
3167int
3168Channel::GetRemoteRTCPData(
3169 unsigned int& NTPHigh,
3170 unsigned int& NTPLow,
3171 unsigned int& timestamp,
3172 unsigned int& playoutTimestamp,
3173 unsigned int* jitter,
3174 unsigned short* fractionLost)
3175{
3176 // --- Information from sender info in received Sender Reports
3177
3178 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003179 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003180 {
3181 _engineStatisticsPtr->SetLastError(
3182 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003183 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003184 "side");
3185 return -1;
3186 }
3187
3188 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3189 // and octet count)
3190 NTPHigh = senderInfo.NTPseconds;
3191 NTPLow = senderInfo.NTPfraction;
3192 timestamp = senderInfo.RTPtimeStamp;
3193
3194 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3195 VoEId(_instanceId, _channelId),
3196 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3197 "timestamp=%lu",
3198 NTPHigh, NTPLow, timestamp);
3199
3200 // --- Locally derived information
3201
3202 // This value is updated on each incoming RTCP packet (0 when no packet
3203 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003204 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003205
3206 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3207 VoEId(_instanceId, _channelId),
3208 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003209 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003210
3211 if (NULL != jitter || NULL != fractionLost)
3212 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003213 // Get all RTCP receiver report blocks that have been received on this
3214 // channel. If we receive RTP packets from a remote source we know the
3215 // remote SSRC and use the report block from him.
3216 // Otherwise use the first report block.
3217 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003218 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003219 remote_stats.empty()) {
3220 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3221 VoEId(_instanceId, _channelId),
3222 "GetRemoteRTCPData() failed to measure statistics due"
3223 " to lack of received RTP and/or RTCP packets");
3224 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003225 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003226
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003227 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003228 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3229 for (; it != remote_stats.end(); ++it) {
3230 if (it->remoteSSRC == remoteSSRC)
3231 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003232 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003233
3234 if (it == remote_stats.end()) {
3235 // If we have not received any RTCP packets from this SSRC it probably
3236 // means that we have not received any RTP packets.
3237 // Use the first received report block instead.
3238 it = remote_stats.begin();
3239 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003240 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003241
xians@webrtc.org79af7342012-01-31 12:22:14 +00003242 if (jitter) {
3243 *jitter = it->jitter;
3244 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3245 VoEId(_instanceId, _channelId),
3246 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3247 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003248
xians@webrtc.org79af7342012-01-31 12:22:14 +00003249 if (fractionLost) {
3250 *fractionLost = it->fractionLost;
3251 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3252 VoEId(_instanceId, _channelId),
3253 "GetRemoteRTCPData() => fractionLost = %lu",
3254 *fractionLost);
3255 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003256 }
3257 return 0;
3258}
3259
3260int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003261Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003262 unsigned int name,
3263 const char* data,
3264 unsigned short dataLengthInBytes)
3265{
3266 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3267 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003268 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 {
3270 _engineStatisticsPtr->SetLastError(
3271 VE_NOT_SENDING, kTraceError,
3272 "SendApplicationDefinedRTCPPacket() not sending");
3273 return -1;
3274 }
3275 if (NULL == data)
3276 {
3277 _engineStatisticsPtr->SetLastError(
3278 VE_INVALID_ARGUMENT, kTraceError,
3279 "SendApplicationDefinedRTCPPacket() invalid data value");
3280 return -1;
3281 }
3282 if (dataLengthInBytes % 4 != 0)
3283 {
3284 _engineStatisticsPtr->SetLastError(
3285 VE_INVALID_ARGUMENT, kTraceError,
3286 "SendApplicationDefinedRTCPPacket() invalid length value");
3287 return -1;
3288 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003289 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003290 if (status == kRtcpOff)
3291 {
3292 _engineStatisticsPtr->SetLastError(
3293 VE_RTCP_ERROR, kTraceError,
3294 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3295 return -1;
3296 }
3297
3298 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003299 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003300 subType,
3301 name,
3302 (const unsigned char*) data,
3303 dataLengthInBytes) != 0)
3304 {
3305 _engineStatisticsPtr->SetLastError(
3306 VE_SEND_ERROR, kTraceError,
3307 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3308 return -1;
3309 }
3310 return 0;
3311}
3312
3313int
3314Channel::GetRTPStatistics(
3315 unsigned int& averageJitterMs,
3316 unsigned int& maxJitterMs,
3317 unsigned int& discardedPackets)
3318{
niklase@google.com470e71d2011-07-07 08:21:25 +00003319 // The jitter statistics is updated for each received RTP packet and is
3320 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003321 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3322 // If RTCP is off, there is no timed thread in the RTCP module regularly
3323 // generating new stats, trigger the update manually here instead.
3324 StreamStatistician* statistician =
3325 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3326 if (statistician) {
3327 // Don't use returned statistics, use data from proxy instead so that
3328 // max jitter can be fetched atomically.
3329 RtcpStatistics s;
3330 statistician->GetStatistics(&s, true);
3331 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003332 }
3333
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003334 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003335 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003336 if (playoutFrequency > 0) {
3337 // Scale RTP statistics given the current playout frequency
3338 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3339 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003340 }
3341
3342 discardedPackets = _numberOfDiscardedPackets;
3343
3344 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3345 VoEId(_instanceId, _channelId),
3346 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003347 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003348 averageJitterMs, maxJitterMs, discardedPackets);
3349 return 0;
3350}
3351
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003352int Channel::GetRemoteRTCPReportBlocks(
3353 std::vector<ReportBlock>* report_blocks) {
3354 if (report_blocks == NULL) {
3355 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3356 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3357 return -1;
3358 }
3359
3360 // Get the report blocks from the latest received RTCP Sender or Receiver
3361 // Report. Each element in the vector contains the sender's SSRC and a
3362 // report block according to RFC 3550.
3363 std::vector<RTCPReportBlock> rtcp_report_blocks;
3364 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3365 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3366 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3367 return -1;
3368 }
3369
3370 if (rtcp_report_blocks.empty())
3371 return 0;
3372
3373 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3374 for (; it != rtcp_report_blocks.end(); ++it) {
3375 ReportBlock report_block;
3376 report_block.sender_SSRC = it->remoteSSRC;
3377 report_block.source_SSRC = it->sourceSSRC;
3378 report_block.fraction_lost = it->fractionLost;
3379 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3380 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3381 report_block.interarrival_jitter = it->jitter;
3382 report_block.last_SR_timestamp = it->lastSR;
3383 report_block.delay_since_last_SR = it->delaySinceLastSR;
3384 report_blocks->push_back(report_block);
3385 }
3386 return 0;
3387}
3388
niklase@google.com470e71d2011-07-07 08:21:25 +00003389int
3390Channel::GetRTPStatistics(CallStatistics& stats)
3391{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003392 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003393
3394 // The jitter statistics is updated for each received RTP packet and is
3395 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003396 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003397 StreamStatistician* statistician =
3398 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3399 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003400 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3401 _engineStatisticsPtr->SetLastError(
3402 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3403 "GetRTPStatistics() failed to read RTP statistics from the "
3404 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003405 }
3406
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003407 stats.fractionLost = statistics.fraction_lost;
3408 stats.cumulativeLost = statistics.cumulative_lost;
3409 stats.extendedMax = statistics.extended_max_sequence_number;
3410 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003411
3412 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3413 VoEId(_instanceId, _channelId),
3414 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003415 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003416 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3417 stats.jitterSamples);
3418
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003419 // --- RTT
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00003420 stats.rttMs = GetRTT();
niklase@google.com470e71d2011-07-07 08:21:25 +00003421
3422 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3423 VoEId(_instanceId, _channelId),
3424 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3425
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003426 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003427
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003428 uint32_t bytesSent(0);
3429 uint32_t packetsSent(0);
3430 uint32_t bytesReceived(0);
3431 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003432
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003433 if (statistician) {
3434 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3435 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003436
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003437 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003438 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003439 {
3440 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3441 VoEId(_instanceId, _channelId),
3442 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003443 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003444 }
3445
3446 stats.bytesSent = bytesSent;
3447 stats.packetsSent = packetsSent;
3448 stats.bytesReceived = bytesReceived;
3449 stats.packetsReceived = packetsReceived;
3450
3451 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3452 VoEId(_instanceId, _channelId),
3453 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003454 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003455 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3456 stats.packetsReceived);
3457
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003458 // --- Timestamps
3459 {
3460 CriticalSectionScoped lock(ts_stats_lock_.get());
3461 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3462 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003463 return 0;
3464}
3465
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003466int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003467 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003468 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003469
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003470 if (enable) {
3471 if (redPayloadtype < 0 || redPayloadtype > 127) {
3472 _engineStatisticsPtr->SetLastError(
3473 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003474 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003475 return -1;
3476 }
3477
3478 if (SetRedPayloadType(redPayloadtype) < 0) {
3479 _engineStatisticsPtr->SetLastError(
3480 VE_CODEC_ERROR, kTraceError,
3481 "SetSecondarySendCodec() Failed to register RED ACM");
3482 return -1;
3483 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003484 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003485
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003486 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003487 _engineStatisticsPtr->SetLastError(
3488 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003489 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003490 return -1;
3491 }
3492 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003493}
3494
3495int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003496Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003497{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003498 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003499 if (enabled)
3500 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003501 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003502 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003503 {
3504 _engineStatisticsPtr->SetLastError(
3505 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003506 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003507 "module");
3508 return -1;
3509 }
3510 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3511 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003512 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003513 enabled, redPayloadtype);
3514 return 0;
3515 }
3516 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3517 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003518 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003519 return 0;
3520}
3521
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003522int Channel::SetCodecFECStatus(bool enable) {
3523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3524 "Channel::SetCodecFECStatus()");
3525
3526 if (audio_coding_->SetCodecFEC(enable) != 0) {
3527 _engineStatisticsPtr->SetLastError(
3528 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3529 "SetCodecFECStatus() failed to set FEC state");
3530 return -1;
3531 }
3532 return 0;
3533}
3534
3535bool Channel::GetCodecFECStatus() {
3536 bool enabled = audio_coding_->CodecFEC();
3537 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3538 VoEId(_instanceId, _channelId),
3539 "GetCodecFECStatus() => enabled=%d", enabled);
3540 return enabled;
3541}
3542
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003543void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3544 // None of these functions can fail.
3545 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003546 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3547 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003548 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003549 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003550 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003551 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003552}
3553
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003554// Called when we are missing one or more packets.
3555int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003556 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3557}
3558
niklase@google.com470e71d2011-07-07 08:21:25 +00003559int
niklase@google.com470e71d2011-07-07 08:21:25 +00003560Channel::StartRTPDump(const char fileNameUTF8[1024],
3561 RTPDirections direction)
3562{
3563 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3564 "Channel::StartRTPDump()");
3565 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3566 {
3567 _engineStatisticsPtr->SetLastError(
3568 VE_INVALID_ARGUMENT, kTraceError,
3569 "StartRTPDump() invalid RTP direction");
3570 return -1;
3571 }
3572 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3573 &_rtpDumpIn : &_rtpDumpOut;
3574 if (rtpDumpPtr == NULL)
3575 {
3576 assert(false);
3577 return -1;
3578 }
3579 if (rtpDumpPtr->IsActive())
3580 {
3581 rtpDumpPtr->Stop();
3582 }
3583 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3584 {
3585 _engineStatisticsPtr->SetLastError(
3586 VE_BAD_FILE, kTraceError,
3587 "StartRTPDump() failed to create file");
3588 return -1;
3589 }
3590 return 0;
3591}
3592
3593int
3594Channel::StopRTPDump(RTPDirections direction)
3595{
3596 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3597 "Channel::StopRTPDump()");
3598 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3599 {
3600 _engineStatisticsPtr->SetLastError(
3601 VE_INVALID_ARGUMENT, kTraceError,
3602 "StopRTPDump() invalid RTP direction");
3603 return -1;
3604 }
3605 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3606 &_rtpDumpIn : &_rtpDumpOut;
3607 if (rtpDumpPtr == NULL)
3608 {
3609 assert(false);
3610 return -1;
3611 }
3612 if (!rtpDumpPtr->IsActive())
3613 {
3614 return 0;
3615 }
3616 return rtpDumpPtr->Stop();
3617}
3618
3619bool
3620Channel::RTPDumpIsActive(RTPDirections direction)
3621{
3622 if ((direction != kRtpIncoming) &&
3623 (direction != kRtpOutgoing))
3624 {
3625 _engineStatisticsPtr->SetLastError(
3626 VE_INVALID_ARGUMENT, kTraceError,
3627 "RTPDumpIsActive() invalid RTP direction");
3628 return false;
3629 }
3630 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3631 &_rtpDumpIn : &_rtpDumpOut;
3632 return rtpDumpPtr->IsActive();
3633}
3634
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003635void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3636 int video_channel) {
3637 CriticalSectionScoped cs(&_callbackCritSect);
3638 if (vie_network_) {
3639 vie_network_->Release();
3640 vie_network_ = NULL;
3641 }
3642 video_channel_ = -1;
3643
3644 if (vie_network != NULL && video_channel != -1) {
3645 vie_network_ = vie_network;
3646 video_channel_ = video_channel;
3647 }
3648}
3649
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003650uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003651Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003652{
3653 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003654 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003655 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003656 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003657 return 0;
3658}
3659
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003660void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003661 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003662 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003663 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003664 CodecInst codec;
3665 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003666
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003667 if (!mono_recording_audio_.get()) {
3668 // Temporary space for DownConvertToCodecFormat.
3669 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003670 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003671 DownConvertToCodecFormat(audio_data,
3672 number_of_frames,
3673 number_of_channels,
3674 sample_rate,
3675 codec.channels,
3676 codec.plfreq,
3677 mono_recording_audio_.get(),
3678 &input_resampler_,
3679 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003680}
3681
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003682uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003683Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003684{
3685 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3686 "Channel::PrepareEncodeAndSend()");
3687
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003688 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003689 {
3690 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3691 "Channel::PrepareEncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003692 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003693 }
3694
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003695 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003696 {
3697 MixOrReplaceAudioWithFile(mixingFrequency);
3698 }
3699
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003700 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3701 if (is_muted) {
3702 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003703 }
3704
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003705 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003706 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003707 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003708 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003709 if (_inputExternalMediaCallbackPtr)
3710 {
3711 _inputExternalMediaCallbackPtr->Process(
3712 _channelId,
3713 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003714 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003715 _audioFrame.samples_per_channel_,
3716 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003717 isStereo);
3718 }
3719 }
3720
3721 InsertInbandDtmfTone();
3722
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003723 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003724 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003725 if (is_muted) {
3726 rms_level_.ProcessMuted(length);
3727 } else {
3728 rms_level_.Process(_audioFrame.data_, length);
3729 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003730 }
3731
niklase@google.com470e71d2011-07-07 08:21:25 +00003732 return 0;
3733}
3734
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003735uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003736Channel::EncodeAndSend()
3737{
3738 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3739 "Channel::EncodeAndSend()");
3740
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003741 assert(_audioFrame.num_channels_ <= 2);
3742 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003743 {
3744 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3745 "Channel::EncodeAndSend() invalid audio frame");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003746 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003747 }
3748
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003749 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003750
3751 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3752
3753 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003754 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003755 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003756 {
3757 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3758 "Channel::EncodeAndSend() ACM encoding failed");
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00003759 return 0xFFFFFFFF;
niklase@google.com470e71d2011-07-07 08:21:25 +00003760 }
3761
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003762 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003763
3764 // --- Encode if complete frame is ready
3765
3766 // This call will trigger AudioPacketizationCallback::SendData if encoding
3767 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003768 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003769}
3770
3771int Channel::RegisterExternalMediaProcessing(
3772 ProcessingTypes type,
3773 VoEMediaProcess& processObject)
3774{
3775 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3776 "Channel::RegisterExternalMediaProcessing()");
3777
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003778 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003779
3780 if (kPlaybackPerChannel == type)
3781 {
3782 if (_outputExternalMediaCallbackPtr)
3783 {
3784 _engineStatisticsPtr->SetLastError(
3785 VE_INVALID_OPERATION, kTraceError,
3786 "Channel::RegisterExternalMediaProcessing() "
3787 "output external media already enabled");
3788 return -1;
3789 }
3790 _outputExternalMediaCallbackPtr = &processObject;
3791 _outputExternalMedia = true;
3792 }
3793 else if (kRecordingPerChannel == type)
3794 {
3795 if (_inputExternalMediaCallbackPtr)
3796 {
3797 _engineStatisticsPtr->SetLastError(
3798 VE_INVALID_OPERATION, kTraceError,
3799 "Channel::RegisterExternalMediaProcessing() "
3800 "output external media already enabled");
3801 return -1;
3802 }
3803 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003804 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003805 }
3806 return 0;
3807}
3808
3809int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3810{
3811 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3812 "Channel::DeRegisterExternalMediaProcessing()");
3813
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003814 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003815
3816 if (kPlaybackPerChannel == type)
3817 {
3818 if (!_outputExternalMediaCallbackPtr)
3819 {
3820 _engineStatisticsPtr->SetLastError(
3821 VE_INVALID_OPERATION, kTraceWarning,
3822 "Channel::DeRegisterExternalMediaProcessing() "
3823 "output external media already disabled");
3824 return 0;
3825 }
3826 _outputExternalMedia = false;
3827 _outputExternalMediaCallbackPtr = NULL;
3828 }
3829 else if (kRecordingPerChannel == type)
3830 {
3831 if (!_inputExternalMediaCallbackPtr)
3832 {
3833 _engineStatisticsPtr->SetLastError(
3834 VE_INVALID_OPERATION, kTraceWarning,
3835 "Channel::DeRegisterExternalMediaProcessing() "
3836 "input external media already disabled");
3837 return 0;
3838 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003839 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003840 _inputExternalMediaCallbackPtr = NULL;
3841 }
3842
3843 return 0;
3844}
3845
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003846int Channel::SetExternalMixing(bool enabled) {
3847 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3848 "Channel::SetExternalMixing(enabled=%d)", enabled);
3849
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003850 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003851 {
3852 _engineStatisticsPtr->SetLastError(
3853 VE_INVALID_OPERATION, kTraceError,
3854 "Channel::SetExternalMixing() "
3855 "external mixing cannot be changed while playing.");
3856 return -1;
3857 }
3858
3859 _externalMixing = enabled;
3860
3861 return 0;
3862}
3863
niklase@google.com470e71d2011-07-07 08:21:25 +00003864int
niklase@google.com470e71d2011-07-07 08:21:25 +00003865Channel::GetNetworkStatistics(NetworkStatistics& stats)
3866{
3867 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3868 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003869 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003870 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003871 if (return_value >= 0) {
3872 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3873 }
3874 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003875}
3876
wu@webrtc.org24301a62013-12-13 19:17:43 +00003877void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3878 audio_coding_->GetDecodingCallStatistics(stats);
3879}
3880
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003881bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3882 int* playout_buffer_delay_ms) const {
3883 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003884 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003885 "Channel::GetDelayEstimate() no valid estimate.");
3886 return false;
3887 }
3888 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3889 _recPacketDelayMs;
3890 *playout_buffer_delay_ms = playout_delay_ms_;
3891 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3892 "Channel::GetDelayEstimate()");
3893 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003894}
3895
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003896int Channel::SetInitialPlayoutDelay(int delay_ms)
3897{
3898 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3899 "Channel::SetInitialPlayoutDelay()");
3900 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3901 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3902 {
3903 _engineStatisticsPtr->SetLastError(
3904 VE_INVALID_ARGUMENT, kTraceError,
3905 "SetInitialPlayoutDelay() invalid min delay");
3906 return -1;
3907 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003908 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003909 {
3910 _engineStatisticsPtr->SetLastError(
3911 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3912 "SetInitialPlayoutDelay() failed to set min playout delay");
3913 return -1;
3914 }
3915 return 0;
3916}
3917
3918
niklase@google.com470e71d2011-07-07 08:21:25 +00003919int
3920Channel::SetMinimumPlayoutDelay(int delayMs)
3921{
3922 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3923 "Channel::SetMinimumPlayoutDelay()");
3924 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3925 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3926 {
3927 _engineStatisticsPtr->SetLastError(
3928 VE_INVALID_ARGUMENT, kTraceError,
3929 "SetMinimumPlayoutDelay() invalid min delay");
3930 return -1;
3931 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003932 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003933 {
3934 _engineStatisticsPtr->SetLastError(
3935 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3936 "SetMinimumPlayoutDelay() failed to set min playout delay");
3937 return -1;
3938 }
3939 return 0;
3940}
3941
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003942void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3943 uint32_t playout_timestamp = 0;
3944
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003945 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
turaj@webrtc.org1ebd2e92014-07-25 17:50:10 +00003946 // This can happen if this channel has not been received any RTP packet. In
3947 // this case, NetEq is not capable of computing playout timestamp.
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003948 return;
3949 }
3950
3951 uint16_t delay_ms = 0;
3952 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3953 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3954 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3955 " delay from the ADM");
3956 _engineStatisticsPtr->SetLastError(
3957 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3958 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3959 return;
3960 }
3961
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003962 jitter_buffer_playout_timestamp_ = playout_timestamp;
3963
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003964 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00003965 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966
3967 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3968 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3969 playout_timestamp);
3970
3971 if (rtcp) {
3972 playout_timestamp_rtcp_ = playout_timestamp;
3973 } else {
3974 playout_timestamp_rtp_ = playout_timestamp;
3975 }
3976 playout_delay_ms_ = delay_ms;
3977}
3978
3979int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3980 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3981 "Channel::GetPlayoutTimestamp()");
3982 if (playout_timestamp_rtp_ == 0) {
3983 _engineStatisticsPtr->SetLastError(
3984 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3985 "GetPlayoutTimestamp() failed to retrieve timestamp");
3986 return -1;
3987 }
3988 timestamp = playout_timestamp_rtp_;
3989 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3990 VoEId(_instanceId,_channelId),
3991 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3992 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003993}
3994
3995int
3996Channel::SetInitTimestamp(unsigned int timestamp)
3997{
3998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3999 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004000 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004001 {
4002 _engineStatisticsPtr->SetLastError(
4003 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4004 return -1;
4005 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004006 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004007 {
4008 _engineStatisticsPtr->SetLastError(
4009 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4010 "SetInitTimestamp() failed to set timestamp");
4011 return -1;
4012 }
4013 return 0;
4014}
4015
4016int
4017Channel::SetInitSequenceNumber(short sequenceNumber)
4018{
4019 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4020 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004021 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004022 {
4023 _engineStatisticsPtr->SetLastError(
4024 VE_SENDING, kTraceError,
4025 "SetInitSequenceNumber() already sending");
4026 return -1;
4027 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004028 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004029 {
4030 _engineStatisticsPtr->SetLastError(
4031 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4032 "SetInitSequenceNumber() failed to set sequence number");
4033 return -1;
4034 }
4035 return 0;
4036}
4037
4038int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004039Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004040{
4041 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4042 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004043 *rtpRtcpModule = _rtpRtcpModule.get();
4044 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004045 return 0;
4046}
4047
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004048// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4049// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004050int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004051Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004052{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004053 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004054 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004055
4056 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004057 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004058
4059 if (_inputFilePlayerPtr == NULL)
4060 {
4061 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4062 VoEId(_instanceId, _channelId),
4063 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4064 " doesnt exist");
4065 return -1;
4066 }
4067
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004068 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004069 fileSamples,
4070 mixingFrequency) == -1)
4071 {
4072 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4073 VoEId(_instanceId, _channelId),
4074 "Channel::MixOrReplaceAudioWithFile() file mixing "
4075 "failed");
4076 return -1;
4077 }
4078 if (fileSamples == 0)
4079 {
4080 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4081 VoEId(_instanceId, _channelId),
4082 "Channel::MixOrReplaceAudioWithFile() file is ended");
4083 return 0;
4084 }
4085 }
4086
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004087 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004088
4089 if (_mixFileWithMicrophone)
4090 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004091 // Currently file stream is always mono.
4092 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004093 MixWithSat(_audioFrame.data_,
4094 _audioFrame.num_channels_,
4095 fileBuffer.get(),
4096 1,
4097 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004098 }
4099 else
4100 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004101 // Replace ACM audio with file.
4102 // Currently file stream is always mono.
4103 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004104 _audioFrame.UpdateFrame(_channelId,
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +00004105 0xFFFFFFFF,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004106 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004107 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004108 mixingFrequency,
4109 AudioFrame::kNormalSpeech,
4110 AudioFrame::kVadUnknown,
4111 1);
4112
4113 }
4114 return 0;
4115}
4116
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004117int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004118Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004119 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004120{
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00004121 assert(mixingFrequency <= 48000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004122
minyue@webrtc.org2a8df7c2014-08-06 10:05:19 +00004123 scoped_ptr<int16_t[]> fileBuffer(new int16_t[960]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004124 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004125
4126 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004127 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004128
4129 if (_outputFilePlayerPtr == NULL)
4130 {
4131 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4132 VoEId(_instanceId, _channelId),
4133 "Channel::MixAudioWithFile() file mixing failed");
4134 return -1;
4135 }
4136
4137 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004138 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004139 fileSamples,
4140 mixingFrequency) == -1)
4141 {
4142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4143 VoEId(_instanceId, _channelId),
4144 "Channel::MixAudioWithFile() file mixing failed");
4145 return -1;
4146 }
4147 }
4148
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004149 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004150 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004151 // Currently file stream is always mono.
4152 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004153 MixWithSat(audioFrame.data_,
4154 audioFrame.num_channels_,
4155 fileBuffer.get(),
4156 1,
4157 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004158 }
4159 else
4160 {
4161 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004162 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004163 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004164 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004165 return -1;
4166 }
4167
4168 return 0;
4169}
4170
4171int
4172Channel::InsertInbandDtmfTone()
4173{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004174 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004175 if (_inbandDtmfQueue.PendingDtmf() &&
4176 !_inbandDtmfGenerator.IsAddingTone() &&
4177 _inbandDtmfGenerator.DelaySinceLastTone() >
4178 kMinTelephoneEventSeparationMs)
4179 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004180 int8_t eventCode(0);
4181 uint16_t lengthMs(0);
4182 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004183
4184 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4185 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4186 if (_playInbandDtmfEvent)
4187 {
4188 // Add tone to output mixer using a reduced length to minimize
4189 // risk of echo.
4190 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4191 attenuationDb);
4192 }
4193 }
4194
4195 if (_inbandDtmfGenerator.IsAddingTone())
4196 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004197 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004198 _inbandDtmfGenerator.GetSampleRate(frequency);
4199
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004200 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004201 {
4202 // Update sample rate of Dtmf tone since the mixing frequency
4203 // has changed.
4204 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004205 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004206 // Reset the tone to be added taking the new sample rate into
4207 // account.
4208 _inbandDtmfGenerator.ResetTone();
4209 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004210
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004211 int16_t toneBuffer[320];
4212 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004213 // Get 10ms tone segment and set time since last tone to zero
4214 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4215 {
4216 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4217 VoEId(_instanceId, _channelId),
4218 "Channel::EncodeAndSend() inserting Dtmf failed");
4219 return -1;
4220 }
4221
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004222 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004223 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004224 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004225 sample++)
4226 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004227 for (int channel = 0;
4228 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004229 channel++)
4230 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004231 const int index = sample * _audioFrame.num_channels_ + channel;
4232 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004233 }
4234 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004235
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004236 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004237 } else
4238 {
4239 // Add 10ms to "delay-since-last-tone" counter
4240 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4241 }
4242 return 0;
4243}
4244
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004245int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004246Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4247{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004248 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004249 if (_transportPtr == NULL)
4250 {
4251 return -1;
4252 }
4253 if (!RTCP)
4254 {
4255 return _transportPtr->SendPacket(_channelId, data, len);
4256 }
4257 else
4258 {
4259 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4260 }
4261}
4262
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004263// Called for incoming RTP packets after successful RTP header parsing.
4264void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4265 uint16_t sequence_number) {
4266 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4267 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4268 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004269
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004270 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004271 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004272
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004273 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004274 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004275
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004276 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4277 // every incoming packet.
4278 uint32_t timestamp_diff_ms = (rtp_timestamp -
4279 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004280 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4281 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4282 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4283 // timestamp, the resulting difference is negative, but is set to zero.
4284 // This can happen when a network glitch causes a packet to arrive late,
4285 // and during long comfort noise periods with clock drift.
4286 timestamp_diff_ms = 0;
4287 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004288
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004289 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4290 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004291
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004292 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004293
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004294 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004295
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004296 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4297 _recPacketDelayMs = packet_delay_ms;
4298 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004299
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004300 if (_average_jitter_buffer_delay_us == 0) {
4301 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4302 return;
4303 }
4304
4305 // Filter average delay value using exponential filter (alpha is
4306 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4307 // risk of rounding error) and compensate for it in GetDelayEstimate()
4308 // later.
4309 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4310 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004311}
4312
4313void
4314Channel::RegisterReceiveCodecsToRTPModule()
4315{
4316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4317 "Channel::RegisterReceiveCodecsToRTPModule()");
4318
4319
4320 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004321 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004322
4323 for (int idx = 0; idx < nSupportedCodecs; idx++)
4324 {
4325 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004326 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004327 (rtp_receiver_->RegisterReceivePayload(
4328 codec.plname,
4329 codec.pltype,
4330 codec.plfreq,
4331 codec.channels,
4332 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004333 {
4334 WEBRTC_TRACE(
4335 kTraceWarning,
4336 kTraceVoice,
4337 VoEId(_instanceId, _channelId),
4338 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4339 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4340 codec.plname, codec.pltype, codec.plfreq,
4341 codec.channels, codec.rate);
4342 }
4343 else
4344 {
4345 WEBRTC_TRACE(
4346 kTraceInfo,
4347 kTraceVoice,
4348 VoEId(_instanceId, _channelId),
4349 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004350 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004351 "receiver",
4352 codec.plname, codec.pltype, codec.plfreq,
4353 codec.channels, codec.rate);
4354 }
4355 }
4356}
4357
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004358int Channel::SetSecondarySendCodec(const CodecInst& codec,
4359 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004360 // Sanity check for payload type.
4361 if (red_payload_type < 0 || red_payload_type > 127) {
4362 _engineStatisticsPtr->SetLastError(
4363 VE_PLTYPE_ERROR, kTraceError,
4364 "SetRedPayloadType() invalid RED payload type");
4365 return -1;
4366 }
4367
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004368 if (SetRedPayloadType(red_payload_type) < 0) {
4369 _engineStatisticsPtr->SetLastError(
4370 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4371 "SetSecondarySendCodec() Failed to register RED ACM");
4372 return -1;
4373 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004374 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004375 _engineStatisticsPtr->SetLastError(
4376 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4377 "SetSecondarySendCodec() Failed to register secondary send codec in "
4378 "ACM");
4379 return -1;
4380 }
4381
4382 return 0;
4383}
4384
4385void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004386 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004387}
4388
4389int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004390 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004391 _engineStatisticsPtr->SetLastError(
4392 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4393 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4394 return -1;
4395 }
4396 return 0;
4397}
4398
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004399// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004400int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004401 CodecInst codec;
4402 bool found_red = false;
4403
4404 // Get default RED settings from the ACM database
4405 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4406 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004407 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004408 if (!STR_CASE_CMP(codec.plname, "RED")) {
4409 found_red = true;
4410 break;
4411 }
4412 }
4413
4414 if (!found_red) {
4415 _engineStatisticsPtr->SetLastError(
4416 VE_CODEC_ERROR, kTraceError,
4417 "SetRedPayloadType() RED is not supported");
4418 return -1;
4419 }
4420
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004421 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004422 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004423 _engineStatisticsPtr->SetLastError(
4424 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4425 "SetRedPayloadType() RED registration in ACM module failed");
4426 return -1;
4427 }
4428
4429 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4430 _engineStatisticsPtr->SetLastError(
4431 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4432 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4433 return -1;
4434 }
4435 return 0;
4436}
4437
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004438int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4439 unsigned char id) {
4440 int error = 0;
4441 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4442 if (enable) {
4443 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4444 }
4445 return error;
4446}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004447
wu@webrtc.org94454b72014-06-05 20:34:08 +00004448int32_t Channel::GetPlayoutFrequency() {
4449 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4450 CodecInst current_recive_codec;
4451 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4452 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4453 // Even though the actual sampling rate for G.722 audio is
4454 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4455 // 8,000 Hz because that value was erroneously assigned in
4456 // RFC 1890 and must remain unchanged for backward compatibility.
4457 playout_frequency = 8000;
4458 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4459 // We are resampling Opus internally to 32,000 Hz until all our
4460 // DSP routines can operate at 48,000 Hz, but the RTP clock
4461 // rate for the Opus payload format is standardized to 48,000 Hz,
4462 // because that is the maximum supported decoding sampling rate.
4463 playout_frequency = 48000;
4464 }
4465 }
4466 return playout_frequency;
4467}
4468
minyue@webrtc.org2b58a442014-09-11 07:51:53 +00004469int Channel::GetRTT() const {
4470 RTCPMethod method = _rtpRtcpModule->RTCP();
4471 if (method == kRtcpOff) {
4472 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4473 VoEId(_instanceId, _channelId),
4474 "GetRTPStatistics() RTCP is disabled => valid RTT "
4475 "measurements cannot be retrieved");
4476 return 0;
4477 }
4478 std::vector<RTCPReportBlock> report_blocks;
4479 _rtpRtcpModule->RemoteRTCPStat(&report_blocks);
4480 if (report_blocks.empty()) {
4481 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4482 VoEId(_instanceId, _channelId),
4483 "GetRTPStatistics() failed to measure RTT since no "
4484 "RTCP packets have been received yet");
4485 return 0;
4486 }
4487
4488 uint32_t remoteSSRC = rtp_receiver_->SSRC();
4489 std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
4490 for (; it != report_blocks.end(); ++it) {
4491 if (it->remoteSSRC == remoteSSRC)
4492 break;
4493 }
4494 if (it == report_blocks.end()) {
4495 // We have not received packets with SSRC matching the report blocks.
4496 // To calculate RTT we try with the SSRC of the first report block.
4497 // This is very important for send-only channels where we don't know
4498 // the SSRC of the other end.
4499 remoteSSRC = report_blocks[0].remoteSSRC;
4500 }
4501 uint16_t rtt = 0;
4502 uint16_t avg_rtt = 0;
4503 uint16_t max_rtt= 0;
4504 uint16_t min_rtt = 0;
4505 if (_rtpRtcpModule->RTT(remoteSSRC, &rtt, &avg_rtt, &min_rtt, &max_rtt)
4506 != 0) {
4507 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4508 VoEId(_instanceId, _channelId),
4509 "GetRTPStatistics() failed to retrieve RTT from "
4510 "the RTP/RTCP module");
4511 return 0;
4512 }
4513 return static_cast<int>(rtt);
4514}
4515
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004516} // namespace voe
4517} // namespace webrtc