blob: f99e590ae4b7c5d1b19a76eb4082c87d99c7d85f [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"
wu@webrtc.org82c4b852014-05-20 22:55:01 +000019#include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000020#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
21#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
22#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000023#include "webrtc/modules/utility/interface/audio_frame_operations.h"
24#include "webrtc/modules/utility/interface/process_thread.h"
25#include "webrtc/modules/utility/interface/rtp_dump.h"
26#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
27#include "webrtc/system_wrappers/interface/logging.h"
28#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000029#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000030#include "webrtc/voice_engine/include/voe_base.h"
31#include "webrtc/voice_engine/include/voe_external_media.h"
32#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
33#include "webrtc/voice_engine/output_mixer.h"
34#include "webrtc/voice_engine/statistics.h"
35#include "webrtc/voice_engine/transmit_mixer.h"
36#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000037
38#if defined(_WIN32)
39#include <Qos.h>
40#endif
41
andrew@webrtc.org50419b02012-11-14 19:07:54 +000042namespace webrtc {
43namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000044
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000045// Extend the default RTCP statistics struct with max_jitter, defined as the
46// maximum jitter value seen in an RTCP report block.
47struct ChannelStatistics : public RtcpStatistics {
48 ChannelStatistics() : rtcp(), max_jitter(0) {}
49
50 RtcpStatistics rtcp;
51 uint32_t max_jitter;
52};
53
54// Statistics callback, called at each generation of a new RTCP report block.
55class StatisticsProxy : public RtcpStatisticsCallback {
56 public:
57 StatisticsProxy(uint32_t ssrc)
58 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
59 ssrc_(ssrc) {}
60 virtual ~StatisticsProxy() {}
61
62 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
63 uint32_t ssrc) OVERRIDE {
64 if (ssrc != ssrc_)
65 return;
66
67 CriticalSectionScoped cs(stats_lock_.get());
68 stats_.rtcp = statistics;
69 if (statistics.jitter > stats_.max_jitter) {
70 stats_.max_jitter = statistics.jitter;
71 }
72 }
73
74 void ResetStatistics() {
75 CriticalSectionScoped cs(stats_lock_.get());
76 stats_ = ChannelStatistics();
77 }
78
79 ChannelStatistics GetStats() {
80 CriticalSectionScoped cs(stats_lock_.get());
81 return stats_;
82 }
83
84 private:
85 // StatisticsUpdated calls are triggered from threads in the RTP module,
86 // while GetStats calls can be triggered from the public voice engine API,
87 // hence synchronization is needed.
88 scoped_ptr<CriticalSectionWrapper> stats_lock_;
89 const uint32_t ssrc_;
90 ChannelStatistics stats_;
91};
92
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +000093class VoEBitrateObserver : public BitrateObserver {
94 public:
95 explicit VoEBitrateObserver(Channel* owner)
96 : owner_(owner) {}
97 virtual ~VoEBitrateObserver() {}
98
99 // Implements BitrateObserver.
100 virtual void OnNetworkChanged(const uint32_t bitrate_bps,
101 const uint8_t fraction_lost,
102 const uint32_t rtt) OVERRIDE {
103 // |fraction_lost| has a scale of 0 - 255.
104 owner_->OnNetworkChanged(bitrate_bps, fraction_lost, rtt);
105 }
106
107 private:
108 Channel* owner_;
109};
110
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000111int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000112Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000113 uint8_t payloadType,
114 uint32_t timeStamp,
115 const uint8_t* payloadData,
116 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 const RTPFragmentationHeader* fragmentation)
118{
119 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
120 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
121 " payloadSize=%u, fragmentation=0x%x)",
122 frameType, payloadType, timeStamp, payloadSize, fragmentation);
123
124 if (_includeAudioLevelIndication)
125 {
126 // Store current audio level in the RTP/RTCP module.
127 // The level will be used in combination with voice-activity state
128 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000129 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 }
131
132 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
133 // packetization.
134 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000135 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 payloadType,
137 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000138 // Leaving the time when this frame was
139 // received from the capture device as
140 // undefined for voice for now.
141 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 payloadData,
143 payloadSize,
144 fragmentation) == -1)
145 {
146 _engineStatisticsPtr->SetLastError(
147 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
148 "Channel::SendData() failed to send data to RTP/RTCP module");
149 return -1;
150 }
151
152 _lastLocalTimeStamp = timeStamp;
153 _lastPayloadType = payloadType;
154
155 return 0;
156}
157
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000158int32_t
159Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000160{
161 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
162 "Channel::InFrameType(frameType=%d)", frameType);
163
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000164 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 // 1 indicates speech
166 _sendFrameType = (frameType == 1) ? 1 : 0;
167 return 0;
168}
169
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000170int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000171Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000172{
173 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
174 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
175
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000176 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 if (_rxVadObserverPtr)
178 {
179 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
180 }
181
182 return 0;
183}
184
185int
186Channel::SendPacket(int channel, const void *data, int len)
187{
188 channel = VoEChannelId(channel);
189 assert(channel == _channelId);
190
191 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
192 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
193
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000194 CriticalSectionScoped cs(&_callbackCritSect);
195
niklase@google.com470e71d2011-07-07 08:21:25 +0000196 if (_transportPtr == NULL)
197 {
198 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
199 "Channel::SendPacket() failed to send RTP packet due to"
200 " invalid transport object");
201 return -1;
202 }
203
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000204 uint8_t* bufferToSendPtr = (uint8_t*)data;
205 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
207 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000208 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 {
210 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
211 VoEId(_instanceId,_channelId),
212 "Channel::SendPacket() RTP dump to output file failed");
213 }
214
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000215 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
216 bufferLength);
217 if (n < 0) {
218 std::string transport_name =
219 _externalTransport ? "external transport" : "WebRtc sockets";
220 WEBRTC_TRACE(kTraceError, kTraceVoice,
221 VoEId(_instanceId,_channelId),
222 "Channel::SendPacket() RTP transmission using %s failed",
223 transport_name.c_str());
224 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000225 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000226 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000227}
228
229int
230Channel::SendRTCPPacket(int channel, const void *data, int len)
231{
232 channel = VoEChannelId(channel);
233 assert(channel == _channelId);
234
235 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
236 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
237
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000238 CriticalSectionScoped cs(&_callbackCritSect);
239 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000240 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000241 WEBRTC_TRACE(kTraceError, kTraceVoice,
242 VoEId(_instanceId,_channelId),
243 "Channel::SendRTCPPacket() failed to send RTCP packet"
244 " due to invalid transport object");
245 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246 }
247
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000248 uint8_t* bufferToSendPtr = (uint8_t*)data;
249 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
251 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000252 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 {
254 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
255 VoEId(_instanceId,_channelId),
256 "Channel::SendPacket() RTCP dump to output file failed");
257 }
258
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000259 int n = _transportPtr->SendRTCPPacket(channel,
260 bufferToSendPtr,
261 bufferLength);
262 if (n < 0) {
263 std::string transport_name =
264 _externalTransport ? "external transport" : "WebRtc sockets";
265 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
266 VoEId(_instanceId,_channelId),
267 "Channel::SendRTCPPacket() transmission using %s failed",
268 transport_name.c_str());
269 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000270 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000271 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000272}
273
274void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000275Channel::OnPlayTelephoneEvent(int32_t id,
276 uint8_t event,
277 uint16_t lengthMs,
278 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000279{
280 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
281 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000282 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
284 if (!_playOutbandDtmfEvent || (event > 15))
285 {
286 // Ignore callback since feedback is disabled or event is not a
287 // Dtmf tone event.
288 return;
289 }
290
291 assert(_outputMixerPtr != NULL);
292
293 // Start playing out the Dtmf tone (if playout is enabled).
294 // Reduce length of tone with 80ms to the reduce risk of echo.
295 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
296}
297
298void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000299Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000300{
301 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
302 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000303 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000305 // Update ssrc so that NTP for AV sync can be updated.
306 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000307}
308
pbos@webrtc.org92135212013-05-14 08:31:39 +0000309void Channel::OnIncomingCSRCChanged(int32_t id,
310 uint32_t CSRC,
311 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000312{
313 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
314 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
315 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000316}
317
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000318void Channel::ResetStatistics(uint32_t ssrc) {
319 StreamStatistician* statistician =
320 rtp_receive_statistics_->GetStatistician(ssrc);
321 if (statistician) {
322 statistician->ResetStatistics();
323 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000324 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000325}
326
niklase@google.com470e71d2011-07-07 08:21:25 +0000327void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000328Channel::OnApplicationDataReceived(int32_t id,
329 uint8_t subType,
330 uint32_t name,
331 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000332 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000333{
334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
335 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
336 " name=%u, length=%u)",
337 id, subType, name, length);
338
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000339 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000340 assert(channel == _channelId);
341
342 if (_rtcpObserver)
343 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000344 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345
346 if (_rtcpObserverPtr)
347 {
348 _rtcpObserverPtr->OnApplicationDataReceived(channel,
349 subType,
350 name,
351 data,
352 length);
353 }
354 }
355}
356
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000357int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000358Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000359 int32_t id,
360 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000361 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000362 int frequency,
363 uint8_t channels,
364 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000365{
366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
367 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
368 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
369 id, payloadType, payloadName, frequency, channels, rate);
370
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000371 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000372
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000373 CodecInst receiveCodec = {0};
374 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000377 receiveCodec.plfreq = frequency;
378 receiveCodec.channels = channels;
379 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000380 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000381
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000382 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000383 receiveCodec.pacsize = dummyCodec.pacsize;
384
385 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000386 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 {
388 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000389 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 "Channel::OnInitializeDecoder() invalid codec ("
391 "pt=%d, name=%s) received - 1", payloadType, payloadName);
392 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
393 return -1;
394 }
395
396 return 0;
397}
398
399void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000400Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000401{
402 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
403 "Channel::OnPacketTimeout(id=%d)", id);
404
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000405 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 if (_voiceEngineObserverPtr)
407 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000408 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000410 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 assert(channel == _channelId);
412 // Ensure that next OnReceivedPacket() callback will trigger
413 // a VE_PACKET_RECEIPT_RESTARTED callback.
414 _rtpPacketTimedOut = true;
415 // Deliver callback to the observer
416 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
417 VoEId(_instanceId,_channelId),
418 "Channel::OnPacketTimeout() => "
419 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
420 _voiceEngineObserverPtr->CallbackOnError(channel,
421 VE_RECEIVE_PACKET_TIMEOUT);
422 }
423 }
424}
425
426void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000427Channel::OnReceivedPacket(int32_t id,
428 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000429{
430 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
431 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
432 id, packetType);
433
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000434 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000435
436 // Notify only for the case when we have restarted an RTP session.
437 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
438 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000439 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000440 if (_voiceEngineObserverPtr)
441 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000442 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 assert(channel == _channelId);
444 // Reset timeout mechanism
445 _rtpPacketTimedOut = false;
446 // Deliver callback to the observer
447 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
448 VoEId(_instanceId,_channelId),
449 "Channel::OnPacketTimeout() =>"
450 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
451 _voiceEngineObserverPtr->CallbackOnError(
452 channel,
453 VE_PACKET_RECEIPT_RESTARTED);
454 }
455 }
456}
457
458void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000459Channel::OnPeriodicDeadOrAlive(int32_t id,
460 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000461{
462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
463 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
464
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000465 {
466 CriticalSectionScoped cs(&_callbackCritSect);
467 if (!_connectionObserver)
468 return;
469 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000470
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000471 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 assert(channel == _channelId);
473
474 // Use Alive as default to limit risk of false Dead detections
475 bool isAlive(true);
476
477 // Always mark the connection as Dead when the module reports kRtpDead
478 if (kRtpDead == alive)
479 {
480 isAlive = false;
481 }
482
483 // It is possible that the connection is alive even if no RTP packet has
484 // been received for a long time since the other side might use VAD/DTX
485 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000486 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000487 {
488 // Detect Alive for all NetEQ states except for the case when we are
489 // in PLC_CNG state.
490 // PLC_CNG <=> background noise only due to long expand or error.
491 // Note that, the case where the other side stops sending during CNG
492 // state will be detected as Alive. Dead is is not set until after
493 // missing RTCP packets for at least twelve seconds (handled
494 // internally by the RTP/RTCP module).
495 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
496 }
497
niklase@google.com470e71d2011-07-07 08:21:25 +0000498 // Send callback to the registered observer
499 if (_connectionObserver)
500 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000501 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000502 if (_connectionObserverPtr)
503 {
504 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
505 }
506 }
507}
508
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000509int32_t
510Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000511 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000512 const WebRtcRTPHeader* rtpHeader)
513{
514 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
515 "Channel::OnReceivedPayloadData(payloadSize=%d,"
516 " payloadType=%u, audioChannel=%u)",
517 payloadSize,
518 rtpHeader->header.payloadType,
519 rtpHeader->type.Audio.channel);
520
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000521 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000522 {
523 // Avoid inserting into NetEQ when we are not playing. Count the
524 // packet as discarded.
525 WEBRTC_TRACE(kTraceStream, kTraceVoice,
526 VoEId(_instanceId, _channelId),
527 "received packet is discarded since playing is not"
528 " activated");
529 _numberOfDiscardedPackets++;
530 return 0;
531 }
532
533 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000534 if (audio_coding_->IncomingPacket(payloadData,
535 payloadSize,
536 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000537 {
538 _engineStatisticsPtr->SetLastError(
539 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
540 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
541 return -1;
542 }
543
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000544 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000545 UpdatePacketDelay(rtpHeader->header.timestamp,
546 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000547
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000548 uint16_t round_trip_time = 0;
549 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
550 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000551
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000552 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000553 round_trip_time);
554 if (!nack_list.empty()) {
555 // Can't use nack_list.data() since it's not supported by all
556 // compilers.
557 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000558 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 return 0;
560}
561
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000562bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
563 int rtp_packet_length) {
564 RTPHeader header;
565 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
566 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
567 "IncomingPacket invalid RTP header");
568 return false;
569 }
570 header.payload_type_frequency =
571 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
572 if (header.payload_type_frequency < 0)
573 return false;
574 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
575}
576
pbos@webrtc.org92135212013-05-14 08:31:39 +0000577int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000578{
579 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
580 "Channel::GetAudioFrame(id=%d)", id);
581
582 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000583 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
584 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000585 {
586 WEBRTC_TRACE(kTraceError, kTraceVoice,
587 VoEId(_instanceId,_channelId),
588 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000589 // In all likelihood, the audio in this frame is garbage. We return an
590 // error so that the audio mixer module doesn't add it to the mix. As
591 // a result, it won't be played out and the actions skipped here are
592 // irrelevant.
593 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 }
595
596 if (_RxVadDetection)
597 {
598 UpdateRxVadDetection(audioFrame);
599 }
600
601 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000602 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000604 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000605
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000606 ChannelState::State state = channel_state_.Get();
607
608 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000609 int err = rx_audioproc_->ProcessStream(&audioFrame);
610 if (err) {
611 LOG(LS_ERROR) << "ProcessStream() error: " << err;
612 assert(false);
613 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 }
615
wu@webrtc.org63420662013-10-17 18:28:55 +0000616 float output_gain = 1.0f;
617 float left_pan = 1.0f;
618 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000620 CriticalSectionScoped cs(&volume_settings_critsect_);
621 output_gain = _outputGain;
622 left_pan = _panLeft;
623 right_pan= _panRight;
624 }
625
626 // Output volume scaling
627 if (output_gain < 0.99f || output_gain > 1.01f)
628 {
629 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 }
631
632 // Scale left and/or right channel(s) if stereo and master balance is
633 // active
634
wu@webrtc.org63420662013-10-17 18:28:55 +0000635 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000637 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 {
639 // Emulate stereo mode since panning is active.
640 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000641 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 }
643 // For true stereo mode (when we are receiving a stereo signal), no
644 // action is needed.
645
646 // Do the panning operation (the audio frame contains stereo at this
647 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000648 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000649 }
650
651 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000652 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000654 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 }
656
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 // External media
658 if (_outputExternalMedia)
659 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000660 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000661 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 if (_outputExternalMediaCallbackPtr)
663 {
664 _outputExternalMediaCallbackPtr->Process(
665 _channelId,
666 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000667 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000668 audioFrame.samples_per_channel_,
669 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 isStereo);
671 }
672 }
673
674 // Record playout if enabled
675 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000676 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000677
678 if (_outputFileRecording && _outputFileRecorderPtr)
679 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000680 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000681 }
682 }
683
684 // Measure audio level (0-9)
685 _outputAudioLevel.ComputeLevel(audioFrame);
686
wu@webrtc.org94454b72014-06-05 20:34:08 +0000687 if (capture_start_rtp_time_stamp_ < 0 && audioFrame.timestamp_ != 0) {
688 // The first frame with a valid rtp timestamp.
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000689 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
wu@webrtc.org94454b72014-06-05 20:34:08 +0000690 }
691
692 if (capture_start_rtp_time_stamp_ >= 0) {
693 // audioFrame.timestamp_ should be valid from now on.
694
695 // Compute elapsed time.
696 int64_t unwrap_timestamp =
697 rtp_ts_wraparound_handler_->Unwrap(audioFrame.timestamp_);
698 audioFrame.elapsed_time_ms_ =
699 (unwrap_timestamp - capture_start_rtp_time_stamp_) /
700 (GetPlayoutFrequency() / 1000);
701
702 // Compute ntp time.
703 audioFrame.ntp_time_ms_ = ntp_estimator_->Estimate(audioFrame.timestamp_);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000704 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
705 if (audioFrame.ntp_time_ms_ > 0) {
706 // Compute |capture_start_ntp_time_ms_| so that
wu@webrtc.org94454b72014-06-05 20:34:08 +0000707 // |capture_start_ntp_time_ms_| + |elapsed_time_ms_| == |ntp_time_ms_|
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000708 CriticalSectionScoped lock(ts_stats_lock_.get());
wu@webrtc.org94454b72014-06-05 20:34:08 +0000709 capture_start_ntp_time_ms_ =
710 audioFrame.ntp_time_ms_ - audioFrame.elapsed_time_ms_;
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000711 }
712 }
713
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 return 0;
715}
716
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000717int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000718Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000719{
720 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
721 "Channel::NeededFrequency(id=%d)", id);
722
723 int highestNeeded = 0;
724
725 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000726 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000727
728 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000729 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000731 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000732 }
733 else
734 {
735 highestNeeded = receiveFrequency;
736 }
737
738 // Special case, if we're playing a file on the playout side
739 // we take that frequency into consideration as well
740 // This is not needed on sending side, since the codec will
741 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000742 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000744 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000745 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000746 {
747 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
748 {
749 highestNeeded=_outputFilePlayerPtr->Frequency();
750 }
751 }
752 }
753
754 return(highestNeeded);
755}
756
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000757int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000758Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000759 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000760 uint32_t instanceId,
761 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000762{
763 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
764 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
765 channelId, instanceId);
766
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000767 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000768 if (channel == NULL)
769 {
770 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
771 VoEId(instanceId,channelId),
772 "Channel::CreateChannel() unable to allocate memory for"
773 " channel");
774 return -1;
775 }
776 return 0;
777}
778
779void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000780Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000781{
782 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
783 "Channel::PlayNotification(id=%d, durationMs=%d)",
784 id, durationMs);
785
786 // Not implement yet
787}
788
789void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000790Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000791{
792 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
793 "Channel::RecordNotification(id=%d, durationMs=%d)",
794 id, durationMs);
795
796 // Not implement yet
797}
798
799void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000800Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000801{
802 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
803 "Channel::PlayFileEnded(id=%d)", id);
804
805 if (id == _inputFilePlayerId)
806 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000807 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000808 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
809 VoEId(_instanceId,_channelId),
810 "Channel::PlayFileEnded() => input file player module is"
811 " shutdown");
812 }
813 else if (id == _outputFilePlayerId)
814 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000815 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000816 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
817 VoEId(_instanceId,_channelId),
818 "Channel::PlayFileEnded() => output file player module is"
819 " shutdown");
820 }
821}
822
823void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000824Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000825{
826 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
827 "Channel::RecordFileEnded(id=%d)", id);
828
829 assert(id == _outputFileRecorderId);
830
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000831 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000832
833 _outputFileRecording = false;
834 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
835 VoEId(_instanceId,_channelId),
836 "Channel::RecordFileEnded() => output file recorder module is"
837 " shutdown");
838}
839
pbos@webrtc.org92135212013-05-14 08:31:39 +0000840Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000841 uint32_t instanceId,
842 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
844 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000845 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000846 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000847 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000848 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000849 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000850 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000851 rtp_receive_statistics_(ReceiveStatistics::Create(
852 Clock::GetRealTimeClock())),
853 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
854 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
855 this, this, rtp_payload_registry_.get())),
856 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000857 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000858 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 _rtpDumpIn(*RtpDump::CreateRtpDump()),
860 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000863 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 _inputFilePlayerPtr(NULL),
865 _outputFilePlayerPtr(NULL),
866 _outputFileRecorderPtr(NULL),
867 // Avoid conflict with other channels by adding 1024 - 1026,
868 // won't use as much as 1024 channels.
869 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
870 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
871 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000872 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000873 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
874 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 _inputExternalMediaCallbackPtr(NULL),
877 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000878 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
879 _sendTelephoneEventPayloadType(106),
wu@webrtc.org82c4b852014-05-20 22:55:01 +0000880 ntp_estimator_(new RemoteNtpTimeEstimator(Clock::GetRealTimeClock())),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000881 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000882 playout_timestamp_rtp_(0),
883 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000884 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000885 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000886 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000887 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org94454b72014-06-05 20:34:08 +0000888 rtp_ts_wraparound_handler_(new rtc::TimestampWrapAroundHandler()),
889 capture_start_rtp_time_stamp_(-1),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000890 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000891 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000892 _outputMixerPtr(NULL),
893 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000894 _moduleProcessThreadPtr(NULL),
895 _audioDeviceModulePtr(NULL),
896 _voiceEngineObserverPtr(NULL),
897 _callbackCritSectPtr(NULL),
898 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000899 _rxVadObserverPtr(NULL),
900 _oldVadDecision(-1),
901 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000903 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000904 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000905 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000906 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 _mute(false),
908 _panLeft(1.0f),
909 _panRight(1.0f),
910 _outputGain(1.0f),
911 _playOutbandDtmfEvent(false),
912 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 _lastLocalTimeStamp(0),
914 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000915 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 _rtpPacketTimedOut(false),
917 _rtpPacketTimeOutIsEnabled(false),
918 _rtpTimeOutSeconds(0),
919 _connectionObserver(false),
920 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000922 vie_network_(NULL),
923 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000924 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000925 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 _previousTimestamp(0),
927 _recPacketDelayMs(20),
928 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000929 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000930 _rxNsIsEnabled(false),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000931 restored_packet_in_use_(false),
932 bitrate_controller_(
933 BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
934 true)),
935 rtcp_bandwidth_observer_(
936 bitrate_controller_->CreateRtcpBandwidthObserver()),
937 send_bitrate_observer_(new VoEBitrateObserver(this))
niklase@google.com470e71d2011-07-07 08:21:25 +0000938{
939 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
940 "Channel::Channel() - ctor");
941 _inbandDtmfQueue.ResetDtmf();
942 _inbandDtmfGenerator.Init();
943 _outputAudioLevel.Clear();
944
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000945 RtpRtcp::Configuration configuration;
946 configuration.id = VoEModuleId(instanceId, channelId);
947 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000948 configuration.outgoing_transport = this;
949 configuration.rtcp_feedback = this;
950 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000951 configuration.receive_statistics = rtp_receive_statistics_.get();
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +0000952 configuration.bandwidth_callback = rtcp_bandwidth_observer_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000953
954 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000955
956 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
957 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
958 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000959
960 Config audioproc_config;
961 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
962 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000963}
964
965Channel::~Channel()
966{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000967 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
969 "Channel::~Channel() - dtor");
970
971 if (_outputExternalMedia)
972 {
973 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
974 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000975 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 {
977 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
978 }
979 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000980 StopPlayout();
981
982 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000983 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 if (_inputFilePlayerPtr)
985 {
986 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
987 _inputFilePlayerPtr->StopPlayingFile();
988 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
989 _inputFilePlayerPtr = NULL;
990 }
991 if (_outputFilePlayerPtr)
992 {
993 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
994 _outputFilePlayerPtr->StopPlayingFile();
995 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
996 _outputFilePlayerPtr = NULL;
997 }
998 if (_outputFileRecorderPtr)
999 {
1000 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1001 _outputFileRecorderPtr->StopRecording();
1002 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1003 _outputFileRecorderPtr = NULL;
1004 }
1005 }
1006
1007 // The order to safely shutdown modules in a channel is:
1008 // 1. De-register callbacks in modules
1009 // 2. De-register modules in process thread
1010 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001011 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 {
1013 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1014 VoEId(_instanceId,_channelId),
1015 "~Channel() failed to de-register transport callback"
1016 " (Audio coding module)");
1017 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001018 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 {
1020 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1021 VoEId(_instanceId,_channelId),
1022 "~Channel() failed to de-register VAD callback"
1023 " (Audio coding module)");
1024 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001026 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001027 {
1028 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1029 VoEId(_instanceId,_channelId),
1030 "~Channel() failed to deregister RTP/RTCP module");
1031 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001032 // End of modules shutdown
1033
1034 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001035 if (vie_network_) {
1036 vie_network_->Release();
1037 vie_network_ = NULL;
1038 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1040 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001041 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001042 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001043 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001044}
1045
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001046int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001047Channel::Init()
1048{
1049 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1050 "Channel::Init()");
1051
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001052 channel_state_.Reset();
1053
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 // --- Initial sanity
1055
1056 if ((_engineStatisticsPtr == NULL) ||
1057 (_moduleProcessThreadPtr == NULL))
1058 {
1059 WEBRTC_TRACE(kTraceError, kTraceVoice,
1060 VoEId(_instanceId,_channelId),
1061 "Channel::Init() must call SetEngineInformation() first");
1062 return -1;
1063 }
1064
1065 // --- Add modules to process thread (for periodic schedulation)
1066
1067 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001068 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001069 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 if (processThreadFail)
1071 {
1072 _engineStatisticsPtr->SetLastError(
1073 VE_CANNOT_INIT_CHANNEL, kTraceError,
1074 "Channel::Init() modules not registered");
1075 return -1;
1076 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001077 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001078
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001079 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001080#ifdef WEBRTC_CODEC_AVT
1081 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001082 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001083#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001084 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 {
1086 _engineStatisticsPtr->SetLastError(
1087 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1088 "Channel::Init() unable to initialize the ACM - 1");
1089 return -1;
1090 }
1091
1092 // --- RTP/RTCP module initialization
1093
1094 // Ensure that RTCP is enabled by default for the created channel.
1095 // Note that, the module will keep generating RTCP until it is explicitly
1096 // disabled by the user.
1097 // After StopListen (when no sockets exists), RTCP packets will no longer
1098 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001099 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1100 // RTCP is enabled by default.
1101 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001102 {
1103 _engineStatisticsPtr->SetLastError(
1104 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1105 "Channel::Init() RTP/RTCP module not initialized");
1106 return -1;
1107 }
1108
1109 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001110 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001111 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1112 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001113
1114 if (fail)
1115 {
1116 _engineStatisticsPtr->SetLastError(
1117 VE_CANNOT_INIT_CHANNEL, kTraceError,
1118 "Channel::Init() callbacks not registered");
1119 return -1;
1120 }
1121
1122 // --- Register all supported codecs to the receiving side of the
1123 // RTP/RTCP module
1124
1125 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001126 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001127
1128 for (int idx = 0; idx < nSupportedCodecs; idx++)
1129 {
1130 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001131 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001132 (rtp_receiver_->RegisterReceivePayload(
1133 codec.plname,
1134 codec.pltype,
1135 codec.plfreq,
1136 codec.channels,
1137 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 {
1139 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1140 VoEId(_instanceId,_channelId),
1141 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1142 "to RTP/RTCP receiver",
1143 codec.plname, codec.pltype, codec.plfreq,
1144 codec.channels, codec.rate);
1145 }
1146 else
1147 {
1148 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1149 VoEId(_instanceId,_channelId),
1150 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1151 "the RTP/RTCP receiver",
1152 codec.plname, codec.pltype, codec.plfreq,
1153 codec.channels, codec.rate);
1154 }
1155
1156 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001157 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 {
1159 SetSendCodec(codec);
1160 }
1161
1162 // Register default PT for outband 'telephone-event'
1163 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1164 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001165 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001166 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001167 {
1168 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1169 VoEId(_instanceId,_channelId),
1170 "Channel::Init() failed to register outband "
1171 "'telephone-event' (%d/%d) correctly",
1172 codec.pltype, codec.plfreq);
1173 }
1174 }
1175
1176 if (!STR_CASE_CMP(codec.plname, "CN"))
1177 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001178 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1179 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001180 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001181 {
1182 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1183 VoEId(_instanceId,_channelId),
1184 "Channel::Init() failed to register CN (%d/%d) "
1185 "correctly - 1",
1186 codec.pltype, codec.plfreq);
1187 }
1188 }
1189#ifdef WEBRTC_CODEC_RED
1190 // Register RED to the receiving side of the ACM.
1191 // We will not receive an OnInitializeDecoder() callback for RED.
1192 if (!STR_CASE_CMP(codec.plname, "RED"))
1193 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001194 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 {
1196 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1197 VoEId(_instanceId,_channelId),
1198 "Channel::Init() failed to register RED (%d/%d) "
1199 "correctly",
1200 codec.pltype, codec.plfreq);
1201 }
1202 }
1203#endif
1204 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001205
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001206 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1207 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1208 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001210 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1211 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1212 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 }
1214
1215 return 0;
1216}
1217
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001218int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001219Channel::SetEngineInformation(Statistics& engineStatistics,
1220 OutputMixer& outputMixer,
1221 voe::TransmitMixer& transmitMixer,
1222 ProcessThread& moduleProcessThread,
1223 AudioDeviceModule& audioDeviceModule,
1224 VoiceEngineObserver* voiceEngineObserver,
1225 CriticalSectionWrapper* callbackCritSect)
1226{
1227 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1228 "Channel::SetEngineInformation()");
1229 _engineStatisticsPtr = &engineStatistics;
1230 _outputMixerPtr = &outputMixer;
1231 _transmitMixerPtr = &transmitMixer,
1232 _moduleProcessThreadPtr = &moduleProcessThread;
1233 _audioDeviceModulePtr = &audioDeviceModule;
1234 _voiceEngineObserverPtr = voiceEngineObserver;
1235 _callbackCritSectPtr = callbackCritSect;
1236 return 0;
1237}
1238
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001239int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001240Channel::UpdateLocalTimeStamp()
1241{
1242
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001243 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001244 return 0;
1245}
1246
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001247int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001248Channel::StartPlayout()
1249{
1250 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1251 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001252 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 {
1254 return 0;
1255 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001256
1257 if (!_externalMixing) {
1258 // Add participant as candidates for mixing.
1259 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1260 {
1261 _engineStatisticsPtr->SetLastError(
1262 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1263 "StartPlayout() failed to add participant to mixer");
1264 return -1;
1265 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001266 }
1267
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001268 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001269 if (RegisterFilePlayingToMixer() != 0)
1270 return -1;
1271
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 return 0;
1273}
1274
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001275int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001276Channel::StopPlayout()
1277{
1278 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1279 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001280 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001281 {
1282 return 0;
1283 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001284
1285 if (!_externalMixing) {
1286 // Remove participant as candidates for mixing
1287 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1288 {
1289 _engineStatisticsPtr->SetLastError(
1290 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1291 "StopPlayout() failed to remove participant from mixer");
1292 return -1;
1293 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001294 }
1295
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001296 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 _outputAudioLevel.Clear();
1298
1299 return 0;
1300}
1301
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001302int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001303Channel::StartSend()
1304{
1305 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1306 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001307 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001308 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001309 if (send_sequence_number_)
1310 SetInitSequenceNumber(send_sequence_number_);
1311
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001312 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001313 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001314 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001316 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001317
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001318 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 {
1320 _engineStatisticsPtr->SetLastError(
1321 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1322 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001323 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001324 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 return -1;
1326 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001327
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 return 0;
1329}
1330
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001331int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001332Channel::StopSend()
1333{
1334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1335 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001336 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001338 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001339 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001340 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001341
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001342 // Store the sequence number to be able to pick up the same sequence for
1343 // the next StartSend(). This is needed for restarting device, otherwise
1344 // it might cause libSRTP to complain about packets being replayed.
1345 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1346 // CL is landed. See issue
1347 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1348 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1349
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 // Reset sending SSRC and sequence number and triggers direct transmission
1351 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001352 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1353 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001354 {
1355 _engineStatisticsPtr->SetLastError(
1356 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1357 "StartSend() RTP/RTCP failed to stop sending");
1358 }
1359
niklase@google.com470e71d2011-07-07 08:21:25 +00001360 return 0;
1361}
1362
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001363int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001364Channel::StartReceiving()
1365{
1366 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1367 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001368 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001369 {
1370 return 0;
1371 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001372 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001373 _numberOfDiscardedPackets = 0;
1374 return 0;
1375}
1376
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001377int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001378Channel::StopReceiving()
1379{
1380 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1381 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001382 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001383 {
1384 return 0;
1385 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001386
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001387 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 return 0;
1389}
1390
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001391int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001392Channel::SetNetEQPlayoutMode(NetEqModes mode)
1393{
1394 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1395 "Channel::SetNetEQPlayoutMode()");
1396 AudioPlayoutMode playoutMode(voice);
1397 switch (mode)
1398 {
1399 case kNetEqDefault:
1400 playoutMode = voice;
1401 break;
1402 case kNetEqStreaming:
1403 playoutMode = streaming;
1404 break;
1405 case kNetEqFax:
1406 playoutMode = fax;
1407 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001408 case kNetEqOff:
1409 playoutMode = off;
1410 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001412 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001413 {
1414 _engineStatisticsPtr->SetLastError(
1415 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1416 "SetNetEQPlayoutMode() failed to set playout mode");
1417 return -1;
1418 }
1419 return 0;
1420}
1421
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001422int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001423Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1424{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001425 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 switch (playoutMode)
1427 {
1428 case voice:
1429 mode = kNetEqDefault;
1430 break;
1431 case streaming:
1432 mode = kNetEqStreaming;
1433 break;
1434 case fax:
1435 mode = kNetEqFax;
1436 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001437 case off:
1438 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 }
1440 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1441 VoEId(_instanceId,_channelId),
1442 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1443 return 0;
1444}
1445
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001446int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001447Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1448{
1449 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1450 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001451 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001452
1453 if (_voiceEngineObserverPtr)
1454 {
1455 _engineStatisticsPtr->SetLastError(
1456 VE_INVALID_OPERATION, kTraceError,
1457 "RegisterVoiceEngineObserver() observer already enabled");
1458 return -1;
1459 }
1460 _voiceEngineObserverPtr = &observer;
1461 return 0;
1462}
1463
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001464int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001465Channel::DeRegisterVoiceEngineObserver()
1466{
1467 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1468 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001469 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001470
1471 if (!_voiceEngineObserverPtr)
1472 {
1473 _engineStatisticsPtr->SetLastError(
1474 VE_INVALID_OPERATION, kTraceWarning,
1475 "DeRegisterVoiceEngineObserver() observer already disabled");
1476 return 0;
1477 }
1478 _voiceEngineObserverPtr = NULL;
1479 return 0;
1480}
1481
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001482int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001483Channel::GetSendCodec(CodecInst& codec)
1484{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001485 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001486}
1487
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001488int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001489Channel::GetRecCodec(CodecInst& codec)
1490{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001491 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001492}
1493
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001494int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001495Channel::SetSendCodec(const CodecInst& codec)
1496{
1497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1498 "Channel::SetSendCodec()");
1499
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001500 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001501 {
1502 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1503 "SetSendCodec() failed to register codec to ACM");
1504 return -1;
1505 }
1506
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001507 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001508 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001509 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1510 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 {
1512 WEBRTC_TRACE(
1513 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1514 "SetSendCodec() failed to register codec to"
1515 " RTP/RTCP module");
1516 return -1;
1517 }
1518 }
1519
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001520 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001521 {
1522 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1523 "SetSendCodec() failed to set audio packet size");
1524 return -1;
1525 }
1526
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001527 bitrate_controller_->SetBitrateObserver(send_bitrate_observer_.get(),
1528 codec.rate, 0, 0);
1529
niklase@google.com470e71d2011-07-07 08:21:25 +00001530 return 0;
1531}
1532
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00001533void
1534Channel::OnNetworkChanged(const uint32_t bitrate_bps,
1535 const uint8_t fraction_lost, // 0 - 255.
1536 const uint32_t rtt) {
1537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1538 "Channel::OnNetworkChanged(bitrate_bps=%d, fration_lost=%d, rtt=%d)",
1539 bitrate_bps, fraction_lost, rtt);
1540 // Normalizes rate to 0 - 100.
1541 if (audio_coding_->SetPacketLossRate(100 * fraction_lost / 255) != 0) {
1542 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR,
1543 kTraceError, "OnNetworkChanged() failed to set packet loss rate");
1544 assert(false); // This should not happen.
1545 }
1546}
1547
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001548int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001549Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1550{
1551 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1552 "Channel::SetVADStatus(mode=%d)", mode);
1553 // To disable VAD, DTX must be disabled too
1554 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001555 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001556 {
1557 _engineStatisticsPtr->SetLastError(
1558 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1559 "SetVADStatus() failed to set VAD");
1560 return -1;
1561 }
1562 return 0;
1563}
1564
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001565int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001566Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1567{
1568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1569 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001570 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001571 {
1572 _engineStatisticsPtr->SetLastError(
1573 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1574 "GetVADStatus() failed to get VAD status");
1575 return -1;
1576 }
1577 disabledDTX = !disabledDTX;
1578 return 0;
1579}
1580
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001581int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001582Channel::SetRecPayloadType(const CodecInst& codec)
1583{
1584 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1585 "Channel::SetRecPayloadType()");
1586
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001587 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001588 {
1589 _engineStatisticsPtr->SetLastError(
1590 VE_ALREADY_PLAYING, kTraceError,
1591 "SetRecPayloadType() unable to set PT while playing");
1592 return -1;
1593 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001594 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001595 {
1596 _engineStatisticsPtr->SetLastError(
1597 VE_ALREADY_LISTENING, kTraceError,
1598 "SetRecPayloadType() unable to set PT while listening");
1599 return -1;
1600 }
1601
1602 if (codec.pltype == -1)
1603 {
1604 // De-register the selected codec (RTP/RTCP module and ACM)
1605
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001606 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001607 CodecInst rxCodec = codec;
1608
1609 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001610 rtp_payload_registry_->ReceivePayloadType(
1611 rxCodec.plname,
1612 rxCodec.plfreq,
1613 rxCodec.channels,
1614 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1615 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001616 rxCodec.pltype = pltype;
1617
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001618 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001619 {
1620 _engineStatisticsPtr->SetLastError(
1621 VE_RTP_RTCP_MODULE_ERROR,
1622 kTraceError,
1623 "SetRecPayloadType() RTP/RTCP-module deregistration "
1624 "failed");
1625 return -1;
1626 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001627 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001628 {
1629 _engineStatisticsPtr->SetLastError(
1630 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1631 "SetRecPayloadType() ACM deregistration failed - 1");
1632 return -1;
1633 }
1634 return 0;
1635 }
1636
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001637 if (rtp_receiver_->RegisterReceivePayload(
1638 codec.plname,
1639 codec.pltype,
1640 codec.plfreq,
1641 codec.channels,
1642 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001643 {
1644 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001645 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1646 if (rtp_receiver_->RegisterReceivePayload(
1647 codec.plname,
1648 codec.pltype,
1649 codec.plfreq,
1650 codec.channels,
1651 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001652 {
1653 _engineStatisticsPtr->SetLastError(
1654 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1655 "SetRecPayloadType() RTP/RTCP-module registration failed");
1656 return -1;
1657 }
1658 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001659 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001660 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001661 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1662 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001663 {
1664 _engineStatisticsPtr->SetLastError(
1665 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1666 "SetRecPayloadType() ACM registration failed - 1");
1667 return -1;
1668 }
1669 }
1670 return 0;
1671}
1672
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001673int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001674Channel::GetRecPayloadType(CodecInst& codec)
1675{
1676 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1677 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001678 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001679 if (rtp_payload_registry_->ReceivePayloadType(
1680 codec.plname,
1681 codec.plfreq,
1682 codec.channels,
1683 (codec.rate < 0) ? 0 : codec.rate,
1684 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001685 {
1686 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001687 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001688 "GetRecPayloadType() failed to retrieve RX payload type");
1689 return -1;
1690 }
1691 codec.pltype = payloadType;
1692 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1693 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1694 return 0;
1695}
1696
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001697int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001698Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1699{
1700 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1701 "Channel::SetSendCNPayloadType()");
1702
1703 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001704 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001705 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001706 if (frequency == kFreq32000Hz)
1707 samplingFreqHz = 32000;
1708 else if (frequency == kFreq16000Hz)
1709 samplingFreqHz = 16000;
1710
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001711 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001712 {
1713 _engineStatisticsPtr->SetLastError(
1714 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1715 "SetSendCNPayloadType() failed to retrieve default CN codec "
1716 "settings");
1717 return -1;
1718 }
1719
1720 // Modify the payload type (must be set to dynamic range)
1721 codec.pltype = type;
1722
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001723 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001724 {
1725 _engineStatisticsPtr->SetLastError(
1726 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1727 "SetSendCNPayloadType() failed to register CN to ACM");
1728 return -1;
1729 }
1730
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001731 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001732 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001733 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1734 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001735 {
1736 _engineStatisticsPtr->SetLastError(
1737 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1738 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1739 "module");
1740 return -1;
1741 }
1742 }
1743 return 0;
1744}
1745
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001746int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001747{
1748 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1749 "Channel::RegisterExternalTransport()");
1750
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001751 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001752
niklase@google.com470e71d2011-07-07 08:21:25 +00001753 if (_externalTransport)
1754 {
1755 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1756 kTraceError,
1757 "RegisterExternalTransport() external transport already enabled");
1758 return -1;
1759 }
1760 _externalTransport = true;
1761 _transportPtr = &transport;
1762 return 0;
1763}
1764
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001765int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001766Channel::DeRegisterExternalTransport()
1767{
1768 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1769 "Channel::DeRegisterExternalTransport()");
1770
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001771 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001772
niklase@google.com470e71d2011-07-07 08:21:25 +00001773 if (!_transportPtr)
1774 {
1775 _engineStatisticsPtr->SetLastError(
1776 VE_INVALID_OPERATION, kTraceWarning,
1777 "DeRegisterExternalTransport() external transport already "
1778 "disabled");
1779 return 0;
1780 }
1781 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001782 _transportPtr = NULL;
1783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1784 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001785 return 0;
1786}
1787
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001788int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1789 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001790 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1791 "Channel::ReceivedRTPPacket()");
1792
1793 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001794 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001795
1796 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001797 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1798 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001799 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1800 VoEId(_instanceId,_channelId),
1801 "Channel::SendPacket() RTP dump to input file failed");
1802 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001803 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001804 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001805 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1806 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1807 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001808 return -1;
1809 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001810 header.payload_type_frequency =
1811 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001812 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001813 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001814 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001815 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001816 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001817 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001818
1819 // Forward any packets to ViE bandwidth estimator, if enabled.
1820 {
1821 CriticalSectionScoped cs(&_callbackCritSect);
1822 if (vie_network_) {
1823 int64_t arrival_time_ms;
1824 if (packet_time.timestamp != -1) {
1825 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1826 } else {
1827 arrival_time_ms = TickTime::MillisecondTimestamp();
1828 }
1829 int payload_length = length - header.headerLength;
1830 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1831 payload_length, header);
1832 }
1833 }
1834
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001835 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001836}
1837
1838bool Channel::ReceivePacket(const uint8_t* packet,
1839 int packet_length,
1840 const RTPHeader& header,
1841 bool in_order) {
1842 if (rtp_payload_registry_->IsEncapsulated(header)) {
1843 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001844 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001845 const uint8_t* payload = packet + header.headerLength;
1846 int payload_length = packet_length - header.headerLength;
1847 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001848 PayloadUnion payload_specific;
1849 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001850 &payload_specific)) {
1851 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001852 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001853 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1854 payload_specific, in_order);
1855}
1856
1857bool Channel::HandleEncapsulation(const uint8_t* packet,
1858 int packet_length,
1859 const RTPHeader& header) {
1860 if (!rtp_payload_registry_->IsRtx(header))
1861 return false;
1862
1863 // Remove the RTX header and parse the original RTP header.
1864 if (packet_length < header.headerLength)
1865 return false;
1866 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1867 return false;
1868 if (restored_packet_in_use_) {
1869 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1870 "Multiple RTX headers detected, dropping packet");
1871 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001872 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001873 uint8_t* restored_packet_ptr = restored_packet_;
1874 if (!rtp_payload_registry_->RestoreOriginalPacket(
1875 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1876 header)) {
1877 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1878 "Incoming RTX packet: invalid RTP header");
1879 return false;
1880 }
1881 restored_packet_in_use_ = true;
1882 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1883 restored_packet_in_use_ = false;
1884 return ret;
1885}
1886
1887bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1888 StreamStatistician* statistician =
1889 rtp_receive_statistics_->GetStatistician(header.ssrc);
1890 if (!statistician)
1891 return false;
1892 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001893}
1894
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001895bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1896 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001897 // Retransmissions are handled separately if RTX is enabled.
1898 if (rtp_payload_registry_->RtxEnabled())
1899 return false;
1900 StreamStatistician* statistician =
1901 rtp_receive_statistics_->GetStatistician(header.ssrc);
1902 if (!statistician)
1903 return false;
1904 // Check if this is a retransmission.
1905 uint16_t min_rtt = 0;
1906 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001907 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001908 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001909}
1910
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001911int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001912 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1913 "Channel::ReceivedRTCPPacket()");
1914 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001915 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001916
1917 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001918 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1919 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001920 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1921 VoEId(_instanceId,_channelId),
1922 "Channel::SendPacket() RTCP dump to input file failed");
1923 }
1924
1925 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001926 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1927 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001928 _engineStatisticsPtr->SetLastError(
1929 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1930 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1931 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001932
1933 ntp_estimator_->UpdateRtcpTimestamp(rtp_receiver_->SSRC(),
1934 _rtpRtcpModule.get());
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001935 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001936}
1937
niklase@google.com470e71d2011-07-07 08:21:25 +00001938int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001939 bool loop,
1940 FileFormats format,
1941 int startPosition,
1942 float volumeScaling,
1943 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001944 const CodecInst* codecInst)
1945{
1946 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1947 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1948 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1949 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1950 startPosition, stopPosition);
1951
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001952 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001953 {
1954 _engineStatisticsPtr->SetLastError(
1955 VE_ALREADY_PLAYING, kTraceError,
1956 "StartPlayingFileLocally() is already playing");
1957 return -1;
1958 }
1959
niklase@google.com470e71d2011-07-07 08:21:25 +00001960 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001961 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001962
1963 if (_outputFilePlayerPtr)
1964 {
1965 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1966 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1967 _outputFilePlayerPtr = NULL;
1968 }
1969
1970 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1971 _outputFilePlayerId, (const FileFormats)format);
1972
1973 if (_outputFilePlayerPtr == NULL)
1974 {
1975 _engineStatisticsPtr->SetLastError(
1976 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001977 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001978 return -1;
1979 }
1980
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001981 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001982
1983 if (_outputFilePlayerPtr->StartPlayingFile(
1984 fileName,
1985 loop,
1986 startPosition,
1987 volumeScaling,
1988 notificationTime,
1989 stopPosition,
1990 (const CodecInst*)codecInst) != 0)
1991 {
1992 _engineStatisticsPtr->SetLastError(
1993 VE_BAD_FILE, kTraceError,
1994 "StartPlayingFile() failed to start file playout");
1995 _outputFilePlayerPtr->StopPlayingFile();
1996 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1997 _outputFilePlayerPtr = NULL;
1998 return -1;
1999 }
2000 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002001 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002002 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002003
2004 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002005 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002006
2007 return 0;
2008}
2009
2010int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002011 FileFormats format,
2012 int startPosition,
2013 float volumeScaling,
2014 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002015 const CodecInst* codecInst)
2016{
2017 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2018 "Channel::StartPlayingFileLocally(format=%d,"
2019 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2020 format, volumeScaling, startPosition, stopPosition);
2021
2022 if(stream == NULL)
2023 {
2024 _engineStatisticsPtr->SetLastError(
2025 VE_BAD_FILE, kTraceError,
2026 "StartPlayingFileLocally() NULL as input stream");
2027 return -1;
2028 }
2029
2030
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002031 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 {
2033 _engineStatisticsPtr->SetLastError(
2034 VE_ALREADY_PLAYING, kTraceError,
2035 "StartPlayingFileLocally() is already playing");
2036 return -1;
2037 }
2038
niklase@google.com470e71d2011-07-07 08:21:25 +00002039 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002040 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002041
2042 // Destroy the old instance
2043 if (_outputFilePlayerPtr)
2044 {
2045 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2046 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2047 _outputFilePlayerPtr = NULL;
2048 }
2049
2050 // Create the instance
2051 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2052 _outputFilePlayerId,
2053 (const FileFormats)format);
2054
2055 if (_outputFilePlayerPtr == NULL)
2056 {
2057 _engineStatisticsPtr->SetLastError(
2058 VE_INVALID_ARGUMENT, kTraceError,
2059 "StartPlayingFileLocally() filePlayer format isnot correct");
2060 return -1;
2061 }
2062
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002063 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002064
2065 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2066 volumeScaling,
2067 notificationTime,
2068 stopPosition, codecInst) != 0)
2069 {
2070 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2071 "StartPlayingFile() failed to "
2072 "start file playout");
2073 _outputFilePlayerPtr->StopPlayingFile();
2074 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2075 _outputFilePlayerPtr = NULL;
2076 return -1;
2077 }
2078 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002079 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002080 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002081
2082 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002083 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002084
niklase@google.com470e71d2011-07-07 08:21:25 +00002085 return 0;
2086}
2087
2088int Channel::StopPlayingFileLocally()
2089{
2090 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2091 "Channel::StopPlayingFileLocally()");
2092
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002093 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002094 {
2095 _engineStatisticsPtr->SetLastError(
2096 VE_INVALID_OPERATION, kTraceWarning,
2097 "StopPlayingFileLocally() isnot playing");
2098 return 0;
2099 }
2100
niklase@google.com470e71d2011-07-07 08:21:25 +00002101 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002102 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002103
2104 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2105 {
2106 _engineStatisticsPtr->SetLastError(
2107 VE_STOP_RECORDING_FAILED, kTraceError,
2108 "StopPlayingFile() could not stop playing");
2109 return -1;
2110 }
2111 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2112 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2113 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002114 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002115 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002116 // _fileCritSect cannot be taken while calling
2117 // SetAnonymousMixibilityStatus. Refer to comments in
2118 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002119 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2120 {
2121 _engineStatisticsPtr->SetLastError(
2122 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002123 "StopPlayingFile() failed to stop participant from playing as"
2124 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002125 return -1;
2126 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002127
2128 return 0;
2129}
2130
2131int Channel::IsPlayingFileLocally() const
2132{
2133 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2134 "Channel::IsPlayingFileLocally()");
2135
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002136 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002137}
2138
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002139int Channel::RegisterFilePlayingToMixer()
2140{
2141 // Return success for not registering for file playing to mixer if:
2142 // 1. playing file before playout is started on that channel.
2143 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002144 if (!channel_state_.Get().playing ||
2145 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002146 {
2147 return 0;
2148 }
2149
2150 // |_fileCritSect| cannot be taken while calling
2151 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2152 // frames can be pulled by the mixer. Since the frames are generated from
2153 // the file, _fileCritSect will be taken. This would result in a deadlock.
2154 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2155 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002156 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002157 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002158 _engineStatisticsPtr->SetLastError(
2159 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2160 "StartPlayingFile() failed to add participant as file to mixer");
2161 _outputFilePlayerPtr->StopPlayingFile();
2162 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2163 _outputFilePlayerPtr = NULL;
2164 return -1;
2165 }
2166
2167 return 0;
2168}
2169
niklase@google.com470e71d2011-07-07 08:21:25 +00002170int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002171 bool loop,
2172 FileFormats format,
2173 int startPosition,
2174 float volumeScaling,
2175 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002176 const CodecInst* codecInst)
2177{
2178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2179 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2180 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2181 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2182 startPosition, stopPosition);
2183
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002184 CriticalSectionScoped cs(&_fileCritSect);
2185
2186 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002187 {
2188 _engineStatisticsPtr->SetLastError(
2189 VE_ALREADY_PLAYING, kTraceWarning,
2190 "StartPlayingFileAsMicrophone() filePlayer is playing");
2191 return 0;
2192 }
2193
niklase@google.com470e71d2011-07-07 08:21:25 +00002194 // Destroy the old instance
2195 if (_inputFilePlayerPtr)
2196 {
2197 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2198 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2199 _inputFilePlayerPtr = NULL;
2200 }
2201
2202 // Create the instance
2203 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2204 _inputFilePlayerId, (const FileFormats)format);
2205
2206 if (_inputFilePlayerPtr == NULL)
2207 {
2208 _engineStatisticsPtr->SetLastError(
2209 VE_INVALID_ARGUMENT, kTraceError,
2210 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2211 return -1;
2212 }
2213
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002214 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002215
2216 if (_inputFilePlayerPtr->StartPlayingFile(
2217 fileName,
2218 loop,
2219 startPosition,
2220 volumeScaling,
2221 notificationTime,
2222 stopPosition,
2223 (const CodecInst*)codecInst) != 0)
2224 {
2225 _engineStatisticsPtr->SetLastError(
2226 VE_BAD_FILE, kTraceError,
2227 "StartPlayingFile() failed to start file playout");
2228 _inputFilePlayerPtr->StopPlayingFile();
2229 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2230 _inputFilePlayerPtr = NULL;
2231 return -1;
2232 }
2233 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002234 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002235
2236 return 0;
2237}
2238
2239int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002240 FileFormats format,
2241 int startPosition,
2242 float volumeScaling,
2243 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002244 const CodecInst* codecInst)
2245{
2246 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2247 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2248 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2249 format, volumeScaling, startPosition, stopPosition);
2250
2251 if(stream == NULL)
2252 {
2253 _engineStatisticsPtr->SetLastError(
2254 VE_BAD_FILE, kTraceError,
2255 "StartPlayingFileAsMicrophone NULL as input stream");
2256 return -1;
2257 }
2258
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002259 CriticalSectionScoped cs(&_fileCritSect);
2260
2261 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002262 {
2263 _engineStatisticsPtr->SetLastError(
2264 VE_ALREADY_PLAYING, kTraceWarning,
2265 "StartPlayingFileAsMicrophone() is playing");
2266 return 0;
2267 }
2268
niklase@google.com470e71d2011-07-07 08:21:25 +00002269 // Destroy the old instance
2270 if (_inputFilePlayerPtr)
2271 {
2272 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2273 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2274 _inputFilePlayerPtr = NULL;
2275 }
2276
2277 // Create the instance
2278 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2279 _inputFilePlayerId, (const FileFormats)format);
2280
2281 if (_inputFilePlayerPtr == NULL)
2282 {
2283 _engineStatisticsPtr->SetLastError(
2284 VE_INVALID_ARGUMENT, kTraceError,
2285 "StartPlayingInputFile() filePlayer format isnot correct");
2286 return -1;
2287 }
2288
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002289 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002290
2291 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2292 volumeScaling, notificationTime,
2293 stopPosition, codecInst) != 0)
2294 {
2295 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2296 "StartPlayingFile() failed to start "
2297 "file playout");
2298 _inputFilePlayerPtr->StopPlayingFile();
2299 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2300 _inputFilePlayerPtr = NULL;
2301 return -1;
2302 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002303
niklase@google.com470e71d2011-07-07 08:21:25 +00002304 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002305 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002306
2307 return 0;
2308}
2309
2310int Channel::StopPlayingFileAsMicrophone()
2311{
2312 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2313 "Channel::StopPlayingFileAsMicrophone()");
2314
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002315 CriticalSectionScoped cs(&_fileCritSect);
2316
2317 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002318 {
2319 _engineStatisticsPtr->SetLastError(
2320 VE_INVALID_OPERATION, kTraceWarning,
2321 "StopPlayingFileAsMicrophone() isnot playing");
2322 return 0;
2323 }
2324
niklase@google.com470e71d2011-07-07 08:21:25 +00002325 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2326 {
2327 _engineStatisticsPtr->SetLastError(
2328 VE_STOP_RECORDING_FAILED, kTraceError,
2329 "StopPlayingFile() could not stop playing");
2330 return -1;
2331 }
2332 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2333 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2334 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002335 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002336
2337 return 0;
2338}
2339
2340int Channel::IsPlayingFileAsMicrophone() const
2341{
2342 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2343 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002344 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002345}
2346
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002347int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002348 const CodecInst* codecInst)
2349{
2350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2351 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2352
2353 if (_outputFileRecording)
2354 {
2355 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2356 "StartRecordingPlayout() is already recording");
2357 return 0;
2358 }
2359
2360 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002361 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002362 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2363
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002364 if ((codecInst != NULL) &&
2365 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002366 {
2367 _engineStatisticsPtr->SetLastError(
2368 VE_BAD_ARGUMENT, kTraceError,
2369 "StartRecordingPlayout() invalid compression");
2370 return(-1);
2371 }
2372 if(codecInst == NULL)
2373 {
2374 format = kFileFormatPcm16kHzFile;
2375 codecInst=&dummyCodec;
2376 }
2377 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2378 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2379 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2380 {
2381 format = kFileFormatWavFile;
2382 }
2383 else
2384 {
2385 format = kFileFormatCompressedFile;
2386 }
2387
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002388 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002389
2390 // Destroy the old instance
2391 if (_outputFileRecorderPtr)
2392 {
2393 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2394 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2395 _outputFileRecorderPtr = NULL;
2396 }
2397
2398 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2399 _outputFileRecorderId, (const FileFormats)format);
2400 if (_outputFileRecorderPtr == NULL)
2401 {
2402 _engineStatisticsPtr->SetLastError(
2403 VE_INVALID_ARGUMENT, kTraceError,
2404 "StartRecordingPlayout() fileRecorder format isnot correct");
2405 return -1;
2406 }
2407
2408 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2409 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2410 {
2411 _engineStatisticsPtr->SetLastError(
2412 VE_BAD_FILE, kTraceError,
2413 "StartRecordingAudioFile() failed to start file recording");
2414 _outputFileRecorderPtr->StopRecording();
2415 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2416 _outputFileRecorderPtr = NULL;
2417 return -1;
2418 }
2419 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2420 _outputFileRecording = true;
2421
2422 return 0;
2423}
2424
2425int Channel::StartRecordingPlayout(OutStream* stream,
2426 const CodecInst* codecInst)
2427{
2428 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2429 "Channel::StartRecordingPlayout()");
2430
2431 if (_outputFileRecording)
2432 {
2433 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2434 "StartRecordingPlayout() is already recording");
2435 return 0;
2436 }
2437
2438 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002439 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002440 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2441
2442 if (codecInst != NULL && codecInst->channels != 1)
2443 {
2444 _engineStatisticsPtr->SetLastError(
2445 VE_BAD_ARGUMENT, kTraceError,
2446 "StartRecordingPlayout() invalid compression");
2447 return(-1);
2448 }
2449 if(codecInst == NULL)
2450 {
2451 format = kFileFormatPcm16kHzFile;
2452 codecInst=&dummyCodec;
2453 }
2454 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2455 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2456 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2457 {
2458 format = kFileFormatWavFile;
2459 }
2460 else
2461 {
2462 format = kFileFormatCompressedFile;
2463 }
2464
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002465 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002466
2467 // Destroy the old instance
2468 if (_outputFileRecorderPtr)
2469 {
2470 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2471 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2472 _outputFileRecorderPtr = NULL;
2473 }
2474
2475 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2476 _outputFileRecorderId, (const FileFormats)format);
2477 if (_outputFileRecorderPtr == NULL)
2478 {
2479 _engineStatisticsPtr->SetLastError(
2480 VE_INVALID_ARGUMENT, kTraceError,
2481 "StartRecordingPlayout() fileRecorder format isnot correct");
2482 return -1;
2483 }
2484
2485 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2486 notificationTime) != 0)
2487 {
2488 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2489 "StartRecordingPlayout() failed to "
2490 "start file recording");
2491 _outputFileRecorderPtr->StopRecording();
2492 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2493 _outputFileRecorderPtr = NULL;
2494 return -1;
2495 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002496
niklase@google.com470e71d2011-07-07 08:21:25 +00002497 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2498 _outputFileRecording = true;
2499
2500 return 0;
2501}
2502
2503int Channel::StopRecordingPlayout()
2504{
2505 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2506 "Channel::StopRecordingPlayout()");
2507
2508 if (!_outputFileRecording)
2509 {
2510 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2511 "StopRecordingPlayout() isnot recording");
2512 return -1;
2513 }
2514
2515
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002516 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002517
2518 if (_outputFileRecorderPtr->StopRecording() != 0)
2519 {
2520 _engineStatisticsPtr->SetLastError(
2521 VE_STOP_RECORDING_FAILED, kTraceError,
2522 "StopRecording() could not stop recording");
2523 return(-1);
2524 }
2525 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2526 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2527 _outputFileRecorderPtr = NULL;
2528 _outputFileRecording = false;
2529
2530 return 0;
2531}
2532
2533void
2534Channel::SetMixWithMicStatus(bool mix)
2535{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002536 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002537 _mixFileWithMicrophone=mix;
2538}
2539
2540int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002541Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002542{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002543 int8_t currentLevel = _outputAudioLevel.Level();
2544 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002545 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2546 VoEId(_instanceId,_channelId),
2547 "GetSpeechOutputLevel() => level=%u", level);
2548 return 0;
2549}
2550
2551int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002552Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002553{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002554 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2555 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002556 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2557 VoEId(_instanceId,_channelId),
2558 "GetSpeechOutputLevelFullRange() => level=%u", level);
2559 return 0;
2560}
2561
2562int
2563Channel::SetMute(bool enable)
2564{
wu@webrtc.org63420662013-10-17 18:28:55 +00002565 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2567 "Channel::SetMute(enable=%d)", enable);
2568 _mute = enable;
2569 return 0;
2570}
2571
2572bool
2573Channel::Mute() const
2574{
wu@webrtc.org63420662013-10-17 18:28:55 +00002575 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002576 return _mute;
2577}
2578
2579int
2580Channel::SetOutputVolumePan(float left, float right)
2581{
wu@webrtc.org63420662013-10-17 18:28:55 +00002582 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2584 "Channel::SetOutputVolumePan()");
2585 _panLeft = left;
2586 _panRight = right;
2587 return 0;
2588}
2589
2590int
2591Channel::GetOutputVolumePan(float& left, float& right) const
2592{
wu@webrtc.org63420662013-10-17 18:28:55 +00002593 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002594 left = _panLeft;
2595 right = _panRight;
2596 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2597 VoEId(_instanceId,_channelId),
2598 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2599 return 0;
2600}
2601
2602int
2603Channel::SetChannelOutputVolumeScaling(float scaling)
2604{
wu@webrtc.org63420662013-10-17 18:28:55 +00002605 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002606 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2607 "Channel::SetChannelOutputVolumeScaling()");
2608 _outputGain = scaling;
2609 return 0;
2610}
2611
2612int
2613Channel::GetChannelOutputVolumeScaling(float& scaling) const
2614{
wu@webrtc.org63420662013-10-17 18:28:55 +00002615 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 scaling = _outputGain;
2617 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2618 VoEId(_instanceId,_channelId),
2619 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2620 return 0;
2621}
2622
niklase@google.com470e71d2011-07-07 08:21:25 +00002623int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002624 int lengthMs, int attenuationDb,
2625 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002626{
2627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2628 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2629 playDtmfEvent);
2630
2631 _playOutbandDtmfEvent = playDtmfEvent;
2632
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002633 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002634 attenuationDb) != 0)
2635 {
2636 _engineStatisticsPtr->SetLastError(
2637 VE_SEND_DTMF_FAILED,
2638 kTraceWarning,
2639 "SendTelephoneEventOutband() failed to send event");
2640 return -1;
2641 }
2642 return 0;
2643}
2644
2645int Channel::SendTelephoneEventInband(unsigned char eventCode,
2646 int lengthMs,
2647 int attenuationDb,
2648 bool playDtmfEvent)
2649{
2650 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2651 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2652 playDtmfEvent);
2653
2654 _playInbandDtmfEvent = playDtmfEvent;
2655 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2656
2657 return 0;
2658}
2659
2660int
2661Channel::SetDtmfPlayoutStatus(bool enable)
2662{
2663 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2664 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002665 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002666 {
2667 _engineStatisticsPtr->SetLastError(
2668 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2669 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2670 return -1;
2671 }
2672 return 0;
2673}
2674
2675bool
2676Channel::DtmfPlayoutStatus() const
2677{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002678 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002679}
2680
2681int
2682Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2683{
2684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2685 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002686 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002687 {
2688 _engineStatisticsPtr->SetLastError(
2689 VE_INVALID_ARGUMENT, kTraceError,
2690 "SetSendTelephoneEventPayloadType() invalid type");
2691 return -1;
2692 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002693 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002694 codec.plfreq = 8000;
2695 codec.pltype = type;
2696 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002697 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002698 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002699 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2700 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2701 _engineStatisticsPtr->SetLastError(
2702 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2703 "SetSendTelephoneEventPayloadType() failed to register send"
2704 "payload type");
2705 return -1;
2706 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002707 }
2708 _sendTelephoneEventPayloadType = type;
2709 return 0;
2710}
2711
2712int
2713Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2714{
2715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2716 "Channel::GetSendTelephoneEventPayloadType()");
2717 type = _sendTelephoneEventPayloadType;
2718 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2719 VoEId(_instanceId,_channelId),
2720 "GetSendTelephoneEventPayloadType() => type=%u", type);
2721 return 0;
2722}
2723
niklase@google.com470e71d2011-07-07 08:21:25 +00002724int
2725Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2726{
2727 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2728 "Channel::UpdateRxVadDetection()");
2729
2730 int vadDecision = 1;
2731
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002732 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002733
2734 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2735 {
2736 OnRxVadDetected(vadDecision);
2737 _oldVadDecision = vadDecision;
2738 }
2739
2740 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2741 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2742 vadDecision);
2743 return 0;
2744}
2745
2746int
2747Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2748{
2749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2750 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002751 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002752
2753 if (_rxVadObserverPtr)
2754 {
2755 _engineStatisticsPtr->SetLastError(
2756 VE_INVALID_OPERATION, kTraceError,
2757 "RegisterRxVadObserver() observer already enabled");
2758 return -1;
2759 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002760 _rxVadObserverPtr = &observer;
2761 _RxVadDetection = true;
2762 return 0;
2763}
2764
2765int
2766Channel::DeRegisterRxVadObserver()
2767{
2768 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2769 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002770 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002771
2772 if (!_rxVadObserverPtr)
2773 {
2774 _engineStatisticsPtr->SetLastError(
2775 VE_INVALID_OPERATION, kTraceWarning,
2776 "DeRegisterRxVadObserver() observer already disabled");
2777 return 0;
2778 }
2779 _rxVadObserverPtr = NULL;
2780 _RxVadDetection = false;
2781 return 0;
2782}
2783
2784int
2785Channel::VoiceActivityIndicator(int &activity)
2786{
2787 activity = _sendFrameType;
2788
2789 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002790 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002791 return 0;
2792}
2793
2794#ifdef WEBRTC_VOICE_ENGINE_AGC
2795
2796int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002797Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002798{
2799 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2800 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2801 (int)enable, (int)mode);
2802
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002803 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002804 switch (mode)
2805 {
2806 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002807 break;
2808 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002809 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002810 break;
2811 case kAgcFixedDigital:
2812 agcMode = GainControl::kFixedDigital;
2813 break;
2814 case kAgcAdaptiveDigital:
2815 agcMode =GainControl::kAdaptiveDigital;
2816 break;
2817 default:
2818 _engineStatisticsPtr->SetLastError(
2819 VE_INVALID_ARGUMENT, kTraceError,
2820 "SetRxAgcStatus() invalid Agc mode");
2821 return -1;
2822 }
2823
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002824 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002825 {
2826 _engineStatisticsPtr->SetLastError(
2827 VE_APM_ERROR, kTraceError,
2828 "SetRxAgcStatus() failed to set Agc mode");
2829 return -1;
2830 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002831 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002832 {
2833 _engineStatisticsPtr->SetLastError(
2834 VE_APM_ERROR, kTraceError,
2835 "SetRxAgcStatus() failed to set Agc state");
2836 return -1;
2837 }
2838
2839 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002840 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002841
2842 return 0;
2843}
2844
2845int
2846Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2847{
2848 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2849 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2850
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002851 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002852 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002853 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002854
2855 enabled = enable;
2856
2857 switch (agcMode)
2858 {
2859 case GainControl::kFixedDigital:
2860 mode = kAgcFixedDigital;
2861 break;
2862 case GainControl::kAdaptiveDigital:
2863 mode = kAgcAdaptiveDigital;
2864 break;
2865 default:
2866 _engineStatisticsPtr->SetLastError(
2867 VE_APM_ERROR, kTraceError,
2868 "GetRxAgcStatus() invalid Agc mode");
2869 return -1;
2870 }
2871
2872 return 0;
2873}
2874
2875int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002876Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002877{
2878 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2879 "Channel::SetRxAgcConfig()");
2880
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002881 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002882 config.targetLeveldBOv) != 0)
2883 {
2884 _engineStatisticsPtr->SetLastError(
2885 VE_APM_ERROR, kTraceError,
2886 "SetRxAgcConfig() failed to set target peak |level|"
2887 "(or envelope) of the Agc");
2888 return -1;
2889 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002890 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002891 config.digitalCompressionGaindB) != 0)
2892 {
2893 _engineStatisticsPtr->SetLastError(
2894 VE_APM_ERROR, kTraceError,
2895 "SetRxAgcConfig() failed to set the range in |gain| the"
2896 " digital compression stage may apply");
2897 return -1;
2898 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002899 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002900 config.limiterEnable) != 0)
2901 {
2902 _engineStatisticsPtr->SetLastError(
2903 VE_APM_ERROR, kTraceError,
2904 "SetRxAgcConfig() failed to set hard limiter to the signal");
2905 return -1;
2906 }
2907
2908 return 0;
2909}
2910
2911int
2912Channel::GetRxAgcConfig(AgcConfig& config)
2913{
2914 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2915 "Channel::GetRxAgcConfig(config=%?)");
2916
2917 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002918 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002919 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002920 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002921 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002922 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002923
2924 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2925 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2926 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2927 " limiterEnable=%d",
2928 config.targetLeveldBOv,
2929 config.digitalCompressionGaindB,
2930 config.limiterEnable);
2931
2932 return 0;
2933}
2934
2935#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2936
2937#ifdef WEBRTC_VOICE_ENGINE_NR
2938
2939int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002940Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002941{
2942 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2943 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2944 (int)enable, (int)mode);
2945
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002946 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002947 switch (mode)
2948 {
2949
2950 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002951 break;
2952 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002953 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002954 break;
2955 case kNsConference:
2956 nsLevel = NoiseSuppression::kHigh;
2957 break;
2958 case kNsLowSuppression:
2959 nsLevel = NoiseSuppression::kLow;
2960 break;
2961 case kNsModerateSuppression:
2962 nsLevel = NoiseSuppression::kModerate;
2963 break;
2964 case kNsHighSuppression:
2965 nsLevel = NoiseSuppression::kHigh;
2966 break;
2967 case kNsVeryHighSuppression:
2968 nsLevel = NoiseSuppression::kVeryHigh;
2969 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002970 }
2971
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002972 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002973 != 0)
2974 {
2975 _engineStatisticsPtr->SetLastError(
2976 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002977 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002978 return -1;
2979 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002980 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002981 {
2982 _engineStatisticsPtr->SetLastError(
2983 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002984 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002985 return -1;
2986 }
2987
2988 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002989 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002990
2991 return 0;
2992}
2993
2994int
2995Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2996{
2997 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2998 "Channel::GetRxNsStatus(enable=?, mode=?)");
2999
3000 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003001 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003002 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003003 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003004
3005 enabled = enable;
3006
3007 switch (ncLevel)
3008 {
3009 case NoiseSuppression::kLow:
3010 mode = kNsLowSuppression;
3011 break;
3012 case NoiseSuppression::kModerate:
3013 mode = kNsModerateSuppression;
3014 break;
3015 case NoiseSuppression::kHigh:
3016 mode = kNsHighSuppression;
3017 break;
3018 case NoiseSuppression::kVeryHigh:
3019 mode = kNsVeryHighSuppression;
3020 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003021 }
3022
3023 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3024 VoEId(_instanceId,_channelId),
3025 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3026 return 0;
3027}
3028
3029#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3030
3031int
niklase@google.com470e71d2011-07-07 08:21:25 +00003032Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3033{
3034 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3035 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003036 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003037
3038 if (_rtcpObserverPtr)
3039 {
3040 _engineStatisticsPtr->SetLastError(
3041 VE_INVALID_OPERATION, kTraceError,
3042 "RegisterRTCPObserver() observer already enabled");
3043 return -1;
3044 }
3045
3046 _rtcpObserverPtr = &observer;
3047 _rtcpObserver = true;
3048
3049 return 0;
3050}
3051
3052int
3053Channel::DeRegisterRTCPObserver()
3054{
3055 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3056 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003057 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003058
3059 if (!_rtcpObserverPtr)
3060 {
3061 _engineStatisticsPtr->SetLastError(
3062 VE_INVALID_OPERATION, kTraceWarning,
3063 "DeRegisterRTCPObserver() observer already disabled");
3064 return 0;
3065 }
3066
3067 _rtcpObserver = false;
3068 _rtcpObserverPtr = NULL;
3069
3070 return 0;
3071}
3072
3073int
3074Channel::SetLocalSSRC(unsigned int ssrc)
3075{
3076 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3077 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003078 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003079 {
3080 _engineStatisticsPtr->SetLastError(
3081 VE_ALREADY_SENDING, kTraceError,
3082 "SetLocalSSRC() already sending");
3083 return -1;
3084 }
stefan@webrtc.orgef927552014-06-05 08:25:29 +00003085 _rtpRtcpModule->SetSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +00003086 return 0;
3087}
3088
3089int
3090Channel::GetLocalSSRC(unsigned int& ssrc)
3091{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003092 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003093 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3094 VoEId(_instanceId,_channelId),
3095 "GetLocalSSRC() => ssrc=%lu", ssrc);
3096 return 0;
3097}
3098
3099int
3100Channel::GetRemoteSSRC(unsigned int& ssrc)
3101{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003102 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003103 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3104 VoEId(_instanceId,_channelId),
3105 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3106 return 0;
3107}
3108
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003109int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003110 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003111 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003112}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003113
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003114int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3115 unsigned char id) {
3116 rtp_header_parser_->DeregisterRtpHeaderExtension(
3117 kRtpExtensionAudioLevel);
3118 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3119 kRtpExtensionAudioLevel, id)) {
3120 return -1;
3121 }
3122 return 0;
3123}
3124
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003125int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3126 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3127}
3128
3129int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3130 rtp_header_parser_->DeregisterRtpHeaderExtension(
3131 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003132 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3133 kRtpExtensionAbsoluteSendTime, id)) {
3134 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003135 }
3136 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003137}
3138
3139int
3140Channel::SetRTCPStatus(bool enable)
3141{
3142 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3143 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003144 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003145 kRtcpCompound : kRtcpOff) != 0)
3146 {
3147 _engineStatisticsPtr->SetLastError(
3148 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3149 "SetRTCPStatus() failed to set RTCP status");
3150 return -1;
3151 }
3152 return 0;
3153}
3154
3155int
3156Channel::GetRTCPStatus(bool& enabled)
3157{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003158 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003159 enabled = (method != kRtcpOff);
3160 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3161 VoEId(_instanceId,_channelId),
3162 "GetRTCPStatus() => enabled=%d", enabled);
3163 return 0;
3164}
3165
3166int
3167Channel::SetRTCP_CNAME(const char cName[256])
3168{
3169 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3170 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003171 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003172 {
3173 _engineStatisticsPtr->SetLastError(
3174 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3175 "SetRTCP_CNAME() failed to set RTCP CNAME");
3176 return -1;
3177 }
3178 return 0;
3179}
3180
3181int
3182Channel::GetRTCP_CNAME(char cName[256])
3183{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003184 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003185 {
3186 _engineStatisticsPtr->SetLastError(
3187 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3188 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3189 return -1;
3190 }
3191 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3192 VoEId(_instanceId, _channelId),
3193 "GetRTCP_CNAME() => cName=%s", cName);
3194 return 0;
3195}
3196
3197int
3198Channel::GetRemoteRTCP_CNAME(char cName[256])
3199{
3200 if (cName == NULL)
3201 {
3202 _engineStatisticsPtr->SetLastError(
3203 VE_INVALID_ARGUMENT, kTraceError,
3204 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3205 return -1;
3206 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003207 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003208 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003209 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003210 {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3213 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3214 return -1;
3215 }
3216 strcpy(cName, cname);
3217 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3218 VoEId(_instanceId, _channelId),
3219 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3220 return 0;
3221}
3222
3223int
3224Channel::GetRemoteRTCPData(
3225 unsigned int& NTPHigh,
3226 unsigned int& NTPLow,
3227 unsigned int& timestamp,
3228 unsigned int& playoutTimestamp,
3229 unsigned int* jitter,
3230 unsigned short* fractionLost)
3231{
3232 // --- Information from sender info in received Sender Reports
3233
3234 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003235 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003236 {
3237 _engineStatisticsPtr->SetLastError(
3238 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003239 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003240 "side");
3241 return -1;
3242 }
3243
3244 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3245 // and octet count)
3246 NTPHigh = senderInfo.NTPseconds;
3247 NTPLow = senderInfo.NTPfraction;
3248 timestamp = senderInfo.RTPtimeStamp;
3249
3250 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3251 VoEId(_instanceId, _channelId),
3252 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3253 "timestamp=%lu",
3254 NTPHigh, NTPLow, timestamp);
3255
3256 // --- Locally derived information
3257
3258 // This value is updated on each incoming RTCP packet (0 when no packet
3259 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003260 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003261
3262 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3263 VoEId(_instanceId, _channelId),
3264 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003265 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003266
3267 if (NULL != jitter || NULL != fractionLost)
3268 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003269 // Get all RTCP receiver report blocks that have been received on this
3270 // channel. If we receive RTP packets from a remote source we know the
3271 // remote SSRC and use the report block from him.
3272 // Otherwise use the first report block.
3273 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003274 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003275 remote_stats.empty()) {
3276 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3277 VoEId(_instanceId, _channelId),
3278 "GetRemoteRTCPData() failed to measure statistics due"
3279 " to lack of received RTP and/or RTCP packets");
3280 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003282
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003283 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003284 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3285 for (; it != remote_stats.end(); ++it) {
3286 if (it->remoteSSRC == remoteSSRC)
3287 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003289
3290 if (it == remote_stats.end()) {
3291 // If we have not received any RTCP packets from this SSRC it probably
3292 // means that we have not received any RTP packets.
3293 // Use the first received report block instead.
3294 it = remote_stats.begin();
3295 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003297
xians@webrtc.org79af7342012-01-31 12:22:14 +00003298 if (jitter) {
3299 *jitter = it->jitter;
3300 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3301 VoEId(_instanceId, _channelId),
3302 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3303 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003304
xians@webrtc.org79af7342012-01-31 12:22:14 +00003305 if (fractionLost) {
3306 *fractionLost = it->fractionLost;
3307 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3308 VoEId(_instanceId, _channelId),
3309 "GetRemoteRTCPData() => fractionLost = %lu",
3310 *fractionLost);
3311 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003312 }
3313 return 0;
3314}
3315
3316int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003317Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003318 unsigned int name,
3319 const char* data,
3320 unsigned short dataLengthInBytes)
3321{
3322 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3323 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003324 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003325 {
3326 _engineStatisticsPtr->SetLastError(
3327 VE_NOT_SENDING, kTraceError,
3328 "SendApplicationDefinedRTCPPacket() not sending");
3329 return -1;
3330 }
3331 if (NULL == data)
3332 {
3333 _engineStatisticsPtr->SetLastError(
3334 VE_INVALID_ARGUMENT, kTraceError,
3335 "SendApplicationDefinedRTCPPacket() invalid data value");
3336 return -1;
3337 }
3338 if (dataLengthInBytes % 4 != 0)
3339 {
3340 _engineStatisticsPtr->SetLastError(
3341 VE_INVALID_ARGUMENT, kTraceError,
3342 "SendApplicationDefinedRTCPPacket() invalid length value");
3343 return -1;
3344 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003345 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003346 if (status == kRtcpOff)
3347 {
3348 _engineStatisticsPtr->SetLastError(
3349 VE_RTCP_ERROR, kTraceError,
3350 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3351 return -1;
3352 }
3353
3354 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003355 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003356 subType,
3357 name,
3358 (const unsigned char*) data,
3359 dataLengthInBytes) != 0)
3360 {
3361 _engineStatisticsPtr->SetLastError(
3362 VE_SEND_ERROR, kTraceError,
3363 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3364 return -1;
3365 }
3366 return 0;
3367}
3368
3369int
3370Channel::GetRTPStatistics(
3371 unsigned int& averageJitterMs,
3372 unsigned int& maxJitterMs,
3373 unsigned int& discardedPackets)
3374{
niklase@google.com470e71d2011-07-07 08:21:25 +00003375 // The jitter statistics is updated for each received RTP packet and is
3376 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003377 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3378 // If RTCP is off, there is no timed thread in the RTCP module regularly
3379 // generating new stats, trigger the update manually here instead.
3380 StreamStatistician* statistician =
3381 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3382 if (statistician) {
3383 // Don't use returned statistics, use data from proxy instead so that
3384 // max jitter can be fetched atomically.
3385 RtcpStatistics s;
3386 statistician->GetStatistics(&s, true);
3387 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003388 }
3389
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003390 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003391 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003392 if (playoutFrequency > 0) {
3393 // Scale RTP statistics given the current playout frequency
3394 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3395 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003396 }
3397
3398 discardedPackets = _numberOfDiscardedPackets;
3399
3400 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3401 VoEId(_instanceId, _channelId),
3402 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003403 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003404 averageJitterMs, maxJitterMs, discardedPackets);
3405 return 0;
3406}
3407
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003408int Channel::GetRemoteRTCPReportBlocks(
3409 std::vector<ReportBlock>* report_blocks) {
3410 if (report_blocks == NULL) {
3411 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3412 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3413 return -1;
3414 }
3415
3416 // Get the report blocks from the latest received RTCP Sender or Receiver
3417 // Report. Each element in the vector contains the sender's SSRC and a
3418 // report block according to RFC 3550.
3419 std::vector<RTCPReportBlock> rtcp_report_blocks;
3420 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3421 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3422 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3423 return -1;
3424 }
3425
3426 if (rtcp_report_blocks.empty())
3427 return 0;
3428
3429 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3430 for (; it != rtcp_report_blocks.end(); ++it) {
3431 ReportBlock report_block;
3432 report_block.sender_SSRC = it->remoteSSRC;
3433 report_block.source_SSRC = it->sourceSSRC;
3434 report_block.fraction_lost = it->fractionLost;
3435 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3436 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3437 report_block.interarrival_jitter = it->jitter;
3438 report_block.last_SR_timestamp = it->lastSR;
3439 report_block.delay_since_last_SR = it->delaySinceLastSR;
3440 report_blocks->push_back(report_block);
3441 }
3442 return 0;
3443}
3444
niklase@google.com470e71d2011-07-07 08:21:25 +00003445int
3446Channel::GetRTPStatistics(CallStatistics& stats)
3447{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003448 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003449
3450 // The jitter statistics is updated for each received RTP packet and is
3451 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003452 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003453 StreamStatistician* statistician =
3454 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3455 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003456 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3457 _engineStatisticsPtr->SetLastError(
3458 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3459 "GetRTPStatistics() failed to read RTP statistics from the "
3460 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003461 }
3462
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003463 stats.fractionLost = statistics.fraction_lost;
3464 stats.cumulativeLost = statistics.cumulative_lost;
3465 stats.extendedMax = statistics.extended_max_sequence_number;
3466 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003467
3468 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3469 VoEId(_instanceId, _channelId),
3470 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003471 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003472 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3473 stats.jitterSamples);
3474
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003475 // --- RTT
niklase@google.com470e71d2011-07-07 08:21:25 +00003476
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003477 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003478 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003479 if (method == kRtcpOff)
3480 {
3481 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3482 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003483 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003484 "measurements cannot be retrieved");
3485 } else
3486 {
3487 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003488 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003489 if (remoteSSRC > 0)
3490 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003491 uint16_t avgRTT(0);
3492 uint16_t maxRTT(0);
3493 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003494
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003495 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003496 != 0)
3497 {
3498 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3499 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003500 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003501 "the RTP/RTCP module");
3502 }
3503 } else
3504 {
3505 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3506 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003507 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003508 "RTP packets have been received yet");
3509 }
3510 }
3511
3512 stats.rttMs = static_cast<int> (RTT);
3513
3514 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3515 VoEId(_instanceId, _channelId),
3516 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3517
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003518 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003519
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003520 uint32_t bytesSent(0);
3521 uint32_t packetsSent(0);
3522 uint32_t bytesReceived(0);
3523 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003524
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003525 if (statistician) {
3526 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3527 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003528
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003529 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003530 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003531 {
3532 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3533 VoEId(_instanceId, _channelId),
3534 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003535 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003536 }
3537
3538 stats.bytesSent = bytesSent;
3539 stats.packetsSent = packetsSent;
3540 stats.bytesReceived = bytesReceived;
3541 stats.packetsReceived = packetsReceived;
3542
3543 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3544 VoEId(_instanceId, _channelId),
3545 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003546 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003547 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3548 stats.packetsReceived);
3549
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003550 // --- Timestamps
3551 {
3552 CriticalSectionScoped lock(ts_stats_lock_.get());
3553 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3554 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003555 return 0;
3556}
3557
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003558int Channel::SetREDStatus(bool enable, int redPayloadtype) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003560 "Channel::SetREDStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003561
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003562 if (enable) {
3563 if (redPayloadtype < 0 || redPayloadtype > 127) {
3564 _engineStatisticsPtr->SetLastError(
3565 VE_PLTYPE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003566 "SetREDStatus() invalid RED payload type");
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003567 return -1;
3568 }
3569
3570 if (SetRedPayloadType(redPayloadtype) < 0) {
3571 _engineStatisticsPtr->SetLastError(
3572 VE_CODEC_ERROR, kTraceError,
3573 "SetSecondarySendCodec() Failed to register RED ACM");
3574 return -1;
3575 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003576 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003577
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003578 if (audio_coding_->SetREDStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003579 _engineStatisticsPtr->SetLastError(
3580 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003581 "SetREDStatus() failed to set RED state in the ACM");
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003582 return -1;
3583 }
3584 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003585}
3586
3587int
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003588Channel::GetREDStatus(bool& enabled, int& redPayloadtype)
niklase@google.com470e71d2011-07-07 08:21:25 +00003589{
minyue@webrtc.orgaa5ea1c2014-05-23 15:16:51 +00003590 enabled = audio_coding_->REDStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003591 if (enabled)
3592 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003593 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003594 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003595 {
3596 _engineStatisticsPtr->SetLastError(
3597 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003598 "GetREDStatus() failed to retrieve RED PT from RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00003599 "module");
3600 return -1;
3601 }
3602 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3603 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003604 "GetREDStatus() => enabled=%d, redPayloadtype=%d",
niklase@google.com470e71d2011-07-07 08:21:25 +00003605 enabled, redPayloadtype);
3606 return 0;
3607 }
3608 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3609 VoEId(_instanceId, _channelId),
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003610 "GetREDStatus() => enabled=%d", enabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003611 return 0;
3612}
3613
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00003614int Channel::SetCodecFECStatus(bool enable) {
3615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3616 "Channel::SetCodecFECStatus()");
3617
3618 if (audio_coding_->SetCodecFEC(enable) != 0) {
3619 _engineStatisticsPtr->SetLastError(
3620 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3621 "SetCodecFECStatus() failed to set FEC state");
3622 return -1;
3623 }
3624 return 0;
3625}
3626
3627bool Channel::GetCodecFECStatus() {
3628 bool enabled = audio_coding_->CodecFEC();
3629 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3630 VoEId(_instanceId, _channelId),
3631 "GetCodecFECStatus() => enabled=%d", enabled);
3632 return enabled;
3633}
3634
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003635void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3636 // None of these functions can fail.
3637 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003638 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3639 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003640 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003641 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003642 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003643 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003644}
3645
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003646// Called when we are missing one or more packets.
3647int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003648 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3649}
3650
niklase@google.com470e71d2011-07-07 08:21:25 +00003651int
niklase@google.com470e71d2011-07-07 08:21:25 +00003652Channel::StartRTPDump(const char fileNameUTF8[1024],
3653 RTPDirections direction)
3654{
3655 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3656 "Channel::StartRTPDump()");
3657 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3658 {
3659 _engineStatisticsPtr->SetLastError(
3660 VE_INVALID_ARGUMENT, kTraceError,
3661 "StartRTPDump() invalid RTP direction");
3662 return -1;
3663 }
3664 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3665 &_rtpDumpIn : &_rtpDumpOut;
3666 if (rtpDumpPtr == NULL)
3667 {
3668 assert(false);
3669 return -1;
3670 }
3671 if (rtpDumpPtr->IsActive())
3672 {
3673 rtpDumpPtr->Stop();
3674 }
3675 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3676 {
3677 _engineStatisticsPtr->SetLastError(
3678 VE_BAD_FILE, kTraceError,
3679 "StartRTPDump() failed to create file");
3680 return -1;
3681 }
3682 return 0;
3683}
3684
3685int
3686Channel::StopRTPDump(RTPDirections direction)
3687{
3688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3689 "Channel::StopRTPDump()");
3690 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3691 {
3692 _engineStatisticsPtr->SetLastError(
3693 VE_INVALID_ARGUMENT, kTraceError,
3694 "StopRTPDump() invalid RTP direction");
3695 return -1;
3696 }
3697 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3698 &_rtpDumpIn : &_rtpDumpOut;
3699 if (rtpDumpPtr == NULL)
3700 {
3701 assert(false);
3702 return -1;
3703 }
3704 if (!rtpDumpPtr->IsActive())
3705 {
3706 return 0;
3707 }
3708 return rtpDumpPtr->Stop();
3709}
3710
3711bool
3712Channel::RTPDumpIsActive(RTPDirections direction)
3713{
3714 if ((direction != kRtpIncoming) &&
3715 (direction != kRtpOutgoing))
3716 {
3717 _engineStatisticsPtr->SetLastError(
3718 VE_INVALID_ARGUMENT, kTraceError,
3719 "RTPDumpIsActive() invalid RTP direction");
3720 return false;
3721 }
3722 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3723 &_rtpDumpIn : &_rtpDumpOut;
3724 return rtpDumpPtr->IsActive();
3725}
3726
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003727void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3728 int video_channel) {
3729 CriticalSectionScoped cs(&_callbackCritSect);
3730 if (vie_network_) {
3731 vie_network_->Release();
3732 vie_network_ = NULL;
3733 }
3734 video_channel_ = -1;
3735
3736 if (vie_network != NULL && video_channel != -1) {
3737 vie_network_ = vie_network;
3738 video_channel_ = video_channel;
3739 }
3740}
3741
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003742uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003743Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003744{
3745 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003746 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003747 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003748 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003749 return 0;
3750}
3751
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003752void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003753 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003754 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003755 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003756 CodecInst codec;
3757 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003758
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003759 if (!mono_recording_audio_.get()) {
3760 // Temporary space for DownConvertToCodecFormat.
3761 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003762 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003763 DownConvertToCodecFormat(audio_data,
3764 number_of_frames,
3765 number_of_channels,
3766 sample_rate,
3767 codec.channels,
3768 codec.plfreq,
3769 mono_recording_audio_.get(),
3770 &input_resampler_,
3771 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003772}
3773
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003774uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003775Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003776{
3777 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3778 "Channel::PrepareEncodeAndSend()");
3779
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003780 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003781 {
3782 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3783 "Channel::PrepareEncodeAndSend() invalid audio frame");
3784 return -1;
3785 }
3786
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003787 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003788 {
3789 MixOrReplaceAudioWithFile(mixingFrequency);
3790 }
3791
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003792 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3793 if (is_muted) {
3794 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003795 }
3796
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003797 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003798 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003799 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003800 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003801 if (_inputExternalMediaCallbackPtr)
3802 {
3803 _inputExternalMediaCallbackPtr->Process(
3804 _channelId,
3805 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003806 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003807 _audioFrame.samples_per_channel_,
3808 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003809 isStereo);
3810 }
3811 }
3812
3813 InsertInbandDtmfTone();
3814
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003815 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003816 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003817 if (is_muted) {
3818 rms_level_.ProcessMuted(length);
3819 } else {
3820 rms_level_.Process(_audioFrame.data_, length);
3821 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003822 }
3823
niklase@google.com470e71d2011-07-07 08:21:25 +00003824 return 0;
3825}
3826
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003827uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003828Channel::EncodeAndSend()
3829{
3830 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3831 "Channel::EncodeAndSend()");
3832
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003833 assert(_audioFrame.num_channels_ <= 2);
3834 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003835 {
3836 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3837 "Channel::EncodeAndSend() invalid audio frame");
3838 return -1;
3839 }
3840
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003841 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003842
3843 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3844
3845 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003846 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003847 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003848 {
3849 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3850 "Channel::EncodeAndSend() ACM encoding failed");
3851 return -1;
3852 }
3853
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003854 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003855
3856 // --- Encode if complete frame is ready
3857
3858 // This call will trigger AudioPacketizationCallback::SendData if encoding
3859 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003860 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003861}
3862
3863int Channel::RegisterExternalMediaProcessing(
3864 ProcessingTypes type,
3865 VoEMediaProcess& processObject)
3866{
3867 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3868 "Channel::RegisterExternalMediaProcessing()");
3869
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003870 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003871
3872 if (kPlaybackPerChannel == type)
3873 {
3874 if (_outputExternalMediaCallbackPtr)
3875 {
3876 _engineStatisticsPtr->SetLastError(
3877 VE_INVALID_OPERATION, kTraceError,
3878 "Channel::RegisterExternalMediaProcessing() "
3879 "output external media already enabled");
3880 return -1;
3881 }
3882 _outputExternalMediaCallbackPtr = &processObject;
3883 _outputExternalMedia = true;
3884 }
3885 else if (kRecordingPerChannel == type)
3886 {
3887 if (_inputExternalMediaCallbackPtr)
3888 {
3889 _engineStatisticsPtr->SetLastError(
3890 VE_INVALID_OPERATION, kTraceError,
3891 "Channel::RegisterExternalMediaProcessing() "
3892 "output external media already enabled");
3893 return -1;
3894 }
3895 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003896 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003897 }
3898 return 0;
3899}
3900
3901int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3902{
3903 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3904 "Channel::DeRegisterExternalMediaProcessing()");
3905
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003906 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003907
3908 if (kPlaybackPerChannel == type)
3909 {
3910 if (!_outputExternalMediaCallbackPtr)
3911 {
3912 _engineStatisticsPtr->SetLastError(
3913 VE_INVALID_OPERATION, kTraceWarning,
3914 "Channel::DeRegisterExternalMediaProcessing() "
3915 "output external media already disabled");
3916 return 0;
3917 }
3918 _outputExternalMedia = false;
3919 _outputExternalMediaCallbackPtr = NULL;
3920 }
3921 else if (kRecordingPerChannel == type)
3922 {
3923 if (!_inputExternalMediaCallbackPtr)
3924 {
3925 _engineStatisticsPtr->SetLastError(
3926 VE_INVALID_OPERATION, kTraceWarning,
3927 "Channel::DeRegisterExternalMediaProcessing() "
3928 "input external media already disabled");
3929 return 0;
3930 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003931 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003932 _inputExternalMediaCallbackPtr = NULL;
3933 }
3934
3935 return 0;
3936}
3937
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003938int Channel::SetExternalMixing(bool enabled) {
3939 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3940 "Channel::SetExternalMixing(enabled=%d)", enabled);
3941
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003942 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003943 {
3944 _engineStatisticsPtr->SetLastError(
3945 VE_INVALID_OPERATION, kTraceError,
3946 "Channel::SetExternalMixing() "
3947 "external mixing cannot be changed while playing.");
3948 return -1;
3949 }
3950
3951 _externalMixing = enabled;
3952
3953 return 0;
3954}
3955
niklase@google.com470e71d2011-07-07 08:21:25 +00003956int
niklase@google.com470e71d2011-07-07 08:21:25 +00003957Channel::GetNetworkStatistics(NetworkStatistics& stats)
3958{
3959 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3960 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003961 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003962 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003963 if (return_value >= 0) {
3964 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3965 }
3966 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003967}
3968
wu@webrtc.org24301a62013-12-13 19:17:43 +00003969void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3970 audio_coding_->GetDecodingCallStatistics(stats);
3971}
3972
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003973bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3974 int* playout_buffer_delay_ms) const {
3975 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003976 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003977 "Channel::GetDelayEstimate() no valid estimate.");
3978 return false;
3979 }
3980 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3981 _recPacketDelayMs;
3982 *playout_buffer_delay_ms = playout_delay_ms_;
3983 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3984 "Channel::GetDelayEstimate()");
3985 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003986}
3987
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003988int Channel::SetInitialPlayoutDelay(int delay_ms)
3989{
3990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3991 "Channel::SetInitialPlayoutDelay()");
3992 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3993 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3994 {
3995 _engineStatisticsPtr->SetLastError(
3996 VE_INVALID_ARGUMENT, kTraceError,
3997 "SetInitialPlayoutDelay() invalid min delay");
3998 return -1;
3999 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004000 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004001 {
4002 _engineStatisticsPtr->SetLastError(
4003 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4004 "SetInitialPlayoutDelay() failed to set min playout delay");
4005 return -1;
4006 }
4007 return 0;
4008}
4009
4010
niklase@google.com470e71d2011-07-07 08:21:25 +00004011int
4012Channel::SetMinimumPlayoutDelay(int delayMs)
4013{
4014 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4015 "Channel::SetMinimumPlayoutDelay()");
4016 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4017 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4018 {
4019 _engineStatisticsPtr->SetLastError(
4020 VE_INVALID_ARGUMENT, kTraceError,
4021 "SetMinimumPlayoutDelay() invalid min delay");
4022 return -1;
4023 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004024 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004025 {
4026 _engineStatisticsPtr->SetLastError(
4027 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4028 "SetMinimumPlayoutDelay() failed to set min playout delay");
4029 return -1;
4030 }
4031 return 0;
4032}
4033
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004034void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4035 uint32_t playout_timestamp = 0;
4036
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004037 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004038 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4039 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4040 " timestamp from the ACM");
4041 _engineStatisticsPtr->SetLastError(
4042 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4043 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4044 return;
4045 }
4046
4047 uint16_t delay_ms = 0;
4048 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4049 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4050 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4051 " delay from the ADM");
4052 _engineStatisticsPtr->SetLastError(
4053 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4054 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4055 return;
4056 }
4057
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004058 jitter_buffer_playout_timestamp_ = playout_timestamp;
4059
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004060 // Remove the playout delay.
wu@webrtc.org94454b72014-06-05 20:34:08 +00004061 playout_timestamp -= (delay_ms * (GetPlayoutFrequency() / 1000));
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004062
4063 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4064 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4065 playout_timestamp);
4066
4067 if (rtcp) {
4068 playout_timestamp_rtcp_ = playout_timestamp;
4069 } else {
4070 playout_timestamp_rtp_ = playout_timestamp;
4071 }
4072 playout_delay_ms_ = delay_ms;
4073}
4074
4075int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4076 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4077 "Channel::GetPlayoutTimestamp()");
4078 if (playout_timestamp_rtp_ == 0) {
4079 _engineStatisticsPtr->SetLastError(
4080 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4081 "GetPlayoutTimestamp() failed to retrieve timestamp");
4082 return -1;
4083 }
4084 timestamp = playout_timestamp_rtp_;
4085 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4086 VoEId(_instanceId,_channelId),
4087 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4088 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004089}
4090
4091int
4092Channel::SetInitTimestamp(unsigned int timestamp)
4093{
4094 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4095 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004096 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004097 {
4098 _engineStatisticsPtr->SetLastError(
4099 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4100 return -1;
4101 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004102 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004103 {
4104 _engineStatisticsPtr->SetLastError(
4105 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4106 "SetInitTimestamp() failed to set timestamp");
4107 return -1;
4108 }
4109 return 0;
4110}
4111
4112int
4113Channel::SetInitSequenceNumber(short sequenceNumber)
4114{
4115 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4116 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004117 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004118 {
4119 _engineStatisticsPtr->SetLastError(
4120 VE_SENDING, kTraceError,
4121 "SetInitSequenceNumber() already sending");
4122 return -1;
4123 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004124 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004125 {
4126 _engineStatisticsPtr->SetLastError(
4127 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4128 "SetInitSequenceNumber() failed to set sequence number");
4129 return -1;
4130 }
4131 return 0;
4132}
4133
4134int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004135Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004136{
4137 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4138 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004139 *rtpRtcpModule = _rtpRtcpModule.get();
4140 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004141 return 0;
4142}
4143
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004144// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4145// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004146int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004147Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004148{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004149 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004150 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004151
4152 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004153 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004154
4155 if (_inputFilePlayerPtr == NULL)
4156 {
4157 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4158 VoEId(_instanceId, _channelId),
4159 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4160 " doesnt exist");
4161 return -1;
4162 }
4163
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004164 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004165 fileSamples,
4166 mixingFrequency) == -1)
4167 {
4168 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4169 VoEId(_instanceId, _channelId),
4170 "Channel::MixOrReplaceAudioWithFile() file mixing "
4171 "failed");
4172 return -1;
4173 }
4174 if (fileSamples == 0)
4175 {
4176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4177 VoEId(_instanceId, _channelId),
4178 "Channel::MixOrReplaceAudioWithFile() file is ended");
4179 return 0;
4180 }
4181 }
4182
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004183 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004184
4185 if (_mixFileWithMicrophone)
4186 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004187 // Currently file stream is always mono.
4188 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004189 MixWithSat(_audioFrame.data_,
4190 _audioFrame.num_channels_,
4191 fileBuffer.get(),
4192 1,
4193 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004194 }
4195 else
4196 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004197 // Replace ACM audio with file.
4198 // Currently file stream is always mono.
4199 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004200 _audioFrame.UpdateFrame(_channelId,
4201 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004202 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004203 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004204 mixingFrequency,
4205 AudioFrame::kNormalSpeech,
4206 AudioFrame::kVadUnknown,
4207 1);
4208
4209 }
4210 return 0;
4211}
4212
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004213int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004214Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004215 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004216{
4217 assert(mixingFrequency <= 32000);
4218
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004219 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004220 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004221
4222 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004223 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004224
4225 if (_outputFilePlayerPtr == NULL)
4226 {
4227 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4228 VoEId(_instanceId, _channelId),
4229 "Channel::MixAudioWithFile() file mixing failed");
4230 return -1;
4231 }
4232
4233 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004234 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004235 fileSamples,
4236 mixingFrequency) == -1)
4237 {
4238 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4239 VoEId(_instanceId, _channelId),
4240 "Channel::MixAudioWithFile() file mixing failed");
4241 return -1;
4242 }
4243 }
4244
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004245 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004246 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004247 // Currently file stream is always mono.
4248 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004249 MixWithSat(audioFrame.data_,
4250 audioFrame.num_channels_,
4251 fileBuffer.get(),
4252 1,
4253 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004254 }
4255 else
4256 {
4257 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004258 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004259 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004260 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004261 return -1;
4262 }
4263
4264 return 0;
4265}
4266
4267int
4268Channel::InsertInbandDtmfTone()
4269{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004270 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004271 if (_inbandDtmfQueue.PendingDtmf() &&
4272 !_inbandDtmfGenerator.IsAddingTone() &&
4273 _inbandDtmfGenerator.DelaySinceLastTone() >
4274 kMinTelephoneEventSeparationMs)
4275 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004276 int8_t eventCode(0);
4277 uint16_t lengthMs(0);
4278 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004279
4280 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4281 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4282 if (_playInbandDtmfEvent)
4283 {
4284 // Add tone to output mixer using a reduced length to minimize
4285 // risk of echo.
4286 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4287 attenuationDb);
4288 }
4289 }
4290
4291 if (_inbandDtmfGenerator.IsAddingTone())
4292 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004293 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004294 _inbandDtmfGenerator.GetSampleRate(frequency);
4295
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004296 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004297 {
4298 // Update sample rate of Dtmf tone since the mixing frequency
4299 // has changed.
4300 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004301 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004302 // Reset the tone to be added taking the new sample rate into
4303 // account.
4304 _inbandDtmfGenerator.ResetTone();
4305 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004306
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004307 int16_t toneBuffer[320];
4308 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004309 // Get 10ms tone segment and set time since last tone to zero
4310 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4311 {
4312 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4313 VoEId(_instanceId, _channelId),
4314 "Channel::EncodeAndSend() inserting Dtmf failed");
4315 return -1;
4316 }
4317
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004318 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004319 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004320 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004321 sample++)
4322 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004323 for (int channel = 0;
4324 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004325 channel++)
4326 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004327 const int index = sample * _audioFrame.num_channels_ + channel;
4328 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004329 }
4330 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004331
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004332 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004333 } else
4334 {
4335 // Add 10ms to "delay-since-last-tone" counter
4336 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4337 }
4338 return 0;
4339}
4340
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004341int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004342Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4343{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004344 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004345 if (_transportPtr == NULL)
4346 {
4347 return -1;
4348 }
4349 if (!RTCP)
4350 {
4351 return _transportPtr->SendPacket(_channelId, data, len);
4352 }
4353 else
4354 {
4355 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4356 }
4357}
4358
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004359// Called for incoming RTP packets after successful RTP header parsing.
4360void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4361 uint16_t sequence_number) {
4362 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4363 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4364 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004365
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004366 // Get frequency of last received payload
wu@webrtc.org94454b72014-06-05 20:34:08 +00004367 int rtp_receive_frequency = GetPlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004368
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004369 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004370 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004371
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004372 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4373 // every incoming packet.
4374 uint32_t timestamp_diff_ms = (rtp_timestamp -
4375 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004376 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4377 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4378 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4379 // timestamp, the resulting difference is negative, but is set to zero.
4380 // This can happen when a network glitch causes a packet to arrive late,
4381 // and during long comfort noise periods with clock drift.
4382 timestamp_diff_ms = 0;
4383 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004384
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004385 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4386 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004387
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004388 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004389
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004390 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004391
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004392 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4393 _recPacketDelayMs = packet_delay_ms;
4394 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004395
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004396 if (_average_jitter_buffer_delay_us == 0) {
4397 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4398 return;
4399 }
4400
4401 // Filter average delay value using exponential filter (alpha is
4402 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4403 // risk of rounding error) and compensate for it in GetDelayEstimate()
4404 // later.
4405 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4406 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004407}
4408
4409void
4410Channel::RegisterReceiveCodecsToRTPModule()
4411{
4412 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4413 "Channel::RegisterReceiveCodecsToRTPModule()");
4414
4415
4416 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004417 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004418
4419 for (int idx = 0; idx < nSupportedCodecs; idx++)
4420 {
4421 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004422 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004423 (rtp_receiver_->RegisterReceivePayload(
4424 codec.plname,
4425 codec.pltype,
4426 codec.plfreq,
4427 codec.channels,
4428 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004429 {
4430 WEBRTC_TRACE(
4431 kTraceWarning,
4432 kTraceVoice,
4433 VoEId(_instanceId, _channelId),
4434 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4435 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4436 codec.plname, codec.pltype, codec.plfreq,
4437 codec.channels, codec.rate);
4438 }
4439 else
4440 {
4441 WEBRTC_TRACE(
4442 kTraceInfo,
4443 kTraceVoice,
4444 VoEId(_instanceId, _channelId),
4445 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004446 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004447 "receiver",
4448 codec.plname, codec.pltype, codec.plfreq,
4449 codec.channels, codec.rate);
4450 }
4451 }
4452}
4453
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004454int Channel::SetSecondarySendCodec(const CodecInst& codec,
4455 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004456 // Sanity check for payload type.
4457 if (red_payload_type < 0 || red_payload_type > 127) {
4458 _engineStatisticsPtr->SetLastError(
4459 VE_PLTYPE_ERROR, kTraceError,
4460 "SetRedPayloadType() invalid RED payload type");
4461 return -1;
4462 }
4463
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004464 if (SetRedPayloadType(red_payload_type) < 0) {
4465 _engineStatisticsPtr->SetLastError(
4466 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4467 "SetSecondarySendCodec() Failed to register RED ACM");
4468 return -1;
4469 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004470 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004471 _engineStatisticsPtr->SetLastError(
4472 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4473 "SetSecondarySendCodec() Failed to register secondary send codec in "
4474 "ACM");
4475 return -1;
4476 }
4477
4478 return 0;
4479}
4480
4481void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004482 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004483}
4484
4485int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004486 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004487 _engineStatisticsPtr->SetLastError(
4488 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4489 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4490 return -1;
4491 }
4492 return 0;
4493}
4494
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004495// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004496int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004497 CodecInst codec;
4498 bool found_red = false;
4499
4500 // Get default RED settings from the ACM database
4501 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4502 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004503 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004504 if (!STR_CASE_CMP(codec.plname, "RED")) {
4505 found_red = true;
4506 break;
4507 }
4508 }
4509
4510 if (!found_red) {
4511 _engineStatisticsPtr->SetLastError(
4512 VE_CODEC_ERROR, kTraceError,
4513 "SetRedPayloadType() RED is not supported");
4514 return -1;
4515 }
4516
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004517 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004518 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004519 _engineStatisticsPtr->SetLastError(
4520 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4521 "SetRedPayloadType() RED registration in ACM module failed");
4522 return -1;
4523 }
4524
4525 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4526 _engineStatisticsPtr->SetLastError(
4527 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4528 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4529 return -1;
4530 }
4531 return 0;
4532}
4533
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004534int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4535 unsigned char id) {
4536 int error = 0;
4537 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4538 if (enable) {
4539 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4540 }
4541 return error;
4542}
minyue@webrtc.orgc1a40a72014-05-28 09:52:06 +00004543
wu@webrtc.org94454b72014-06-05 20:34:08 +00004544int32_t Channel::GetPlayoutFrequency() {
4545 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
4546 CodecInst current_recive_codec;
4547 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
4548 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4549 // Even though the actual sampling rate for G.722 audio is
4550 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4551 // 8,000 Hz because that value was erroneously assigned in
4552 // RFC 1890 and must remain unchanged for backward compatibility.
4553 playout_frequency = 8000;
4554 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4555 // We are resampling Opus internally to 32,000 Hz until all our
4556 // DSP routines can operate at 48,000 Hz, but the RTP clock
4557 // rate for the Opus payload format is standardized to 48,000 Hz,
4558 // because that is the maximum supported decoding sampling rate.
4559 playout_frequency = 48000;
4560 }
4561 }
4562 return playout_frequency;
4563}
4564
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004565} // namespace voe
4566} // namespace webrtc