blob: 2c75a7901980bf55a9d7a5bddacf5dae542c27fb [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000016#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000017#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
19#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
20#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000021#include "webrtc/modules/utility/interface/audio_frame_operations.h"
22#include "webrtc/modules/utility/interface/process_thread.h"
23#include "webrtc/modules/utility/interface/rtp_dump.h"
24#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
25#include "webrtc/system_wrappers/interface/logging.h"
26#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000027#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000028#include "webrtc/voice_engine/include/voe_base.h"
29#include "webrtc/voice_engine/include/voe_external_media.h"
30#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
31#include "webrtc/voice_engine/output_mixer.h"
32#include "webrtc/voice_engine/statistics.h"
33#include "webrtc/voice_engine/transmit_mixer.h"
34#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36#if defined(_WIN32)
37#include <Qos.h>
38#endif
39
andrew@webrtc.org50419b02012-11-14 19:07:54 +000040namespace webrtc {
41namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000042
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000043// Extend the default RTCP statistics struct with max_jitter, defined as the
44// maximum jitter value seen in an RTCP report block.
45struct ChannelStatistics : public RtcpStatistics {
46 ChannelStatistics() : rtcp(), max_jitter(0) {}
47
48 RtcpStatistics rtcp;
49 uint32_t max_jitter;
50};
51
52// Statistics callback, called at each generation of a new RTCP report block.
53class StatisticsProxy : public RtcpStatisticsCallback {
54 public:
55 StatisticsProxy(uint32_t ssrc)
56 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
57 ssrc_(ssrc) {}
58 virtual ~StatisticsProxy() {}
59
60 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
61 uint32_t ssrc) OVERRIDE {
62 if (ssrc != ssrc_)
63 return;
64
65 CriticalSectionScoped cs(stats_lock_.get());
66 stats_.rtcp = statistics;
67 if (statistics.jitter > stats_.max_jitter) {
68 stats_.max_jitter = statistics.jitter;
69 }
70 }
71
72 void ResetStatistics() {
73 CriticalSectionScoped cs(stats_lock_.get());
74 stats_ = ChannelStatistics();
75 }
76
77 ChannelStatistics GetStats() {
78 CriticalSectionScoped cs(stats_lock_.get());
79 return stats_;
80 }
81
82 private:
83 // StatisticsUpdated calls are triggered from threads in the RTP module,
84 // while GetStats calls can be triggered from the public voice engine API,
85 // hence synchronization is needed.
86 scoped_ptr<CriticalSectionWrapper> stats_lock_;
87 const uint32_t ssrc_;
88 ChannelStatistics stats_;
89};
90
pbos@webrtc.org6141e132013-04-09 10:09:10 +000091int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000092Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000093 uint8_t payloadType,
94 uint32_t timeStamp,
95 const uint8_t* payloadData,
96 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000097 const RTPFragmentationHeader* fragmentation)
98{
99 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
100 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
101 " payloadSize=%u, fragmentation=0x%x)",
102 frameType, payloadType, timeStamp, payloadSize, fragmentation);
103
104 if (_includeAudioLevelIndication)
105 {
106 // Store current audio level in the RTP/RTCP module.
107 // The level will be used in combination with voice-activity state
108 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000109 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
111
112 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
113 // packetization.
114 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000115 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 payloadType,
117 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000118 // Leaving the time when this frame was
119 // received from the capture device as
120 // undefined for voice for now.
121 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000122 payloadData,
123 payloadSize,
124 fragmentation) == -1)
125 {
126 _engineStatisticsPtr->SetLastError(
127 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
128 "Channel::SendData() failed to send data to RTP/RTCP module");
129 return -1;
130 }
131
132 _lastLocalTimeStamp = timeStamp;
133 _lastPayloadType = payloadType;
134
135 return 0;
136}
137
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000138int32_t
139Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000140{
141 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
142 "Channel::InFrameType(frameType=%d)", frameType);
143
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000144 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 // 1 indicates speech
146 _sendFrameType = (frameType == 1) ? 1 : 0;
147 return 0;
148}
149
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000151Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152{
153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
154 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
155
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000156 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 if (_rxVadObserverPtr)
158 {
159 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
160 }
161
162 return 0;
163}
164
165int
166Channel::SendPacket(int channel, const void *data, int len)
167{
168 channel = VoEChannelId(channel);
169 assert(channel == _channelId);
170
171 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
172 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
173
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000174 CriticalSectionScoped cs(&_callbackCritSect);
175
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 if (_transportPtr == NULL)
177 {
178 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
179 "Channel::SendPacket() failed to send RTP packet due to"
180 " invalid transport object");
181 return -1;
182 }
183
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000184 uint8_t* bufferToSendPtr = (uint8_t*)data;
185 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000186
187 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000188 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 {
190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
191 VoEId(_instanceId,_channelId),
192 "Channel::SendPacket() RTP dump to output file failed");
193 }
194
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000195 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
196 bufferLength);
197 if (n < 0) {
198 std::string transport_name =
199 _externalTransport ? "external transport" : "WebRtc sockets";
200 WEBRTC_TRACE(kTraceError, kTraceVoice,
201 VoEId(_instanceId,_channelId),
202 "Channel::SendPacket() RTP transmission using %s failed",
203 transport_name.c_str());
204 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000206 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207}
208
209int
210Channel::SendRTCPPacket(int channel, const void *data, int len)
211{
212 channel = VoEChannelId(channel);
213 assert(channel == _channelId);
214
215 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
216 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
217
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000218 CriticalSectionScoped cs(&_callbackCritSect);
219 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000221 WEBRTC_TRACE(kTraceError, kTraceVoice,
222 VoEId(_instanceId,_channelId),
223 "Channel::SendRTCPPacket() failed to send RTCP packet"
224 " due to invalid transport object");
225 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 }
227
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000228 uint8_t* bufferToSendPtr = (uint8_t*)data;
229 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
231 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000232 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 {
234 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
235 VoEId(_instanceId,_channelId),
236 "Channel::SendPacket() RTCP dump to output file failed");
237 }
238
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000239 int n = _transportPtr->SendRTCPPacket(channel,
240 bufferToSendPtr,
241 bufferLength);
242 if (n < 0) {
243 std::string transport_name =
244 _externalTransport ? "external transport" : "WebRtc sockets";
245 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
246 VoEId(_instanceId,_channelId),
247 "Channel::SendRTCPPacket() transmission using %s failed",
248 transport_name.c_str());
249 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000251 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252}
253
254void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000255Channel::OnPlayTelephoneEvent(int32_t id,
256 uint8_t event,
257 uint16_t lengthMs,
258 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000259{
260 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
261 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000262 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263
264 if (!_playOutbandDtmfEvent || (event > 15))
265 {
266 // Ignore callback since feedback is disabled or event is not a
267 // Dtmf tone event.
268 return;
269 }
270
271 assert(_outputMixerPtr != NULL);
272
273 // Start playing out the Dtmf tone (if playout is enabled).
274 // Reduce length of tone with 80ms to the reduce risk of echo.
275 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
276}
277
278void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000279Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000280{
281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
282 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000283 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000284
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000285 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000286 assert(channel == _channelId);
287
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000288 // Update ssrc so that NTP for AV sync can be updated.
289 _rtpRtcpModule->SetRemoteSSRC(ssrc);
290
niklase@google.com470e71d2011-07-07 08:21:25 +0000291 if (_rtpObserver)
292 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000293 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000294
295 if (_rtpObserverPtr)
296 {
297 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000298 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000299 }
300 }
301}
302
pbos@webrtc.org92135212013-05-14 08:31:39 +0000303void Channel::OnIncomingCSRCChanged(int32_t id,
304 uint32_t CSRC,
305 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000306{
307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
308 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
309 id, CSRC, added);
310
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000311 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000312 assert(channel == _channelId);
313
314 if (_rtpObserver)
315 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000316 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000317
318 if (_rtpObserverPtr)
319 {
320 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
321 }
322 }
323}
324
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000325void Channel::ResetStatistics(uint32_t ssrc) {
326 StreamStatistician* statistician =
327 rtp_receive_statistics_->GetStatistician(ssrc);
328 if (statistician) {
329 statistician->ResetStatistics();
330 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000331 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000332}
333
niklase@google.com470e71d2011-07-07 08:21:25 +0000334void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000335Channel::OnApplicationDataReceived(int32_t id,
336 uint8_t subType,
337 uint32_t name,
338 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000339 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000340{
341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
342 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
343 " name=%u, length=%u)",
344 id, subType, name, length);
345
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000346 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000347 assert(channel == _channelId);
348
349 if (_rtcpObserver)
350 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000351 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352
353 if (_rtcpObserverPtr)
354 {
355 _rtcpObserverPtr->OnApplicationDataReceived(channel,
356 subType,
357 name,
358 data,
359 length);
360 }
361 }
362}
363
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000364int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000365Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000366 int32_t id,
367 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000368 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000369 int frequency,
370 uint8_t channels,
371 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000372{
373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
374 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
375 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
376 id, payloadType, payloadName, frequency, channels, rate);
377
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000378 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000379
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000380 CodecInst receiveCodec = {0};
381 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000382
383 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000384 receiveCodec.plfreq = frequency;
385 receiveCodec.channels = channels;
386 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000387 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000388
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000389 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 receiveCodec.pacsize = dummyCodec.pacsize;
391
392 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000393 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000394 {
395 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000396 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000397 "Channel::OnInitializeDecoder() invalid codec ("
398 "pt=%d, name=%s) received - 1", payloadType, payloadName);
399 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
400 return -1;
401 }
402
403 return 0;
404}
405
406void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000407Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000408{
409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
410 "Channel::OnPacketTimeout(id=%d)", id);
411
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000412 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 if (_voiceEngineObserverPtr)
414 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000415 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000417 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 assert(channel == _channelId);
419 // Ensure that next OnReceivedPacket() callback will trigger
420 // a VE_PACKET_RECEIPT_RESTARTED callback.
421 _rtpPacketTimedOut = true;
422 // Deliver callback to the observer
423 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
424 VoEId(_instanceId,_channelId),
425 "Channel::OnPacketTimeout() => "
426 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
427 _voiceEngineObserverPtr->CallbackOnError(channel,
428 VE_RECEIVE_PACKET_TIMEOUT);
429 }
430 }
431}
432
433void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000434Channel::OnReceivedPacket(int32_t id,
435 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000436{
437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
438 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
439 id, packetType);
440
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000441 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000442
443 // Notify only for the case when we have restarted an RTP session.
444 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
445 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000446 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 if (_voiceEngineObserverPtr)
448 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000449 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000450 assert(channel == _channelId);
451 // Reset timeout mechanism
452 _rtpPacketTimedOut = false;
453 // Deliver callback to the observer
454 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
455 VoEId(_instanceId,_channelId),
456 "Channel::OnPacketTimeout() =>"
457 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
458 _voiceEngineObserverPtr->CallbackOnError(
459 channel,
460 VE_PACKET_RECEIPT_RESTARTED);
461 }
462 }
463}
464
465void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000466Channel::OnPeriodicDeadOrAlive(int32_t id,
467 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000468{
469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
470 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
471
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000472 {
473 CriticalSectionScoped cs(&_callbackCritSect);
474 if (!_connectionObserver)
475 return;
476 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000477
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000478 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 assert(channel == _channelId);
480
481 // Use Alive as default to limit risk of false Dead detections
482 bool isAlive(true);
483
484 // Always mark the connection as Dead when the module reports kRtpDead
485 if (kRtpDead == alive)
486 {
487 isAlive = false;
488 }
489
490 // It is possible that the connection is alive even if no RTP packet has
491 // been received for a long time since the other side might use VAD/DTX
492 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000493 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 {
495 // Detect Alive for all NetEQ states except for the case when we are
496 // in PLC_CNG state.
497 // PLC_CNG <=> background noise only due to long expand or error.
498 // Note that, the case where the other side stops sending during CNG
499 // state will be detected as Alive. Dead is is not set until after
500 // missing RTCP packets for at least twelve seconds (handled
501 // internally by the RTP/RTCP module).
502 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
503 }
504
505 UpdateDeadOrAliveCounters(isAlive);
506
507 // Send callback to the registered observer
508 if (_connectionObserver)
509 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000510 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 if (_connectionObserverPtr)
512 {
513 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
514 }
515 }
516}
517
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000518int32_t
519Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000520 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000521 const WebRtcRTPHeader* rtpHeader)
522{
523 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
524 "Channel::OnReceivedPayloadData(payloadSize=%d,"
525 " payloadType=%u, audioChannel=%u)",
526 payloadSize,
527 rtpHeader->header.payloadType,
528 rtpHeader->type.Audio.channel);
529
roosa@google.com0870f022012-12-12 21:31:41 +0000530 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
531
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000532 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 {
534 // Avoid inserting into NetEQ when we are not playing. Count the
535 // packet as discarded.
536 WEBRTC_TRACE(kTraceStream, kTraceVoice,
537 VoEId(_instanceId, _channelId),
538 "received packet is discarded since playing is not"
539 " activated");
540 _numberOfDiscardedPackets++;
541 return 0;
542 }
543
544 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000545 if (audio_coding_->IncomingPacket(payloadData,
546 payloadSize,
547 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000548 {
549 _engineStatisticsPtr->SetLastError(
550 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
551 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
552 return -1;
553 }
554
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000555 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 UpdatePacketDelay(rtpHeader->header.timestamp,
557 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000558
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000559 uint16_t round_trip_time = 0;
560 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
561 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000562
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000563 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000564 round_trip_time);
565 if (!nack_list.empty()) {
566 // Can't use nack_list.data() since it's not supported by all
567 // compilers.
568 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000569 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000570 return 0;
571}
572
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000573bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
574 int rtp_packet_length) {
575 RTPHeader header;
576 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
577 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
578 "IncomingPacket invalid RTP header");
579 return false;
580 }
581 header.payload_type_frequency =
582 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
583 if (header.payload_type_frequency < 0)
584 return false;
585 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
586}
587
pbos@webrtc.org92135212013-05-14 08:31:39 +0000588int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000589{
590 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
591 "Channel::GetAudioFrame(id=%d)", id);
592
593 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000594 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
595 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 {
597 WEBRTC_TRACE(kTraceError, kTraceVoice,
598 VoEId(_instanceId,_channelId),
599 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000600 // In all likelihood, the audio in this frame is garbage. We return an
601 // error so that the audio mixer module doesn't add it to the mix. As
602 // a result, it won't be played out and the actions skipped here are
603 // irrelevant.
604 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 }
606
607 if (_RxVadDetection)
608 {
609 UpdateRxVadDetection(audioFrame);
610 }
611
612 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000613 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000615 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000617 ChannelState::State state = channel_state_.Get();
618
619 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000620 int err = rx_audioproc_->ProcessStream(&audioFrame);
621 if (err) {
622 LOG(LS_ERROR) << "ProcessStream() error: " << err;
623 assert(false);
624 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000625 }
626
wu@webrtc.org63420662013-10-17 18:28:55 +0000627 float output_gain = 1.0f;
628 float left_pan = 1.0f;
629 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000631 CriticalSectionScoped cs(&volume_settings_critsect_);
632 output_gain = _outputGain;
633 left_pan = _panLeft;
634 right_pan= _panRight;
635 }
636
637 // Output volume scaling
638 if (output_gain < 0.99f || output_gain > 1.01f)
639 {
640 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641 }
642
643 // Scale left and/or right channel(s) if stereo and master balance is
644 // active
645
wu@webrtc.org63420662013-10-17 18:28:55 +0000646 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000648 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000649 {
650 // Emulate stereo mode since panning is active.
651 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000652 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000653 }
654 // For true stereo mode (when we are receiving a stereo signal), no
655 // action is needed.
656
657 // Do the panning operation (the audio frame contains stereo at this
658 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000659 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 }
661
662 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000663 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000665 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000666 }
667
668 // Place channel in on-hold state (~muted) if on-hold is activated
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000669 if (state.output_is_on_hold)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 {
671 AudioFrameOperations::Mute(audioFrame);
672 }
673
674 // External media
675 if (_outputExternalMedia)
676 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000677 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000678 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 if (_outputExternalMediaCallbackPtr)
680 {
681 _outputExternalMediaCallbackPtr->Process(
682 _channelId,
683 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000684 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000685 audioFrame.samples_per_channel_,
686 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000687 isStereo);
688 }
689 }
690
691 // Record playout if enabled
692 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000693 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000694
695 if (_outputFileRecording && _outputFileRecorderPtr)
696 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000697 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
699 }
700
701 // Measure audio level (0-9)
702 _outputAudioLevel.ComputeLevel(audioFrame);
703
704 return 0;
705}
706
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000707int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000708Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000709{
710 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
711 "Channel::NeededFrequency(id=%d)", id);
712
713 int highestNeeded = 0;
714
715 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000716 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000717
718 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000719 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000721 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 }
723 else
724 {
725 highestNeeded = receiveFrequency;
726 }
727
728 // Special case, if we're playing a file on the playout side
729 // we take that frequency into consideration as well
730 // This is not needed on sending side, since the codec will
731 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000732 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000734 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000735 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 {
737 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
738 {
739 highestNeeded=_outputFilePlayerPtr->Frequency();
740 }
741 }
742 }
743
744 return(highestNeeded);
745}
746
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000747int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000748Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000749 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000750 uint32_t instanceId,
751 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000752{
753 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
754 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
755 channelId, instanceId);
756
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000757 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000758 if (channel == NULL)
759 {
760 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
761 VoEId(instanceId,channelId),
762 "Channel::CreateChannel() unable to allocate memory for"
763 " channel");
764 return -1;
765 }
766 return 0;
767}
768
769void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000770Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000771{
772 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
773 "Channel::PlayNotification(id=%d, durationMs=%d)",
774 id, durationMs);
775
776 // Not implement yet
777}
778
779void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000780Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000781{
782 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
783 "Channel::RecordNotification(id=%d, durationMs=%d)",
784 id, durationMs);
785
786 // Not implement yet
787}
788
789void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000790Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000791{
792 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
793 "Channel::PlayFileEnded(id=%d)", id);
794
795 if (id == _inputFilePlayerId)
796 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000797 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
799 VoEId(_instanceId,_channelId),
800 "Channel::PlayFileEnded() => input file player module is"
801 " shutdown");
802 }
803 else if (id == _outputFilePlayerId)
804 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000805 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
807 VoEId(_instanceId,_channelId),
808 "Channel::PlayFileEnded() => output file player module is"
809 " shutdown");
810 }
811}
812
813void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000814Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000815{
816 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
817 "Channel::RecordFileEnded(id=%d)", id);
818
819 assert(id == _outputFileRecorderId);
820
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000821 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000822
823 _outputFileRecording = false;
824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
825 VoEId(_instanceId,_channelId),
826 "Channel::RecordFileEnded() => output file recorder module is"
827 " shutdown");
828}
829
pbos@webrtc.org92135212013-05-14 08:31:39 +0000830Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000831 uint32_t instanceId,
832 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
834 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000835 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000837 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000838 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000839 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000840 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000841 rtp_receive_statistics_(ReceiveStatistics::Create(
842 Clock::GetRealTimeClock())),
843 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
844 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
845 this, this, rtp_payload_registry_.get())),
846 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000847 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000848 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 _rtpDumpIn(*RtpDump::CreateRtpDump()),
850 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000851 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000853 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000854 _inputFilePlayerPtr(NULL),
855 _outputFilePlayerPtr(NULL),
856 _outputFileRecorderPtr(NULL),
857 // Avoid conflict with other channels by adding 1024 - 1026,
858 // won't use as much as 1024 channels.
859 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
860 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
861 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000862 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000863 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
864 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000865 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000866 _inputExternalMediaCallbackPtr(NULL),
867 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000868 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
869 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000870 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000871 playout_timestamp_rtp_(0),
872 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000873 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000874 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000875 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000876 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000877 _outputMixerPtr(NULL),
878 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000879 _moduleProcessThreadPtr(NULL),
880 _audioDeviceModulePtr(NULL),
881 _voiceEngineObserverPtr(NULL),
882 _callbackCritSectPtr(NULL),
883 _transportPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000884 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000885 _rxVadObserverPtr(NULL),
886 _oldVadDecision(-1),
887 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 _rtpObserverPtr(NULL),
889 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000890 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000891 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000892 _inputIsOnHold(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000893 _mixFileWithMicrophone(false),
894 _rtpObserver(false),
895 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000896 _mute(false),
897 _panLeft(1.0f),
898 _panRight(1.0f),
899 _outputGain(1.0f),
900 _playOutbandDtmfEvent(false),
901 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000903 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000905 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 _rtpPacketTimedOut(false),
907 _rtpPacketTimeOutIsEnabled(false),
908 _rtpTimeOutSeconds(0),
909 _connectionObserver(false),
910 _connectionObserverPtr(NULL),
911 _countAliveDetections(0),
912 _countDeadDetections(0),
913 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000914 vie_network_(NULL),
915 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000916 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000917 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _previousTimestamp(0),
919 _recPacketDelayMs(20),
920 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000922 _rxNsIsEnabled(false),
923 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000924{
925 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
926 "Channel::Channel() - ctor");
927 _inbandDtmfQueue.ResetDtmf();
928 _inbandDtmfGenerator.Init();
929 _outputAudioLevel.Clear();
930
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000931 RtpRtcp::Configuration configuration;
932 configuration.id = VoEModuleId(instanceId, channelId);
933 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000934 configuration.outgoing_transport = this;
935 configuration.rtcp_feedback = this;
936 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000937 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000938
939 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000940
941 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
942 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
943 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000944}
945
946Channel::~Channel()
947{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000948 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
950 "Channel::~Channel() - dtor");
951
952 if (_outputExternalMedia)
953 {
954 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
955 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000956 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 {
958 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
959 }
960 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000961 StopPlayout();
962
963 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000964 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000965 if (_inputFilePlayerPtr)
966 {
967 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
968 _inputFilePlayerPtr->StopPlayingFile();
969 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
970 _inputFilePlayerPtr = NULL;
971 }
972 if (_outputFilePlayerPtr)
973 {
974 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
975 _outputFilePlayerPtr->StopPlayingFile();
976 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
977 _outputFilePlayerPtr = NULL;
978 }
979 if (_outputFileRecorderPtr)
980 {
981 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
982 _outputFileRecorderPtr->StopRecording();
983 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
984 _outputFileRecorderPtr = NULL;
985 }
986 }
987
988 // The order to safely shutdown modules in a channel is:
989 // 1. De-register callbacks in modules
990 // 2. De-register modules in process thread
991 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000992 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000993 {
994 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
995 VoEId(_instanceId,_channelId),
996 "~Channel() failed to de-register transport callback"
997 " (Audio coding module)");
998 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000999 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 {
1001 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1002 VoEId(_instanceId,_channelId),
1003 "~Channel() failed to de-register VAD callback"
1004 " (Audio coding module)");
1005 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001007 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001008 {
1009 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1010 VoEId(_instanceId,_channelId),
1011 "~Channel() failed to deregister RTP/RTCP module");
1012 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 // End of modules shutdown
1014
1015 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001016 if (vie_network_) {
1017 vie_network_->Release();
1018 vie_network_ = NULL;
1019 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001020 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1021 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001023 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001024 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001025}
1026
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001027int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001028Channel::Init()
1029{
1030 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1031 "Channel::Init()");
1032
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001033 channel_state_.Reset();
1034
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 // --- Initial sanity
1036
1037 if ((_engineStatisticsPtr == NULL) ||
1038 (_moduleProcessThreadPtr == NULL))
1039 {
1040 WEBRTC_TRACE(kTraceError, kTraceVoice,
1041 VoEId(_instanceId,_channelId),
1042 "Channel::Init() must call SetEngineInformation() first");
1043 return -1;
1044 }
1045
1046 // --- Add modules to process thread (for periodic schedulation)
1047
1048 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001049 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 if (processThreadFail)
1052 {
1053 _engineStatisticsPtr->SetLastError(
1054 VE_CANNOT_INIT_CHANNEL, kTraceError,
1055 "Channel::Init() modules not registered");
1056 return -1;
1057 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001058 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001059
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001060 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001061#ifdef WEBRTC_CODEC_AVT
1062 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001063 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001064#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001065 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 {
1067 _engineStatisticsPtr->SetLastError(
1068 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1069 "Channel::Init() unable to initialize the ACM - 1");
1070 return -1;
1071 }
1072
1073 // --- RTP/RTCP module initialization
1074
1075 // Ensure that RTCP is enabled by default for the created channel.
1076 // Note that, the module will keep generating RTCP until it is explicitly
1077 // disabled by the user.
1078 // After StopListen (when no sockets exists), RTCP packets will no longer
1079 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001080 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1081 // RTCP is enabled by default.
1082 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001083 {
1084 _engineStatisticsPtr->SetLastError(
1085 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1086 "Channel::Init() RTP/RTCP module not initialized");
1087 return -1;
1088 }
1089
1090 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001092 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1093 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001094
1095 if (fail)
1096 {
1097 _engineStatisticsPtr->SetLastError(
1098 VE_CANNOT_INIT_CHANNEL, kTraceError,
1099 "Channel::Init() callbacks not registered");
1100 return -1;
1101 }
1102
1103 // --- Register all supported codecs to the receiving side of the
1104 // RTP/RTCP module
1105
1106 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001107 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001108
1109 for (int idx = 0; idx < nSupportedCodecs; idx++)
1110 {
1111 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001112 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001113 (rtp_receiver_->RegisterReceivePayload(
1114 codec.plname,
1115 codec.pltype,
1116 codec.plfreq,
1117 codec.channels,
1118 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001119 {
1120 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1121 VoEId(_instanceId,_channelId),
1122 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1123 "to RTP/RTCP receiver",
1124 codec.plname, codec.pltype, codec.plfreq,
1125 codec.channels, codec.rate);
1126 }
1127 else
1128 {
1129 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1130 VoEId(_instanceId,_channelId),
1131 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1132 "the RTP/RTCP receiver",
1133 codec.plname, codec.pltype, codec.plfreq,
1134 codec.channels, codec.rate);
1135 }
1136
1137 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001138 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001139 {
1140 SetSendCodec(codec);
1141 }
1142
1143 // Register default PT for outband 'telephone-event'
1144 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1145 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001146 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001147 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001148 {
1149 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1150 VoEId(_instanceId,_channelId),
1151 "Channel::Init() failed to register outband "
1152 "'telephone-event' (%d/%d) correctly",
1153 codec.pltype, codec.plfreq);
1154 }
1155 }
1156
1157 if (!STR_CASE_CMP(codec.plname, "CN"))
1158 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001159 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1160 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001161 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
1163 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1164 VoEId(_instanceId,_channelId),
1165 "Channel::Init() failed to register CN (%d/%d) "
1166 "correctly - 1",
1167 codec.pltype, codec.plfreq);
1168 }
1169 }
1170#ifdef WEBRTC_CODEC_RED
1171 // Register RED to the receiving side of the ACM.
1172 // We will not receive an OnInitializeDecoder() callback for RED.
1173 if (!STR_CASE_CMP(codec.plname, "RED"))
1174 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001175 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001176 {
1177 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1178 VoEId(_instanceId,_channelId),
1179 "Channel::Init() failed to register RED (%d/%d) "
1180 "correctly",
1181 codec.pltype, codec.plfreq);
1182 }
1183 }
1184#endif
1185 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001186
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001187 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1188 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1189 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001191 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1192 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1193 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 }
1195
1196 return 0;
1197}
1198
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001199int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001200Channel::SetEngineInformation(Statistics& engineStatistics,
1201 OutputMixer& outputMixer,
1202 voe::TransmitMixer& transmitMixer,
1203 ProcessThread& moduleProcessThread,
1204 AudioDeviceModule& audioDeviceModule,
1205 VoiceEngineObserver* voiceEngineObserver,
1206 CriticalSectionWrapper* callbackCritSect)
1207{
1208 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1209 "Channel::SetEngineInformation()");
1210 _engineStatisticsPtr = &engineStatistics;
1211 _outputMixerPtr = &outputMixer;
1212 _transmitMixerPtr = &transmitMixer,
1213 _moduleProcessThreadPtr = &moduleProcessThread;
1214 _audioDeviceModulePtr = &audioDeviceModule;
1215 _voiceEngineObserverPtr = voiceEngineObserver;
1216 _callbackCritSectPtr = callbackCritSect;
1217 return 0;
1218}
1219
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001220int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001221Channel::UpdateLocalTimeStamp()
1222{
1223
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001224 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 return 0;
1226}
1227
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001228int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001229Channel::StartPlayout()
1230{
1231 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1232 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001233 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001234 {
1235 return 0;
1236 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001237
1238 if (!_externalMixing) {
1239 // Add participant as candidates for mixing.
1240 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1241 {
1242 _engineStatisticsPtr->SetLastError(
1243 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1244 "StartPlayout() failed to add participant to mixer");
1245 return -1;
1246 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 }
1248
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001249 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001250 if (RegisterFilePlayingToMixer() != 0)
1251 return -1;
1252
niklase@google.com470e71d2011-07-07 08:21:25 +00001253 return 0;
1254}
1255
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001256int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001257Channel::StopPlayout()
1258{
1259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1260 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001261 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 {
1263 return 0;
1264 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001265
1266 if (!_externalMixing) {
1267 // Remove participant as candidates for mixing
1268 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1269 {
1270 _engineStatisticsPtr->SetLastError(
1271 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1272 "StopPlayout() failed to remove participant from mixer");
1273 return -1;
1274 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001275 }
1276
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001277 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 _outputAudioLevel.Clear();
1279
1280 return 0;
1281}
1282
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001283int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001284Channel::StartSend()
1285{
1286 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1287 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001288 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001289 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001290 if (send_sequence_number_)
1291 SetInitSequenceNumber(send_sequence_number_);
1292
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001293 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001294 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001295 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001297 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001298
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001299 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001300 {
1301 _engineStatisticsPtr->SetLastError(
1302 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1303 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001304 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001305 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001306 return -1;
1307 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001308
niklase@google.com470e71d2011-07-07 08:21:25 +00001309 return 0;
1310}
1311
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001312int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001313Channel::StopSend()
1314{
1315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1316 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001317 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001319 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001320 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001321 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001322
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001323 // Store the sequence number to be able to pick up the same sequence for
1324 // the next StartSend(). This is needed for restarting device, otherwise
1325 // it might cause libSRTP to complain about packets being replayed.
1326 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1327 // CL is landed. See issue
1328 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1329 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1330
niklase@google.com470e71d2011-07-07 08:21:25 +00001331 // Reset sending SSRC and sequence number and triggers direct transmission
1332 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001333 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1334 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001335 {
1336 _engineStatisticsPtr->SetLastError(
1337 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1338 "StartSend() RTP/RTCP failed to stop sending");
1339 }
1340
niklase@google.com470e71d2011-07-07 08:21:25 +00001341 return 0;
1342}
1343
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001344int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001345Channel::StartReceiving()
1346{
1347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1348 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001349 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 {
1351 return 0;
1352 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001353 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001354 _numberOfDiscardedPackets = 0;
1355 return 0;
1356}
1357
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001358int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001359Channel::StopReceiving()
1360{
1361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1362 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001363 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001364 {
1365 return 0;
1366 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001367
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001368 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001369 return 0;
1370}
1371
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001372int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001373Channel::SetNetEQPlayoutMode(NetEqModes mode)
1374{
1375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1376 "Channel::SetNetEQPlayoutMode()");
1377 AudioPlayoutMode playoutMode(voice);
1378 switch (mode)
1379 {
1380 case kNetEqDefault:
1381 playoutMode = voice;
1382 break;
1383 case kNetEqStreaming:
1384 playoutMode = streaming;
1385 break;
1386 case kNetEqFax:
1387 playoutMode = fax;
1388 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001389 case kNetEqOff:
1390 playoutMode = off;
1391 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001392 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001393 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001394 {
1395 _engineStatisticsPtr->SetLastError(
1396 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1397 "SetNetEQPlayoutMode() failed to set playout mode");
1398 return -1;
1399 }
1400 return 0;
1401}
1402
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001403int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001404Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1405{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001406 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001407 switch (playoutMode)
1408 {
1409 case voice:
1410 mode = kNetEqDefault;
1411 break;
1412 case streaming:
1413 mode = kNetEqStreaming;
1414 break;
1415 case fax:
1416 mode = kNetEqFax;
1417 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001418 case off:
1419 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001420 }
1421 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1422 VoEId(_instanceId,_channelId),
1423 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1424 return 0;
1425}
1426
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001427int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001428Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1429{
1430 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1431 "Channel::SetOnHoldStatus()");
1432 if (mode == kHoldSendAndPlay)
1433 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001434 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001435 _inputIsOnHold = enable;
1436 }
1437 else if (mode == kHoldPlayOnly)
1438 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001439 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 }
1441 if (mode == kHoldSendOnly)
1442 {
1443 _inputIsOnHold = enable;
1444 }
1445 return 0;
1446}
1447
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001448int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001449Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1450{
1451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1452 "Channel::GetOnHoldStatus()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001453 bool output_is_on_hold = channel_state_.Get().output_is_on_hold;
1454 enabled = (output_is_on_hold || _inputIsOnHold);
1455 if (output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001456 {
1457 mode = kHoldSendAndPlay;
1458 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001459 else if (output_is_on_hold && !_inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001460 {
1461 mode = kHoldPlayOnly;
1462 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001463 else if (!output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001464 {
1465 mode = kHoldSendOnly;
1466 }
1467 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1468 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1469 enabled, mode);
1470 return 0;
1471}
1472
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001473int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001474Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1475{
1476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1477 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001478 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001479
1480 if (_voiceEngineObserverPtr)
1481 {
1482 _engineStatisticsPtr->SetLastError(
1483 VE_INVALID_OPERATION, kTraceError,
1484 "RegisterVoiceEngineObserver() observer already enabled");
1485 return -1;
1486 }
1487 _voiceEngineObserverPtr = &observer;
1488 return 0;
1489}
1490
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001491int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001492Channel::DeRegisterVoiceEngineObserver()
1493{
1494 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1495 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001496 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001497
1498 if (!_voiceEngineObserverPtr)
1499 {
1500 _engineStatisticsPtr->SetLastError(
1501 VE_INVALID_OPERATION, kTraceWarning,
1502 "DeRegisterVoiceEngineObserver() observer already disabled");
1503 return 0;
1504 }
1505 _voiceEngineObserverPtr = NULL;
1506 return 0;
1507}
1508
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001509int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001510Channel::GetSendCodec(CodecInst& codec)
1511{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001512 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001513}
1514
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001515int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001516Channel::GetRecCodec(CodecInst& codec)
1517{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001518 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001519}
1520
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001521int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001522Channel::SetSendCodec(const CodecInst& codec)
1523{
1524 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1525 "Channel::SetSendCodec()");
1526
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001527 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001528 {
1529 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1530 "SetSendCodec() failed to register codec to ACM");
1531 return -1;
1532 }
1533
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001534 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001536 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1537 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001538 {
1539 WEBRTC_TRACE(
1540 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1541 "SetSendCodec() failed to register codec to"
1542 " RTP/RTCP module");
1543 return -1;
1544 }
1545 }
1546
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001547 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001548 {
1549 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1550 "SetSendCodec() failed to set audio packet size");
1551 return -1;
1552 }
1553
1554 return 0;
1555}
1556
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001557int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001558Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1559{
1560 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1561 "Channel::SetVADStatus(mode=%d)", mode);
1562 // To disable VAD, DTX must be disabled too
1563 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001564 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001565 {
1566 _engineStatisticsPtr->SetLastError(
1567 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1568 "SetVADStatus() failed to set VAD");
1569 return -1;
1570 }
1571 return 0;
1572}
1573
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001574int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001575Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1576{
1577 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1578 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001579 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001580 {
1581 _engineStatisticsPtr->SetLastError(
1582 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1583 "GetVADStatus() failed to get VAD status");
1584 return -1;
1585 }
1586 disabledDTX = !disabledDTX;
1587 return 0;
1588}
1589
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001590int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001591Channel::SetRecPayloadType(const CodecInst& codec)
1592{
1593 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1594 "Channel::SetRecPayloadType()");
1595
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001596 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001597 {
1598 _engineStatisticsPtr->SetLastError(
1599 VE_ALREADY_PLAYING, kTraceError,
1600 "SetRecPayloadType() unable to set PT while playing");
1601 return -1;
1602 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001603 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001604 {
1605 _engineStatisticsPtr->SetLastError(
1606 VE_ALREADY_LISTENING, kTraceError,
1607 "SetRecPayloadType() unable to set PT while listening");
1608 return -1;
1609 }
1610
1611 if (codec.pltype == -1)
1612 {
1613 // De-register the selected codec (RTP/RTCP module and ACM)
1614
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001615 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001616 CodecInst rxCodec = codec;
1617
1618 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001619 rtp_payload_registry_->ReceivePayloadType(
1620 rxCodec.plname,
1621 rxCodec.plfreq,
1622 rxCodec.channels,
1623 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1624 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001625 rxCodec.pltype = pltype;
1626
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001627 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001628 {
1629 _engineStatisticsPtr->SetLastError(
1630 VE_RTP_RTCP_MODULE_ERROR,
1631 kTraceError,
1632 "SetRecPayloadType() RTP/RTCP-module deregistration "
1633 "failed");
1634 return -1;
1635 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001636 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001637 {
1638 _engineStatisticsPtr->SetLastError(
1639 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1640 "SetRecPayloadType() ACM deregistration failed - 1");
1641 return -1;
1642 }
1643 return 0;
1644 }
1645
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001646 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 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001654 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1655 if (rtp_receiver_->RegisterReceivePayload(
1656 codec.plname,
1657 codec.pltype,
1658 codec.plfreq,
1659 codec.channels,
1660 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001661 {
1662 _engineStatisticsPtr->SetLastError(
1663 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1664 "SetRecPayloadType() RTP/RTCP-module registration failed");
1665 return -1;
1666 }
1667 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001668 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001669 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001670 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1671 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001672 {
1673 _engineStatisticsPtr->SetLastError(
1674 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1675 "SetRecPayloadType() ACM registration failed - 1");
1676 return -1;
1677 }
1678 }
1679 return 0;
1680}
1681
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001682int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001683Channel::GetRecPayloadType(CodecInst& codec)
1684{
1685 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1686 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001687 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001688 if (rtp_payload_registry_->ReceivePayloadType(
1689 codec.plname,
1690 codec.plfreq,
1691 codec.channels,
1692 (codec.rate < 0) ? 0 : codec.rate,
1693 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001694 {
1695 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001696 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001697 "GetRecPayloadType() failed to retrieve RX payload type");
1698 return -1;
1699 }
1700 codec.pltype = payloadType;
1701 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1702 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1703 return 0;
1704}
1705
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001706int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001707Channel::SetAMREncFormat(AmrMode mode)
1708{
1709 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1710 "Channel::SetAMREncFormat()");
1711
1712 // ACM doesn't support AMR
1713 return -1;
1714}
1715
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001716int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001717Channel::SetAMRDecFormat(AmrMode mode)
1718{
1719 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1720 "Channel::SetAMRDecFormat()");
1721
1722 // ACM doesn't support AMR
1723 return -1;
1724}
1725
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001726int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001727Channel::SetAMRWbEncFormat(AmrMode mode)
1728{
1729 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1730 "Channel::SetAMRWbEncFormat()");
1731
1732 // ACM doesn't support AMR
1733 return -1;
1734
1735}
1736
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001737int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001738Channel::SetAMRWbDecFormat(AmrMode mode)
1739{
1740 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1741 "Channel::SetAMRWbDecFormat()");
1742
1743 // ACM doesn't support AMR
1744 return -1;
1745}
1746
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001747int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001748Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1749{
1750 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1751 "Channel::SetSendCNPayloadType()");
1752
1753 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001754 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001755 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001756 if (frequency == kFreq32000Hz)
1757 samplingFreqHz = 32000;
1758 else if (frequency == kFreq16000Hz)
1759 samplingFreqHz = 16000;
1760
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001761 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001762 {
1763 _engineStatisticsPtr->SetLastError(
1764 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1765 "SetSendCNPayloadType() failed to retrieve default CN codec "
1766 "settings");
1767 return -1;
1768 }
1769
1770 // Modify the payload type (must be set to dynamic range)
1771 codec.pltype = type;
1772
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001773 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001774 {
1775 _engineStatisticsPtr->SetLastError(
1776 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1777 "SetSendCNPayloadType() failed to register CN to ACM");
1778 return -1;
1779 }
1780
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001781 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001782 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001783 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1784 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001785 {
1786 _engineStatisticsPtr->SetLastError(
1787 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1788 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1789 "module");
1790 return -1;
1791 }
1792 }
1793 return 0;
1794}
1795
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001796int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001797Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1798{
1799 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1800 "Channel::SetISACInitTargetRate()");
1801
1802 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001803 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001804 {
1805 _engineStatisticsPtr->SetLastError(
1806 VE_CODEC_ERROR, kTraceError,
1807 "SetISACInitTargetRate() failed to retrieve send codec");
1808 return -1;
1809 }
1810 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1811 {
1812 // This API is only valid if iSAC is setup to run in channel-adaptive
1813 // mode.
1814 // We do not validate the adaptive mode here. It is done later in the
1815 // ConfigISACBandwidthEstimator() API.
1816 _engineStatisticsPtr->SetLastError(
1817 VE_CODEC_ERROR, kTraceError,
1818 "SetISACInitTargetRate() send codec is not iSAC");
1819 return -1;
1820 }
1821
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001822 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001823 if (16000 == sendCodec.plfreq)
1824 {
1825 // Note that 0 is a valid and corresponds to "use default
1826 if ((rateBps != 0 &&
1827 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1828 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1829 {
1830 _engineStatisticsPtr->SetLastError(
1831 VE_INVALID_ARGUMENT, kTraceError,
1832 "SetISACInitTargetRate() invalid target rate - 1");
1833 return -1;
1834 }
1835 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001836 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001837 }
1838 else if (32000 == sendCodec.plfreq)
1839 {
1840 if ((rateBps != 0 &&
1841 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1842 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1843 {
1844 _engineStatisticsPtr->SetLastError(
1845 VE_INVALID_ARGUMENT, kTraceError,
1846 "SetISACInitTargetRate() invalid target rate - 2");
1847 return -1;
1848 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001849 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001850 }
1851
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001852 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001853 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1854 {
1855 _engineStatisticsPtr->SetLastError(
1856 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1857 "SetISACInitTargetRate() iSAC BWE config failed");
1858 return -1;
1859 }
1860
1861 return 0;
1862}
1863
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001864int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001865Channel::SetISACMaxRate(int rateBps)
1866{
1867 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1868 "Channel::SetISACMaxRate()");
1869
1870 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001871 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001872 {
1873 _engineStatisticsPtr->SetLastError(
1874 VE_CODEC_ERROR, kTraceError,
1875 "SetISACMaxRate() failed to retrieve send codec");
1876 return -1;
1877 }
1878 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1879 {
1880 // This API is only valid if iSAC is selected as sending codec.
1881 _engineStatisticsPtr->SetLastError(
1882 VE_CODEC_ERROR, kTraceError,
1883 "SetISACMaxRate() send codec is not iSAC");
1884 return -1;
1885 }
1886 if (16000 == sendCodec.plfreq)
1887 {
1888 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1889 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1890 {
1891 _engineStatisticsPtr->SetLastError(
1892 VE_INVALID_ARGUMENT, kTraceError,
1893 "SetISACMaxRate() invalid max rate - 1");
1894 return -1;
1895 }
1896 }
1897 else if (32000 == sendCodec.plfreq)
1898 {
1899 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1900 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1901 {
1902 _engineStatisticsPtr->SetLastError(
1903 VE_INVALID_ARGUMENT, kTraceError,
1904 "SetISACMaxRate() invalid max rate - 2");
1905 return -1;
1906 }
1907 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001908 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001909 {
1910 _engineStatisticsPtr->SetLastError(
1911 VE_SENDING, kTraceError,
1912 "SetISACMaxRate() unable to set max rate while sending");
1913 return -1;
1914 }
1915
1916 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1917 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001918 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001919 {
1920 _engineStatisticsPtr->SetLastError(
1921 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1922 "SetISACMaxRate() failed to set max rate");
1923 return -1;
1924 }
1925
1926 return 0;
1927}
1928
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001929int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001930Channel::SetISACMaxPayloadSize(int sizeBytes)
1931{
1932 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1933 "Channel::SetISACMaxPayloadSize()");
1934 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001935 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001936 {
1937 _engineStatisticsPtr->SetLastError(
1938 VE_CODEC_ERROR, kTraceError,
1939 "SetISACMaxPayloadSize() failed to retrieve send codec");
1940 return -1;
1941 }
1942 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1943 {
1944 _engineStatisticsPtr->SetLastError(
1945 VE_CODEC_ERROR, kTraceError,
1946 "SetISACMaxPayloadSize() send codec is not iSAC");
1947 return -1;
1948 }
1949 if (16000 == sendCodec.plfreq)
1950 {
1951 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1952 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1953 {
1954 _engineStatisticsPtr->SetLastError(
1955 VE_INVALID_ARGUMENT, kTraceError,
1956 "SetISACMaxPayloadSize() invalid max payload - 1");
1957 return -1;
1958 }
1959 }
1960 else if (32000 == sendCodec.plfreq)
1961 {
1962 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1963 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1964 {
1965 _engineStatisticsPtr->SetLastError(
1966 VE_INVALID_ARGUMENT, kTraceError,
1967 "SetISACMaxPayloadSize() invalid max payload - 2");
1968 return -1;
1969 }
1970 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001971 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001972 {
1973 _engineStatisticsPtr->SetLastError(
1974 VE_SENDING, kTraceError,
1975 "SetISACMaxPayloadSize() unable to set max rate while sending");
1976 return -1;
1977 }
1978
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001979 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001980 {
1981 _engineStatisticsPtr->SetLastError(
1982 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1983 "SetISACMaxPayloadSize() failed to set max payload size");
1984 return -1;
1985 }
1986 return 0;
1987}
1988
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001989int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001990{
1991 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1992 "Channel::RegisterExternalTransport()");
1993
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001994 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001995
niklase@google.com470e71d2011-07-07 08:21:25 +00001996 if (_externalTransport)
1997 {
1998 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1999 kTraceError,
2000 "RegisterExternalTransport() external transport already enabled");
2001 return -1;
2002 }
2003 _externalTransport = true;
2004 _transportPtr = &transport;
2005 return 0;
2006}
2007
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002008int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002009Channel::DeRegisterExternalTransport()
2010{
2011 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2012 "Channel::DeRegisterExternalTransport()");
2013
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002014 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002015
niklase@google.com470e71d2011-07-07 08:21:25 +00002016 if (!_transportPtr)
2017 {
2018 _engineStatisticsPtr->SetLastError(
2019 VE_INVALID_OPERATION, kTraceWarning,
2020 "DeRegisterExternalTransport() external transport already "
2021 "disabled");
2022 return 0;
2023 }
2024 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002025 _transportPtr = NULL;
2026 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2027 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002028 return 0;
2029}
2030
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002031int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
2032 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002033 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2034 "Channel::ReceivedRTPPacket()");
2035
2036 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002037 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002038
2039 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002040 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2041 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002042 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2043 VoEId(_instanceId,_channelId),
2044 "Channel::SendPacket() RTP dump to input file failed");
2045 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002046 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002047 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002048 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2049 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2050 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002051 return -1;
2052 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002053 header.payload_type_frequency =
2054 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002055 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002056 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002057 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002058 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002059 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002060 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002061
2062 // Forward any packets to ViE bandwidth estimator, if enabled.
2063 {
2064 CriticalSectionScoped cs(&_callbackCritSect);
2065 if (vie_network_) {
2066 int64_t arrival_time_ms;
2067 if (packet_time.timestamp != -1) {
2068 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
2069 } else {
2070 arrival_time_ms = TickTime::MillisecondTimestamp();
2071 }
2072 int payload_length = length - header.headerLength;
2073 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
2074 payload_length, header);
2075 }
2076 }
2077
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002078 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002079}
2080
2081bool Channel::ReceivePacket(const uint8_t* packet,
2082 int packet_length,
2083 const RTPHeader& header,
2084 bool in_order) {
2085 if (rtp_payload_registry_->IsEncapsulated(header)) {
2086 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002087 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002088 const uint8_t* payload = packet + header.headerLength;
2089 int payload_length = packet_length - header.headerLength;
2090 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002091 PayloadUnion payload_specific;
2092 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002093 &payload_specific)) {
2094 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002095 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002096 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2097 payload_specific, in_order);
2098}
2099
2100bool Channel::HandleEncapsulation(const uint8_t* packet,
2101 int packet_length,
2102 const RTPHeader& header) {
2103 if (!rtp_payload_registry_->IsRtx(header))
2104 return false;
2105
2106 // Remove the RTX header and parse the original RTP header.
2107 if (packet_length < header.headerLength)
2108 return false;
2109 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2110 return false;
2111 if (restored_packet_in_use_) {
2112 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2113 "Multiple RTX headers detected, dropping packet");
2114 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002115 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002116 uint8_t* restored_packet_ptr = restored_packet_;
2117 if (!rtp_payload_registry_->RestoreOriginalPacket(
2118 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2119 header)) {
2120 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2121 "Incoming RTX packet: invalid RTP header");
2122 return false;
2123 }
2124 restored_packet_in_use_ = true;
2125 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2126 restored_packet_in_use_ = false;
2127 return ret;
2128}
2129
2130bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2131 StreamStatistician* statistician =
2132 rtp_receive_statistics_->GetStatistician(header.ssrc);
2133 if (!statistician)
2134 return false;
2135 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002136}
2137
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002138bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2139 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002140 // Retransmissions are handled separately if RTX is enabled.
2141 if (rtp_payload_registry_->RtxEnabled())
2142 return false;
2143 StreamStatistician* statistician =
2144 rtp_receive_statistics_->GetStatistician(header.ssrc);
2145 if (!statistician)
2146 return false;
2147 // Check if this is a retransmission.
2148 uint16_t min_rtt = 0;
2149 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002150 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002151 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002152}
2153
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002154int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002155 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2156 "Channel::ReceivedRTCPPacket()");
2157 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002158 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002159
2160 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002161 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2162 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002163 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2164 VoEId(_instanceId,_channelId),
2165 "Channel::SendPacket() RTCP dump to input file failed");
2166 }
2167
2168 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002169 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2170 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002171 _engineStatisticsPtr->SetLastError(
2172 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2173 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2174 }
2175 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002176}
2177
niklase@google.com470e71d2011-07-07 08:21:25 +00002178int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002179 bool loop,
2180 FileFormats format,
2181 int startPosition,
2182 float volumeScaling,
2183 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002184 const CodecInst* codecInst)
2185{
2186 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2187 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2188 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2189 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2190 startPosition, stopPosition);
2191
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002192 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002193 {
2194 _engineStatisticsPtr->SetLastError(
2195 VE_ALREADY_PLAYING, kTraceError,
2196 "StartPlayingFileLocally() is already playing");
2197 return -1;
2198 }
2199
niklase@google.com470e71d2011-07-07 08:21:25 +00002200 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002201 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002202
2203 if (_outputFilePlayerPtr)
2204 {
2205 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2206 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2207 _outputFilePlayerPtr = NULL;
2208 }
2209
2210 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2211 _outputFilePlayerId, (const FileFormats)format);
2212
2213 if (_outputFilePlayerPtr == NULL)
2214 {
2215 _engineStatisticsPtr->SetLastError(
2216 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002217 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002218 return -1;
2219 }
2220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002221 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002222
2223 if (_outputFilePlayerPtr->StartPlayingFile(
2224 fileName,
2225 loop,
2226 startPosition,
2227 volumeScaling,
2228 notificationTime,
2229 stopPosition,
2230 (const CodecInst*)codecInst) != 0)
2231 {
2232 _engineStatisticsPtr->SetLastError(
2233 VE_BAD_FILE, kTraceError,
2234 "StartPlayingFile() failed to start file playout");
2235 _outputFilePlayerPtr->StopPlayingFile();
2236 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2237 _outputFilePlayerPtr = NULL;
2238 return -1;
2239 }
2240 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002241 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002242 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002243
2244 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002245 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002246
2247 return 0;
2248}
2249
2250int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002251 FileFormats format,
2252 int startPosition,
2253 float volumeScaling,
2254 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002255 const CodecInst* codecInst)
2256{
2257 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2258 "Channel::StartPlayingFileLocally(format=%d,"
2259 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2260 format, volumeScaling, startPosition, stopPosition);
2261
2262 if(stream == NULL)
2263 {
2264 _engineStatisticsPtr->SetLastError(
2265 VE_BAD_FILE, kTraceError,
2266 "StartPlayingFileLocally() NULL as input stream");
2267 return -1;
2268 }
2269
2270
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002271 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002272 {
2273 _engineStatisticsPtr->SetLastError(
2274 VE_ALREADY_PLAYING, kTraceError,
2275 "StartPlayingFileLocally() is already playing");
2276 return -1;
2277 }
2278
niklase@google.com470e71d2011-07-07 08:21:25 +00002279 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002280 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002281
2282 // Destroy the old instance
2283 if (_outputFilePlayerPtr)
2284 {
2285 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2286 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2287 _outputFilePlayerPtr = NULL;
2288 }
2289
2290 // Create the instance
2291 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2292 _outputFilePlayerId,
2293 (const FileFormats)format);
2294
2295 if (_outputFilePlayerPtr == NULL)
2296 {
2297 _engineStatisticsPtr->SetLastError(
2298 VE_INVALID_ARGUMENT, kTraceError,
2299 "StartPlayingFileLocally() filePlayer format isnot correct");
2300 return -1;
2301 }
2302
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002303 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002304
2305 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2306 volumeScaling,
2307 notificationTime,
2308 stopPosition, codecInst) != 0)
2309 {
2310 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2311 "StartPlayingFile() failed to "
2312 "start file playout");
2313 _outputFilePlayerPtr->StopPlayingFile();
2314 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2315 _outputFilePlayerPtr = NULL;
2316 return -1;
2317 }
2318 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002319 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002320 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002321
2322 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002323 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002324
niklase@google.com470e71d2011-07-07 08:21:25 +00002325 return 0;
2326}
2327
2328int Channel::StopPlayingFileLocally()
2329{
2330 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2331 "Channel::StopPlayingFileLocally()");
2332
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002333 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002334 {
2335 _engineStatisticsPtr->SetLastError(
2336 VE_INVALID_OPERATION, kTraceWarning,
2337 "StopPlayingFileLocally() isnot playing");
2338 return 0;
2339 }
2340
niklase@google.com470e71d2011-07-07 08:21:25 +00002341 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002342 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002343
2344 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2345 {
2346 _engineStatisticsPtr->SetLastError(
2347 VE_STOP_RECORDING_FAILED, kTraceError,
2348 "StopPlayingFile() could not stop playing");
2349 return -1;
2350 }
2351 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2352 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2353 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002354 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002355 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002356 // _fileCritSect cannot be taken while calling
2357 // SetAnonymousMixibilityStatus. Refer to comments in
2358 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002359 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2360 {
2361 _engineStatisticsPtr->SetLastError(
2362 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002363 "StopPlayingFile() failed to stop participant from playing as"
2364 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002365 return -1;
2366 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002367
2368 return 0;
2369}
2370
2371int Channel::IsPlayingFileLocally() const
2372{
2373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2374 "Channel::IsPlayingFileLocally()");
2375
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002376 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002377}
2378
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002379int Channel::RegisterFilePlayingToMixer()
2380{
2381 // Return success for not registering for file playing to mixer if:
2382 // 1. playing file before playout is started on that channel.
2383 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002384 if (!channel_state_.Get().playing ||
2385 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002386 {
2387 return 0;
2388 }
2389
2390 // |_fileCritSect| cannot be taken while calling
2391 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2392 // frames can be pulled by the mixer. Since the frames are generated from
2393 // the file, _fileCritSect will be taken. This would result in a deadlock.
2394 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2395 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002396 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002397 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002398 _engineStatisticsPtr->SetLastError(
2399 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2400 "StartPlayingFile() failed to add participant as file to mixer");
2401 _outputFilePlayerPtr->StopPlayingFile();
2402 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2403 _outputFilePlayerPtr = NULL;
2404 return -1;
2405 }
2406
2407 return 0;
2408}
2409
pbos@webrtc.org92135212013-05-14 08:31:39 +00002410int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002411{
2412 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2413 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2414
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002415 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002416
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002417 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002418 {
2419 _engineStatisticsPtr->SetLastError(
2420 VE_INVALID_OPERATION, kTraceError,
2421 "ScaleLocalFilePlayout() isnot playing");
2422 return -1;
2423 }
2424 if ((_outputFilePlayerPtr == NULL) ||
2425 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2426 {
2427 _engineStatisticsPtr->SetLastError(
2428 VE_BAD_ARGUMENT, kTraceError,
2429 "SetAudioScaling() failed to scale the playout");
2430 return -1;
2431 }
2432
2433 return 0;
2434}
2435
2436int Channel::GetLocalPlayoutPosition(int& positionMs)
2437{
2438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2439 "Channel::GetLocalPlayoutPosition(position=?)");
2440
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002441 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002442
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002443 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002444
2445 if (_outputFilePlayerPtr == NULL)
2446 {
2447 _engineStatisticsPtr->SetLastError(
2448 VE_INVALID_OPERATION, kTraceError,
2449 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2450 return -1;
2451 }
2452
2453 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2454 {
2455 _engineStatisticsPtr->SetLastError(
2456 VE_BAD_FILE, kTraceError,
2457 "GetLocalPlayoutPosition() failed");
2458 return -1;
2459 }
2460 positionMs = position;
2461
2462 return 0;
2463}
2464
2465int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002466 bool loop,
2467 FileFormats format,
2468 int startPosition,
2469 float volumeScaling,
2470 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002471 const CodecInst* codecInst)
2472{
2473 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2474 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2475 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2476 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2477 startPosition, stopPosition);
2478
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002479 CriticalSectionScoped cs(&_fileCritSect);
2480
2481 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002482 {
2483 _engineStatisticsPtr->SetLastError(
2484 VE_ALREADY_PLAYING, kTraceWarning,
2485 "StartPlayingFileAsMicrophone() filePlayer is playing");
2486 return 0;
2487 }
2488
niklase@google.com470e71d2011-07-07 08:21:25 +00002489 // Destroy the old instance
2490 if (_inputFilePlayerPtr)
2491 {
2492 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2493 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2494 _inputFilePlayerPtr = NULL;
2495 }
2496
2497 // Create the instance
2498 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2499 _inputFilePlayerId, (const FileFormats)format);
2500
2501 if (_inputFilePlayerPtr == NULL)
2502 {
2503 _engineStatisticsPtr->SetLastError(
2504 VE_INVALID_ARGUMENT, kTraceError,
2505 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2506 return -1;
2507 }
2508
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002509 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002510
2511 if (_inputFilePlayerPtr->StartPlayingFile(
2512 fileName,
2513 loop,
2514 startPosition,
2515 volumeScaling,
2516 notificationTime,
2517 stopPosition,
2518 (const CodecInst*)codecInst) != 0)
2519 {
2520 _engineStatisticsPtr->SetLastError(
2521 VE_BAD_FILE, kTraceError,
2522 "StartPlayingFile() failed to start file playout");
2523 _inputFilePlayerPtr->StopPlayingFile();
2524 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2525 _inputFilePlayerPtr = NULL;
2526 return -1;
2527 }
2528 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002529 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002530
2531 return 0;
2532}
2533
2534int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002535 FileFormats format,
2536 int startPosition,
2537 float volumeScaling,
2538 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002539 const CodecInst* codecInst)
2540{
2541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2542 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2543 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2544 format, volumeScaling, startPosition, stopPosition);
2545
2546 if(stream == NULL)
2547 {
2548 _engineStatisticsPtr->SetLastError(
2549 VE_BAD_FILE, kTraceError,
2550 "StartPlayingFileAsMicrophone NULL as input stream");
2551 return -1;
2552 }
2553
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002554 CriticalSectionScoped cs(&_fileCritSect);
2555
2556 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002557 {
2558 _engineStatisticsPtr->SetLastError(
2559 VE_ALREADY_PLAYING, kTraceWarning,
2560 "StartPlayingFileAsMicrophone() is playing");
2561 return 0;
2562 }
2563
niklase@google.com470e71d2011-07-07 08:21:25 +00002564 // Destroy the old instance
2565 if (_inputFilePlayerPtr)
2566 {
2567 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2568 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2569 _inputFilePlayerPtr = NULL;
2570 }
2571
2572 // Create the instance
2573 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2574 _inputFilePlayerId, (const FileFormats)format);
2575
2576 if (_inputFilePlayerPtr == NULL)
2577 {
2578 _engineStatisticsPtr->SetLastError(
2579 VE_INVALID_ARGUMENT, kTraceError,
2580 "StartPlayingInputFile() filePlayer format isnot correct");
2581 return -1;
2582 }
2583
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002584 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002585
2586 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2587 volumeScaling, notificationTime,
2588 stopPosition, codecInst) != 0)
2589 {
2590 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2591 "StartPlayingFile() failed to start "
2592 "file playout");
2593 _inputFilePlayerPtr->StopPlayingFile();
2594 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2595 _inputFilePlayerPtr = NULL;
2596 return -1;
2597 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002598
niklase@google.com470e71d2011-07-07 08:21:25 +00002599 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002600 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002601
2602 return 0;
2603}
2604
2605int Channel::StopPlayingFileAsMicrophone()
2606{
2607 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2608 "Channel::StopPlayingFileAsMicrophone()");
2609
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002610 CriticalSectionScoped cs(&_fileCritSect);
2611
2612 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002613 {
2614 _engineStatisticsPtr->SetLastError(
2615 VE_INVALID_OPERATION, kTraceWarning,
2616 "StopPlayingFileAsMicrophone() isnot playing");
2617 return 0;
2618 }
2619
niklase@google.com470e71d2011-07-07 08:21:25 +00002620 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2621 {
2622 _engineStatisticsPtr->SetLastError(
2623 VE_STOP_RECORDING_FAILED, kTraceError,
2624 "StopPlayingFile() could not stop playing");
2625 return -1;
2626 }
2627 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2628 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2629 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002630 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002631
2632 return 0;
2633}
2634
2635int Channel::IsPlayingFileAsMicrophone() const
2636{
2637 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2638 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002639 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002640}
2641
pbos@webrtc.org92135212013-05-14 08:31:39 +00002642int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002643{
2644 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2645 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2646
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002647 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002648
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002649 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002650 {
2651 _engineStatisticsPtr->SetLastError(
2652 VE_INVALID_OPERATION, kTraceError,
2653 "ScaleFileAsMicrophonePlayout() isnot playing");
2654 return -1;
2655 }
2656
2657 if ((_inputFilePlayerPtr == NULL) ||
2658 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2659 {
2660 _engineStatisticsPtr->SetLastError(
2661 VE_BAD_ARGUMENT, kTraceError,
2662 "SetAudioScaling() failed to scale playout");
2663 return -1;
2664 }
2665
2666 return 0;
2667}
2668
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002669int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002670 const CodecInst* codecInst)
2671{
2672 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2673 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2674
2675 if (_outputFileRecording)
2676 {
2677 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2678 "StartRecordingPlayout() is already recording");
2679 return 0;
2680 }
2681
2682 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002683 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002684 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2685
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002686 if ((codecInst != NULL) &&
2687 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002688 {
2689 _engineStatisticsPtr->SetLastError(
2690 VE_BAD_ARGUMENT, kTraceError,
2691 "StartRecordingPlayout() invalid compression");
2692 return(-1);
2693 }
2694 if(codecInst == NULL)
2695 {
2696 format = kFileFormatPcm16kHzFile;
2697 codecInst=&dummyCodec;
2698 }
2699 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2700 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2701 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2702 {
2703 format = kFileFormatWavFile;
2704 }
2705 else
2706 {
2707 format = kFileFormatCompressedFile;
2708 }
2709
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002710 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002711
2712 // Destroy the old instance
2713 if (_outputFileRecorderPtr)
2714 {
2715 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2716 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2717 _outputFileRecorderPtr = NULL;
2718 }
2719
2720 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2721 _outputFileRecorderId, (const FileFormats)format);
2722 if (_outputFileRecorderPtr == NULL)
2723 {
2724 _engineStatisticsPtr->SetLastError(
2725 VE_INVALID_ARGUMENT, kTraceError,
2726 "StartRecordingPlayout() fileRecorder format isnot correct");
2727 return -1;
2728 }
2729
2730 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2731 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2732 {
2733 _engineStatisticsPtr->SetLastError(
2734 VE_BAD_FILE, kTraceError,
2735 "StartRecordingAudioFile() failed to start file recording");
2736 _outputFileRecorderPtr->StopRecording();
2737 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2738 _outputFileRecorderPtr = NULL;
2739 return -1;
2740 }
2741 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2742 _outputFileRecording = true;
2743
2744 return 0;
2745}
2746
2747int Channel::StartRecordingPlayout(OutStream* stream,
2748 const CodecInst* codecInst)
2749{
2750 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2751 "Channel::StartRecordingPlayout()");
2752
2753 if (_outputFileRecording)
2754 {
2755 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2756 "StartRecordingPlayout() is already recording");
2757 return 0;
2758 }
2759
2760 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002761 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2763
2764 if (codecInst != NULL && codecInst->channels != 1)
2765 {
2766 _engineStatisticsPtr->SetLastError(
2767 VE_BAD_ARGUMENT, kTraceError,
2768 "StartRecordingPlayout() invalid compression");
2769 return(-1);
2770 }
2771 if(codecInst == NULL)
2772 {
2773 format = kFileFormatPcm16kHzFile;
2774 codecInst=&dummyCodec;
2775 }
2776 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2777 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2778 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2779 {
2780 format = kFileFormatWavFile;
2781 }
2782 else
2783 {
2784 format = kFileFormatCompressedFile;
2785 }
2786
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002787 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002788
2789 // Destroy the old instance
2790 if (_outputFileRecorderPtr)
2791 {
2792 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2793 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2794 _outputFileRecorderPtr = NULL;
2795 }
2796
2797 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2798 _outputFileRecorderId, (const FileFormats)format);
2799 if (_outputFileRecorderPtr == NULL)
2800 {
2801 _engineStatisticsPtr->SetLastError(
2802 VE_INVALID_ARGUMENT, kTraceError,
2803 "StartRecordingPlayout() fileRecorder format isnot correct");
2804 return -1;
2805 }
2806
2807 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2808 notificationTime) != 0)
2809 {
2810 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2811 "StartRecordingPlayout() failed to "
2812 "start file recording");
2813 _outputFileRecorderPtr->StopRecording();
2814 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2815 _outputFileRecorderPtr = NULL;
2816 return -1;
2817 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002818
niklase@google.com470e71d2011-07-07 08:21:25 +00002819 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2820 _outputFileRecording = true;
2821
2822 return 0;
2823}
2824
2825int Channel::StopRecordingPlayout()
2826{
2827 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2828 "Channel::StopRecordingPlayout()");
2829
2830 if (!_outputFileRecording)
2831 {
2832 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2833 "StopRecordingPlayout() isnot recording");
2834 return -1;
2835 }
2836
2837
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002838 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002839
2840 if (_outputFileRecorderPtr->StopRecording() != 0)
2841 {
2842 _engineStatisticsPtr->SetLastError(
2843 VE_STOP_RECORDING_FAILED, kTraceError,
2844 "StopRecording() could not stop recording");
2845 return(-1);
2846 }
2847 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2848 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2849 _outputFileRecorderPtr = NULL;
2850 _outputFileRecording = false;
2851
2852 return 0;
2853}
2854
2855void
2856Channel::SetMixWithMicStatus(bool mix)
2857{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002858 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002859 _mixFileWithMicrophone=mix;
2860}
2861
2862int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002863Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002864{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002865 int8_t currentLevel = _outputAudioLevel.Level();
2866 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002867 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2868 VoEId(_instanceId,_channelId),
2869 "GetSpeechOutputLevel() => level=%u", level);
2870 return 0;
2871}
2872
2873int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002874Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002875{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002876 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2877 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002878 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2879 VoEId(_instanceId,_channelId),
2880 "GetSpeechOutputLevelFullRange() => level=%u", level);
2881 return 0;
2882}
2883
2884int
2885Channel::SetMute(bool enable)
2886{
wu@webrtc.org63420662013-10-17 18:28:55 +00002887 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002888 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2889 "Channel::SetMute(enable=%d)", enable);
2890 _mute = enable;
2891 return 0;
2892}
2893
2894bool
2895Channel::Mute() const
2896{
wu@webrtc.org63420662013-10-17 18:28:55 +00002897 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002898 return _mute;
2899}
2900
2901int
2902Channel::SetOutputVolumePan(float left, float right)
2903{
wu@webrtc.org63420662013-10-17 18:28:55 +00002904 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002905 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2906 "Channel::SetOutputVolumePan()");
2907 _panLeft = left;
2908 _panRight = right;
2909 return 0;
2910}
2911
2912int
2913Channel::GetOutputVolumePan(float& left, float& right) const
2914{
wu@webrtc.org63420662013-10-17 18:28:55 +00002915 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002916 left = _panLeft;
2917 right = _panRight;
2918 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2919 VoEId(_instanceId,_channelId),
2920 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2921 return 0;
2922}
2923
2924int
2925Channel::SetChannelOutputVolumeScaling(float scaling)
2926{
wu@webrtc.org63420662013-10-17 18:28:55 +00002927 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002928 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2929 "Channel::SetChannelOutputVolumeScaling()");
2930 _outputGain = scaling;
2931 return 0;
2932}
2933
2934int
2935Channel::GetChannelOutputVolumeScaling(float& scaling) const
2936{
wu@webrtc.org63420662013-10-17 18:28:55 +00002937 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002938 scaling = _outputGain;
2939 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2940 VoEId(_instanceId,_channelId),
2941 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2942 return 0;
2943}
2944
niklase@google.com470e71d2011-07-07 08:21:25 +00002945int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002946 int lengthMs, int attenuationDb,
2947 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002948{
2949 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2950 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2951 playDtmfEvent);
2952
2953 _playOutbandDtmfEvent = playDtmfEvent;
2954
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002955 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002956 attenuationDb) != 0)
2957 {
2958 _engineStatisticsPtr->SetLastError(
2959 VE_SEND_DTMF_FAILED,
2960 kTraceWarning,
2961 "SendTelephoneEventOutband() failed to send event");
2962 return -1;
2963 }
2964 return 0;
2965}
2966
2967int Channel::SendTelephoneEventInband(unsigned char eventCode,
2968 int lengthMs,
2969 int attenuationDb,
2970 bool playDtmfEvent)
2971{
2972 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2973 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2974 playDtmfEvent);
2975
2976 _playInbandDtmfEvent = playDtmfEvent;
2977 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2978
2979 return 0;
2980}
2981
2982int
2983Channel::SetDtmfPlayoutStatus(bool enable)
2984{
2985 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2986 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002987 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002988 {
2989 _engineStatisticsPtr->SetLastError(
2990 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2991 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2992 return -1;
2993 }
2994 return 0;
2995}
2996
2997bool
2998Channel::DtmfPlayoutStatus() const
2999{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003000 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003001}
3002
3003int
3004Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3005{
3006 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3007 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003008 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003009 {
3010 _engineStatisticsPtr->SetLastError(
3011 VE_INVALID_ARGUMENT, kTraceError,
3012 "SetSendTelephoneEventPayloadType() invalid type");
3013 return -1;
3014 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003015 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003016 codec.plfreq = 8000;
3017 codec.pltype = type;
3018 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003019 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003020 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003021 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3022 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3023 _engineStatisticsPtr->SetLastError(
3024 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3025 "SetSendTelephoneEventPayloadType() failed to register send"
3026 "payload type");
3027 return -1;
3028 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003029 }
3030 _sendTelephoneEventPayloadType = type;
3031 return 0;
3032}
3033
3034int
3035Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3036{
3037 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3038 "Channel::GetSendTelephoneEventPayloadType()");
3039 type = _sendTelephoneEventPayloadType;
3040 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3041 VoEId(_instanceId,_channelId),
3042 "GetSendTelephoneEventPayloadType() => type=%u", type);
3043 return 0;
3044}
3045
niklase@google.com470e71d2011-07-07 08:21:25 +00003046int
3047Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3048{
3049 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3050 "Channel::UpdateRxVadDetection()");
3051
3052 int vadDecision = 1;
3053
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003054 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003055
3056 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3057 {
3058 OnRxVadDetected(vadDecision);
3059 _oldVadDecision = vadDecision;
3060 }
3061
3062 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3063 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3064 vadDecision);
3065 return 0;
3066}
3067
3068int
3069Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3070{
3071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3072 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003073 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003074
3075 if (_rxVadObserverPtr)
3076 {
3077 _engineStatisticsPtr->SetLastError(
3078 VE_INVALID_OPERATION, kTraceError,
3079 "RegisterRxVadObserver() observer already enabled");
3080 return -1;
3081 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003082 _rxVadObserverPtr = &observer;
3083 _RxVadDetection = true;
3084 return 0;
3085}
3086
3087int
3088Channel::DeRegisterRxVadObserver()
3089{
3090 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3091 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003092 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003093
3094 if (!_rxVadObserverPtr)
3095 {
3096 _engineStatisticsPtr->SetLastError(
3097 VE_INVALID_OPERATION, kTraceWarning,
3098 "DeRegisterRxVadObserver() observer already disabled");
3099 return 0;
3100 }
3101 _rxVadObserverPtr = NULL;
3102 _RxVadDetection = false;
3103 return 0;
3104}
3105
3106int
3107Channel::VoiceActivityIndicator(int &activity)
3108{
3109 activity = _sendFrameType;
3110
3111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003112 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003113 return 0;
3114}
3115
3116#ifdef WEBRTC_VOICE_ENGINE_AGC
3117
3118int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003119Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003120{
3121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3122 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3123 (int)enable, (int)mode);
3124
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003125 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003126 switch (mode)
3127 {
3128 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003129 break;
3130 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003131 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003132 break;
3133 case kAgcFixedDigital:
3134 agcMode = GainControl::kFixedDigital;
3135 break;
3136 case kAgcAdaptiveDigital:
3137 agcMode =GainControl::kAdaptiveDigital;
3138 break;
3139 default:
3140 _engineStatisticsPtr->SetLastError(
3141 VE_INVALID_ARGUMENT, kTraceError,
3142 "SetRxAgcStatus() invalid Agc mode");
3143 return -1;
3144 }
3145
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003146 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003147 {
3148 _engineStatisticsPtr->SetLastError(
3149 VE_APM_ERROR, kTraceError,
3150 "SetRxAgcStatus() failed to set Agc mode");
3151 return -1;
3152 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003153 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003154 {
3155 _engineStatisticsPtr->SetLastError(
3156 VE_APM_ERROR, kTraceError,
3157 "SetRxAgcStatus() failed to set Agc state");
3158 return -1;
3159 }
3160
3161 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003162 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003163
3164 return 0;
3165}
3166
3167int
3168Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3169{
3170 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3171 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3172
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003173 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003174 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003175 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003176
3177 enabled = enable;
3178
3179 switch (agcMode)
3180 {
3181 case GainControl::kFixedDigital:
3182 mode = kAgcFixedDigital;
3183 break;
3184 case GainControl::kAdaptiveDigital:
3185 mode = kAgcAdaptiveDigital;
3186 break;
3187 default:
3188 _engineStatisticsPtr->SetLastError(
3189 VE_APM_ERROR, kTraceError,
3190 "GetRxAgcStatus() invalid Agc mode");
3191 return -1;
3192 }
3193
3194 return 0;
3195}
3196
3197int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003198Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003199{
3200 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3201 "Channel::SetRxAgcConfig()");
3202
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003203 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003204 config.targetLeveldBOv) != 0)
3205 {
3206 _engineStatisticsPtr->SetLastError(
3207 VE_APM_ERROR, kTraceError,
3208 "SetRxAgcConfig() failed to set target peak |level|"
3209 "(or envelope) of the Agc");
3210 return -1;
3211 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003212 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003213 config.digitalCompressionGaindB) != 0)
3214 {
3215 _engineStatisticsPtr->SetLastError(
3216 VE_APM_ERROR, kTraceError,
3217 "SetRxAgcConfig() failed to set the range in |gain| the"
3218 " digital compression stage may apply");
3219 return -1;
3220 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003221 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003222 config.limiterEnable) != 0)
3223 {
3224 _engineStatisticsPtr->SetLastError(
3225 VE_APM_ERROR, kTraceError,
3226 "SetRxAgcConfig() failed to set hard limiter to the signal");
3227 return -1;
3228 }
3229
3230 return 0;
3231}
3232
3233int
3234Channel::GetRxAgcConfig(AgcConfig& config)
3235{
3236 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3237 "Channel::GetRxAgcConfig(config=%?)");
3238
3239 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003240 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003241 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003242 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003243 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003244 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003245
3246 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3247 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3248 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3249 " limiterEnable=%d",
3250 config.targetLeveldBOv,
3251 config.digitalCompressionGaindB,
3252 config.limiterEnable);
3253
3254 return 0;
3255}
3256
3257#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3258
3259#ifdef WEBRTC_VOICE_ENGINE_NR
3260
3261int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003262Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003263{
3264 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3265 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3266 (int)enable, (int)mode);
3267
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003268 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 switch (mode)
3270 {
3271
3272 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003273 break;
3274 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003275 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003276 break;
3277 case kNsConference:
3278 nsLevel = NoiseSuppression::kHigh;
3279 break;
3280 case kNsLowSuppression:
3281 nsLevel = NoiseSuppression::kLow;
3282 break;
3283 case kNsModerateSuppression:
3284 nsLevel = NoiseSuppression::kModerate;
3285 break;
3286 case kNsHighSuppression:
3287 nsLevel = NoiseSuppression::kHigh;
3288 break;
3289 case kNsVeryHighSuppression:
3290 nsLevel = NoiseSuppression::kVeryHigh;
3291 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003292 }
3293
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003294 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003295 != 0)
3296 {
3297 _engineStatisticsPtr->SetLastError(
3298 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003299 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003300 return -1;
3301 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003302 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003303 {
3304 _engineStatisticsPtr->SetLastError(
3305 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003306 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003307 return -1;
3308 }
3309
3310 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003311 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003312
3313 return 0;
3314}
3315
3316int
3317Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3318{
3319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3320 "Channel::GetRxNsStatus(enable=?, mode=?)");
3321
3322 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003323 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003324 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003325 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003326
3327 enabled = enable;
3328
3329 switch (ncLevel)
3330 {
3331 case NoiseSuppression::kLow:
3332 mode = kNsLowSuppression;
3333 break;
3334 case NoiseSuppression::kModerate:
3335 mode = kNsModerateSuppression;
3336 break;
3337 case NoiseSuppression::kHigh:
3338 mode = kNsHighSuppression;
3339 break;
3340 case NoiseSuppression::kVeryHigh:
3341 mode = kNsVeryHighSuppression;
3342 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003343 }
3344
3345 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3346 VoEId(_instanceId,_channelId),
3347 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3348 return 0;
3349}
3350
3351#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3352
3353int
3354Channel::RegisterRTPObserver(VoERTPObserver& observer)
3355{
3356 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3357 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003358 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003359
3360 if (_rtpObserverPtr)
3361 {
3362 _engineStatisticsPtr->SetLastError(
3363 VE_INVALID_OPERATION, kTraceError,
3364 "RegisterRTPObserver() observer already enabled");
3365 return -1;
3366 }
3367
3368 _rtpObserverPtr = &observer;
3369 _rtpObserver = true;
3370
3371 return 0;
3372}
3373
3374int
3375Channel::DeRegisterRTPObserver()
3376{
3377 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3378 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003379 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003380
3381 if (!_rtpObserverPtr)
3382 {
3383 _engineStatisticsPtr->SetLastError(
3384 VE_INVALID_OPERATION, kTraceWarning,
3385 "DeRegisterRTPObserver() observer already disabled");
3386 return 0;
3387 }
3388
3389 _rtpObserver = false;
3390 _rtpObserverPtr = NULL;
3391
3392 return 0;
3393}
3394
3395int
3396Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3397{
3398 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3399 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003400 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003401
3402 if (_rtcpObserverPtr)
3403 {
3404 _engineStatisticsPtr->SetLastError(
3405 VE_INVALID_OPERATION, kTraceError,
3406 "RegisterRTCPObserver() observer already enabled");
3407 return -1;
3408 }
3409
3410 _rtcpObserverPtr = &observer;
3411 _rtcpObserver = true;
3412
3413 return 0;
3414}
3415
3416int
3417Channel::DeRegisterRTCPObserver()
3418{
3419 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3420 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003421 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003422
3423 if (!_rtcpObserverPtr)
3424 {
3425 _engineStatisticsPtr->SetLastError(
3426 VE_INVALID_OPERATION, kTraceWarning,
3427 "DeRegisterRTCPObserver() observer already disabled");
3428 return 0;
3429 }
3430
3431 _rtcpObserver = false;
3432 _rtcpObserverPtr = NULL;
3433
3434 return 0;
3435}
3436
3437int
3438Channel::SetLocalSSRC(unsigned int ssrc)
3439{
3440 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3441 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003442 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003443 {
3444 _engineStatisticsPtr->SetLastError(
3445 VE_ALREADY_SENDING, kTraceError,
3446 "SetLocalSSRC() already sending");
3447 return -1;
3448 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003449 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003450 {
3451 _engineStatisticsPtr->SetLastError(
3452 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3453 "SetLocalSSRC() failed to set SSRC");
3454 return -1;
3455 }
3456 return 0;
3457}
3458
3459int
3460Channel::GetLocalSSRC(unsigned int& ssrc)
3461{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003462 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3464 VoEId(_instanceId,_channelId),
3465 "GetLocalSSRC() => ssrc=%lu", ssrc);
3466 return 0;
3467}
3468
3469int
3470Channel::GetRemoteSSRC(unsigned int& ssrc)
3471{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003472 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003473 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3474 VoEId(_instanceId,_channelId),
3475 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3476 return 0;
3477}
3478
3479int
3480Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3481{
3482 if (arrCSRC == NULL)
3483 {
3484 _engineStatisticsPtr->SetLastError(
3485 VE_INVALID_ARGUMENT, kTraceError,
3486 "GetRemoteCSRCs() invalid array argument");
3487 return -1;
3488 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003489 uint32_t arrOfCSRC[kRtpCsrcSize];
3490 int32_t CSRCs(0);
braveyao@webrtc.orgcdefc912014-03-11 16:19:56 +00003491 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003492 if (CSRCs > 0)
3493 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003494 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003495 for (int i = 0; i < (int) CSRCs; i++)
3496 {
3497 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3498 VoEId(_instanceId, _channelId),
3499 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3500 }
3501 } else
3502 {
3503 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3504 VoEId(_instanceId, _channelId),
3505 "GetRemoteCSRCs() => list is empty!");
3506 }
3507 return CSRCs;
3508}
3509
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003510int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003511 if (rtp_audioproc_.get() == NULL) {
3512 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3513 _channelId)));
3514 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003515
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003516 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3517 AudioProcessing::kNoError) {
3518 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3519 "Failed to enable AudioProcessing::level_estimator()");
3520 return -1;
3521 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003522
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003523 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003524
3525 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003526}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003527
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003528int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3529 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3530}
3531
3532int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3533 rtp_header_parser_->DeregisterRtpHeaderExtension(
3534 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003535 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3536 kRtpExtensionAbsoluteSendTime, id)) {
3537 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003538 }
3539 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003540}
3541
3542int
3543Channel::SetRTCPStatus(bool enable)
3544{
3545 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3546 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003547 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003548 kRtcpCompound : kRtcpOff) != 0)
3549 {
3550 _engineStatisticsPtr->SetLastError(
3551 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3552 "SetRTCPStatus() failed to set RTCP status");
3553 return -1;
3554 }
3555 return 0;
3556}
3557
3558int
3559Channel::GetRTCPStatus(bool& enabled)
3560{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003561 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003562 enabled = (method != kRtcpOff);
3563 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3564 VoEId(_instanceId,_channelId),
3565 "GetRTCPStatus() => enabled=%d", enabled);
3566 return 0;
3567}
3568
3569int
3570Channel::SetRTCP_CNAME(const char cName[256])
3571{
3572 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3573 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003574 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003575 {
3576 _engineStatisticsPtr->SetLastError(
3577 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3578 "SetRTCP_CNAME() failed to set RTCP CNAME");
3579 return -1;
3580 }
3581 return 0;
3582}
3583
3584int
3585Channel::GetRTCP_CNAME(char cName[256])
3586{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003587 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003588 {
3589 _engineStatisticsPtr->SetLastError(
3590 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3591 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3592 return -1;
3593 }
3594 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3595 VoEId(_instanceId, _channelId),
3596 "GetRTCP_CNAME() => cName=%s", cName);
3597 return 0;
3598}
3599
3600int
3601Channel::GetRemoteRTCP_CNAME(char cName[256])
3602{
3603 if (cName == NULL)
3604 {
3605 _engineStatisticsPtr->SetLastError(
3606 VE_INVALID_ARGUMENT, kTraceError,
3607 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3608 return -1;
3609 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003610 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003611 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003612 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003613 {
3614 _engineStatisticsPtr->SetLastError(
3615 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3616 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3617 return -1;
3618 }
3619 strcpy(cName, cname);
3620 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3621 VoEId(_instanceId, _channelId),
3622 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3623 return 0;
3624}
3625
3626int
3627Channel::GetRemoteRTCPData(
3628 unsigned int& NTPHigh,
3629 unsigned int& NTPLow,
3630 unsigned int& timestamp,
3631 unsigned int& playoutTimestamp,
3632 unsigned int* jitter,
3633 unsigned short* fractionLost)
3634{
3635 // --- Information from sender info in received Sender Reports
3636
3637 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003638 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003639 {
3640 _engineStatisticsPtr->SetLastError(
3641 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003642 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003643 "side");
3644 return -1;
3645 }
3646
3647 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3648 // and octet count)
3649 NTPHigh = senderInfo.NTPseconds;
3650 NTPLow = senderInfo.NTPfraction;
3651 timestamp = senderInfo.RTPtimeStamp;
3652
3653 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3654 VoEId(_instanceId, _channelId),
3655 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3656 "timestamp=%lu",
3657 NTPHigh, NTPLow, timestamp);
3658
3659 // --- Locally derived information
3660
3661 // This value is updated on each incoming RTCP packet (0 when no packet
3662 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003663 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003664
3665 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3666 VoEId(_instanceId, _channelId),
3667 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003668 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003669
3670 if (NULL != jitter || NULL != fractionLost)
3671 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003672 // Get all RTCP receiver report blocks that have been received on this
3673 // channel. If we receive RTP packets from a remote source we know the
3674 // remote SSRC and use the report block from him.
3675 // Otherwise use the first report block.
3676 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003677 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003678 remote_stats.empty()) {
3679 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3680 VoEId(_instanceId, _channelId),
3681 "GetRemoteRTCPData() failed to measure statistics due"
3682 " to lack of received RTP and/or RTCP packets");
3683 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003684 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003685
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003686 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003687 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3688 for (; it != remote_stats.end(); ++it) {
3689 if (it->remoteSSRC == remoteSSRC)
3690 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003691 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003692
3693 if (it == remote_stats.end()) {
3694 // If we have not received any RTCP packets from this SSRC it probably
3695 // means that we have not received any RTP packets.
3696 // Use the first received report block instead.
3697 it = remote_stats.begin();
3698 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003699 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003700
xians@webrtc.org79af7342012-01-31 12:22:14 +00003701 if (jitter) {
3702 *jitter = it->jitter;
3703 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3704 VoEId(_instanceId, _channelId),
3705 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3706 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003707
xians@webrtc.org79af7342012-01-31 12:22:14 +00003708 if (fractionLost) {
3709 *fractionLost = it->fractionLost;
3710 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3711 VoEId(_instanceId, _channelId),
3712 "GetRemoteRTCPData() => fractionLost = %lu",
3713 *fractionLost);
3714 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003715 }
3716 return 0;
3717}
3718
3719int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003720Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003721 unsigned int name,
3722 const char* data,
3723 unsigned short dataLengthInBytes)
3724{
3725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3726 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003727 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003728 {
3729 _engineStatisticsPtr->SetLastError(
3730 VE_NOT_SENDING, kTraceError,
3731 "SendApplicationDefinedRTCPPacket() not sending");
3732 return -1;
3733 }
3734 if (NULL == data)
3735 {
3736 _engineStatisticsPtr->SetLastError(
3737 VE_INVALID_ARGUMENT, kTraceError,
3738 "SendApplicationDefinedRTCPPacket() invalid data value");
3739 return -1;
3740 }
3741 if (dataLengthInBytes % 4 != 0)
3742 {
3743 _engineStatisticsPtr->SetLastError(
3744 VE_INVALID_ARGUMENT, kTraceError,
3745 "SendApplicationDefinedRTCPPacket() invalid length value");
3746 return -1;
3747 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003748 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003749 if (status == kRtcpOff)
3750 {
3751 _engineStatisticsPtr->SetLastError(
3752 VE_RTCP_ERROR, kTraceError,
3753 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3754 return -1;
3755 }
3756
3757 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003758 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003759 subType,
3760 name,
3761 (const unsigned char*) data,
3762 dataLengthInBytes) != 0)
3763 {
3764 _engineStatisticsPtr->SetLastError(
3765 VE_SEND_ERROR, kTraceError,
3766 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3767 return -1;
3768 }
3769 return 0;
3770}
3771
3772int
3773Channel::GetRTPStatistics(
3774 unsigned int& averageJitterMs,
3775 unsigned int& maxJitterMs,
3776 unsigned int& discardedPackets)
3777{
niklase@google.com470e71d2011-07-07 08:21:25 +00003778 // The jitter statistics is updated for each received RTP packet and is
3779 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003780 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3781 // If RTCP is off, there is no timed thread in the RTCP module regularly
3782 // generating new stats, trigger the update manually here instead.
3783 StreamStatistician* statistician =
3784 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3785 if (statistician) {
3786 // Don't use returned statistics, use data from proxy instead so that
3787 // max jitter can be fetched atomically.
3788 RtcpStatistics s;
3789 statistician->GetStatistics(&s, true);
3790 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003791 }
3792
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003793 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003794 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003795 if (playoutFrequency > 0) {
3796 // Scale RTP statistics given the current playout frequency
3797 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3798 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003799 }
3800
3801 discardedPackets = _numberOfDiscardedPackets;
3802
3803 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3804 VoEId(_instanceId, _channelId),
3805 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003806 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003807 averageJitterMs, maxJitterMs, discardedPackets);
3808 return 0;
3809}
3810
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003811int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3812 if (sender_info == NULL) {
3813 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3814 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3815 return -1;
3816 }
3817
3818 // Get the sender info from the latest received RTCP Sender Report.
3819 RTCPSenderInfo rtcp_sender_info;
3820 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3821 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3822 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3823 return -1;
3824 }
3825
3826 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3827 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3828 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3829 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3830 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3831 return 0;
3832}
3833
3834int Channel::GetRemoteRTCPReportBlocks(
3835 std::vector<ReportBlock>* report_blocks) {
3836 if (report_blocks == NULL) {
3837 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3838 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3839 return -1;
3840 }
3841
3842 // Get the report blocks from the latest received RTCP Sender or Receiver
3843 // Report. Each element in the vector contains the sender's SSRC and a
3844 // report block according to RFC 3550.
3845 std::vector<RTCPReportBlock> rtcp_report_blocks;
3846 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3847 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3848 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3849 return -1;
3850 }
3851
3852 if (rtcp_report_blocks.empty())
3853 return 0;
3854
3855 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3856 for (; it != rtcp_report_blocks.end(); ++it) {
3857 ReportBlock report_block;
3858 report_block.sender_SSRC = it->remoteSSRC;
3859 report_block.source_SSRC = it->sourceSSRC;
3860 report_block.fraction_lost = it->fractionLost;
3861 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3862 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3863 report_block.interarrival_jitter = it->jitter;
3864 report_block.last_SR_timestamp = it->lastSR;
3865 report_block.delay_since_last_SR = it->delaySinceLastSR;
3866 report_blocks->push_back(report_block);
3867 }
3868 return 0;
3869}
3870
niklase@google.com470e71d2011-07-07 08:21:25 +00003871int
3872Channel::GetRTPStatistics(CallStatistics& stats)
3873{
niklase@google.com470e71d2011-07-07 08:21:25 +00003874 // --- Part one of the final structure (four values)
3875
3876 // The jitter statistics is updated for each received RTP packet and is
3877 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003878 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003879 StreamStatistician* statistician =
3880 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3881 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003882 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3883 _engineStatisticsPtr->SetLastError(
3884 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3885 "GetRTPStatistics() failed to read RTP statistics from the "
3886 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003887 }
3888
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003889 stats.fractionLost = statistics.fraction_lost;
3890 stats.cumulativeLost = statistics.cumulative_lost;
3891 stats.extendedMax = statistics.extended_max_sequence_number;
3892 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003893
3894 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3895 VoEId(_instanceId, _channelId),
3896 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003897 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003898 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3899 stats.jitterSamples);
3900
3901 // --- Part two of the final structure (one value)
3902
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003903 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003904 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003905 if (method == kRtcpOff)
3906 {
3907 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3908 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003909 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003910 "measurements cannot be retrieved");
3911 } else
3912 {
3913 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003914 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003915 if (remoteSSRC > 0)
3916 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003917 uint16_t avgRTT(0);
3918 uint16_t maxRTT(0);
3919 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003920
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003921 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003922 != 0)
3923 {
3924 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3925 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003926 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003927 "the RTP/RTCP module");
3928 }
3929 } else
3930 {
3931 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3932 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003933 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003934 "RTP packets have been received yet");
3935 }
3936 }
3937
3938 stats.rttMs = static_cast<int> (RTT);
3939
3940 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3941 VoEId(_instanceId, _channelId),
3942 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3943
3944 // --- Part three of the final structure (four values)
3945
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003946 uint32_t bytesSent(0);
3947 uint32_t packetsSent(0);
3948 uint32_t bytesReceived(0);
3949 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003950
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003951 if (statistician) {
3952 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3953 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003954
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003955 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003956 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003957 {
3958 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3959 VoEId(_instanceId, _channelId),
3960 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003961 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003962 }
3963
3964 stats.bytesSent = bytesSent;
3965 stats.packetsSent = packetsSent;
3966 stats.bytesReceived = bytesReceived;
3967 stats.packetsReceived = packetsReceived;
3968
3969 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3970 VoEId(_instanceId, _channelId),
3971 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003972 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003973 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3974 stats.packetsReceived);
3975
3976 return 0;
3977}
3978
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003979int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3980 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3981 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003982
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003983 if (enable) {
3984 if (redPayloadtype < 0 || redPayloadtype > 127) {
3985 _engineStatisticsPtr->SetLastError(
3986 VE_PLTYPE_ERROR, kTraceError,
3987 "SetFECStatus() invalid RED payload type");
3988 return -1;
3989 }
3990
3991 if (SetRedPayloadType(redPayloadtype) < 0) {
3992 _engineStatisticsPtr->SetLastError(
3993 VE_CODEC_ERROR, kTraceError,
3994 "SetSecondarySendCodec() Failed to register RED ACM");
3995 return -1;
3996 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003997 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003998
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003999 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004000 _engineStatisticsPtr->SetLastError(
4001 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4002 "SetFECStatus() failed to set FEC state in the ACM");
4003 return -1;
4004 }
4005 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004006}
4007
4008int
4009Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4010{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004011 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004012 if (enabled)
4013 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004014 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004015 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004016 {
4017 _engineStatisticsPtr->SetLastError(
4018 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4019 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4020 "module");
4021 return -1;
4022 }
4023 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4024 VoEId(_instanceId, _channelId),
4025 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4026 enabled, redPayloadtype);
4027 return 0;
4028 }
4029 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4030 VoEId(_instanceId, _channelId),
4031 "GetFECStatus() => enabled=%d", enabled);
4032 return 0;
4033}
4034
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004035void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4036 // None of these functions can fail.
4037 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004038 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4039 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004040 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004041 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004042 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004043 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004044}
4045
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004046// Called when we are missing one or more packets.
4047int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004048 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4049}
4050
niklase@google.com470e71d2011-07-07 08:21:25 +00004051int
niklase@google.com470e71d2011-07-07 08:21:25 +00004052Channel::StartRTPDump(const char fileNameUTF8[1024],
4053 RTPDirections direction)
4054{
4055 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4056 "Channel::StartRTPDump()");
4057 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4058 {
4059 _engineStatisticsPtr->SetLastError(
4060 VE_INVALID_ARGUMENT, kTraceError,
4061 "StartRTPDump() invalid RTP direction");
4062 return -1;
4063 }
4064 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4065 &_rtpDumpIn : &_rtpDumpOut;
4066 if (rtpDumpPtr == NULL)
4067 {
4068 assert(false);
4069 return -1;
4070 }
4071 if (rtpDumpPtr->IsActive())
4072 {
4073 rtpDumpPtr->Stop();
4074 }
4075 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4076 {
4077 _engineStatisticsPtr->SetLastError(
4078 VE_BAD_FILE, kTraceError,
4079 "StartRTPDump() failed to create file");
4080 return -1;
4081 }
4082 return 0;
4083}
4084
4085int
4086Channel::StopRTPDump(RTPDirections direction)
4087{
4088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4089 "Channel::StopRTPDump()");
4090 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4091 {
4092 _engineStatisticsPtr->SetLastError(
4093 VE_INVALID_ARGUMENT, kTraceError,
4094 "StopRTPDump() invalid RTP direction");
4095 return -1;
4096 }
4097 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4098 &_rtpDumpIn : &_rtpDumpOut;
4099 if (rtpDumpPtr == NULL)
4100 {
4101 assert(false);
4102 return -1;
4103 }
4104 if (!rtpDumpPtr->IsActive())
4105 {
4106 return 0;
4107 }
4108 return rtpDumpPtr->Stop();
4109}
4110
4111bool
4112Channel::RTPDumpIsActive(RTPDirections direction)
4113{
4114 if ((direction != kRtpIncoming) &&
4115 (direction != kRtpOutgoing))
4116 {
4117 _engineStatisticsPtr->SetLastError(
4118 VE_INVALID_ARGUMENT, kTraceError,
4119 "RTPDumpIsActive() invalid RTP direction");
4120 return false;
4121 }
4122 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4123 &_rtpDumpIn : &_rtpDumpOut;
4124 return rtpDumpPtr->IsActive();
4125}
4126
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00004127void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
4128 int video_channel) {
4129 CriticalSectionScoped cs(&_callbackCritSect);
4130 if (vie_network_) {
4131 vie_network_->Release();
4132 vie_network_ = NULL;
4133 }
4134 video_channel_ = -1;
4135
4136 if (vie_network != NULL && video_channel != -1) {
4137 vie_network_ = vie_network;
4138 video_channel_ = video_channel;
4139 }
4140}
4141
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004142uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004143Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004144{
4145 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004146 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004147 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004148 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004149 return 0;
4150}
4151
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004152void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004153 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004154 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004155 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004156 CodecInst codec;
4157 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004158
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004159 if (!mono_recording_audio_.get()) {
4160 // Temporary space for DownConvertToCodecFormat.
4161 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004162 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004163 DownConvertToCodecFormat(audio_data,
4164 number_of_frames,
4165 number_of_channels,
4166 sample_rate,
4167 codec.channels,
4168 codec.plfreq,
4169 mono_recording_audio_.get(),
4170 &input_resampler_,
4171 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004172}
4173
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004174uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004175Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004176{
4177 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4178 "Channel::PrepareEncodeAndSend()");
4179
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004180 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004181 {
4182 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4183 "Channel::PrepareEncodeAndSend() invalid audio frame");
4184 return -1;
4185 }
4186
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004187 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00004188 {
4189 MixOrReplaceAudioWithFile(mixingFrequency);
4190 }
4191
wu@webrtc.org63420662013-10-17 18:28:55 +00004192 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004193 {
4194 AudioFrameOperations::Mute(_audioFrame);
4195 }
4196
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004197 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00004198 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004199 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004200 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004201 if (_inputExternalMediaCallbackPtr)
4202 {
4203 _inputExternalMediaCallbackPtr->Process(
4204 _channelId,
4205 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004206 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004207 _audioFrame.samples_per_channel_,
4208 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004209 isStereo);
4210 }
4211 }
4212
4213 InsertInbandDtmfTone();
4214
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004215 if (_includeAudioLevelIndication) {
4216 // Performs level analysis only; does not affect the signal.
4217 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4218 if (err) {
4219 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4220 assert(false);
4221 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004222 }
4223
niklase@google.com470e71d2011-07-07 08:21:25 +00004224 return 0;
4225}
4226
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004227uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004228Channel::EncodeAndSend()
4229{
4230 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4231 "Channel::EncodeAndSend()");
4232
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004233 assert(_audioFrame.num_channels_ <= 2);
4234 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004235 {
4236 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4237 "Channel::EncodeAndSend() invalid audio frame");
4238 return -1;
4239 }
4240
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004241 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004242
4243 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4244
4245 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004246 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004247 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004248 {
4249 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4250 "Channel::EncodeAndSend() ACM encoding failed");
4251 return -1;
4252 }
4253
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004254 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004255
4256 // --- Encode if complete frame is ready
4257
4258 // This call will trigger AudioPacketizationCallback::SendData if encoding
4259 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004260 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004261}
4262
4263int Channel::RegisterExternalMediaProcessing(
4264 ProcessingTypes type,
4265 VoEMediaProcess& processObject)
4266{
4267 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4268 "Channel::RegisterExternalMediaProcessing()");
4269
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004270 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004271
4272 if (kPlaybackPerChannel == type)
4273 {
4274 if (_outputExternalMediaCallbackPtr)
4275 {
4276 _engineStatisticsPtr->SetLastError(
4277 VE_INVALID_OPERATION, kTraceError,
4278 "Channel::RegisterExternalMediaProcessing() "
4279 "output external media already enabled");
4280 return -1;
4281 }
4282 _outputExternalMediaCallbackPtr = &processObject;
4283 _outputExternalMedia = true;
4284 }
4285 else if (kRecordingPerChannel == type)
4286 {
4287 if (_inputExternalMediaCallbackPtr)
4288 {
4289 _engineStatisticsPtr->SetLastError(
4290 VE_INVALID_OPERATION, kTraceError,
4291 "Channel::RegisterExternalMediaProcessing() "
4292 "output external media already enabled");
4293 return -1;
4294 }
4295 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004296 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00004297 }
4298 return 0;
4299}
4300
4301int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4302{
4303 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4304 "Channel::DeRegisterExternalMediaProcessing()");
4305
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004306 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004307
4308 if (kPlaybackPerChannel == type)
4309 {
4310 if (!_outputExternalMediaCallbackPtr)
4311 {
4312 _engineStatisticsPtr->SetLastError(
4313 VE_INVALID_OPERATION, kTraceWarning,
4314 "Channel::DeRegisterExternalMediaProcessing() "
4315 "output external media already disabled");
4316 return 0;
4317 }
4318 _outputExternalMedia = false;
4319 _outputExternalMediaCallbackPtr = NULL;
4320 }
4321 else if (kRecordingPerChannel == type)
4322 {
4323 if (!_inputExternalMediaCallbackPtr)
4324 {
4325 _engineStatisticsPtr->SetLastError(
4326 VE_INVALID_OPERATION, kTraceWarning,
4327 "Channel::DeRegisterExternalMediaProcessing() "
4328 "input external media already disabled");
4329 return 0;
4330 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004331 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00004332 _inputExternalMediaCallbackPtr = NULL;
4333 }
4334
4335 return 0;
4336}
4337
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004338int Channel::SetExternalMixing(bool enabled) {
4339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4340 "Channel::SetExternalMixing(enabled=%d)", enabled);
4341
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004342 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004343 {
4344 _engineStatisticsPtr->SetLastError(
4345 VE_INVALID_OPERATION, kTraceError,
4346 "Channel::SetExternalMixing() "
4347 "external mixing cannot be changed while playing.");
4348 return -1;
4349 }
4350
4351 _externalMixing = enabled;
4352
4353 return 0;
4354}
4355
niklase@google.com470e71d2011-07-07 08:21:25 +00004356int
4357Channel::ResetRTCPStatistics()
4358{
4359 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4360 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004361 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004362 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004363 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004364}
4365
4366int
4367Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4368{
4369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4370 "Channel::GetRoundTripTimeSummary()");
4371 // Override default module outputs for the case when RTCP is disabled.
4372 // This is done to ensure that we are backward compatible with the
4373 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004374 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004375 {
4376 delaysMs.min = -1;
4377 delaysMs.max = -1;
4378 delaysMs.average = -1;
4379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4380 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4381 " valid RTT measurements cannot be retrieved");
4382 return 0;
4383 }
4384
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004385 uint32_t remoteSSRC;
4386 uint16_t RTT;
4387 uint16_t avgRTT;
4388 uint16_t maxRTT;
4389 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004390 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004391 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004392 if (remoteSSRC == 0)
4393 {
4394 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4395 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4396 " since no RTP packet has been received yet");
4397 }
4398
4399 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4400 // channel and SSRC. The SSRC is required to parse out the correct source
4401 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004402 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004403 {
4404 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4405 "GetRoundTripTimeSummary unable to retrieve RTT values"
4406 " from the RTCP layer");
4407 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4408 }
4409 else
4410 {
4411 delaysMs.min = minRTT;
4412 delaysMs.max = maxRTT;
4413 delaysMs.average = avgRTT;
4414 }
4415 return 0;
4416}
4417
4418int
4419Channel::GetNetworkStatistics(NetworkStatistics& stats)
4420{
4421 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4422 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004423 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004424 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004425 if (return_value >= 0) {
4426 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4427 }
4428 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004429}
4430
wu@webrtc.org24301a62013-12-13 19:17:43 +00004431void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4432 audio_coding_->GetDecodingCallStatistics(stats);
4433}
4434
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004435bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4436 int* playout_buffer_delay_ms) const {
4437 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004439 "Channel::GetDelayEstimate() no valid estimate.");
4440 return false;
4441 }
4442 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4443 _recPacketDelayMs;
4444 *playout_buffer_delay_ms = playout_delay_ms_;
4445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4446 "Channel::GetDelayEstimate()");
4447 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004448}
4449
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004450int Channel::SetInitialPlayoutDelay(int delay_ms)
4451{
4452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4453 "Channel::SetInitialPlayoutDelay()");
4454 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4455 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4456 {
4457 _engineStatisticsPtr->SetLastError(
4458 VE_INVALID_ARGUMENT, kTraceError,
4459 "SetInitialPlayoutDelay() invalid min delay");
4460 return -1;
4461 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004462 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004463 {
4464 _engineStatisticsPtr->SetLastError(
4465 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4466 "SetInitialPlayoutDelay() failed to set min playout delay");
4467 return -1;
4468 }
4469 return 0;
4470}
4471
4472
niklase@google.com470e71d2011-07-07 08:21:25 +00004473int
4474Channel::SetMinimumPlayoutDelay(int delayMs)
4475{
4476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4477 "Channel::SetMinimumPlayoutDelay()");
4478 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4479 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4480 {
4481 _engineStatisticsPtr->SetLastError(
4482 VE_INVALID_ARGUMENT, kTraceError,
4483 "SetMinimumPlayoutDelay() invalid min delay");
4484 return -1;
4485 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004486 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004487 {
4488 _engineStatisticsPtr->SetLastError(
4489 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4490 "SetMinimumPlayoutDelay() failed to set min playout delay");
4491 return -1;
4492 }
4493 return 0;
4494}
4495
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004496void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4497 uint32_t playout_timestamp = 0;
4498
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004499 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004500 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4501 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4502 " timestamp from the ACM");
4503 _engineStatisticsPtr->SetLastError(
4504 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4505 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4506 return;
4507 }
4508
4509 uint16_t delay_ms = 0;
4510 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4511 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4512 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4513 " delay from the ADM");
4514 _engineStatisticsPtr->SetLastError(
4515 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4516 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4517 return;
4518 }
4519
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004520 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004521 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004522 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004523 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4524 playout_frequency = 8000;
4525 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4526 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004527 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004528 }
4529
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004530 jitter_buffer_playout_timestamp_ = playout_timestamp;
4531
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004532 // Remove the playout delay.
4533 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4534
4535 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4536 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4537 playout_timestamp);
4538
4539 if (rtcp) {
4540 playout_timestamp_rtcp_ = playout_timestamp;
4541 } else {
4542 playout_timestamp_rtp_ = playout_timestamp;
4543 }
4544 playout_delay_ms_ = delay_ms;
4545}
4546
4547int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4549 "Channel::GetPlayoutTimestamp()");
4550 if (playout_timestamp_rtp_ == 0) {
4551 _engineStatisticsPtr->SetLastError(
4552 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4553 "GetPlayoutTimestamp() failed to retrieve timestamp");
4554 return -1;
4555 }
4556 timestamp = playout_timestamp_rtp_;
4557 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4558 VoEId(_instanceId,_channelId),
4559 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4560 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004561}
4562
4563int
4564Channel::SetInitTimestamp(unsigned int timestamp)
4565{
4566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4567 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004568 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004569 {
4570 _engineStatisticsPtr->SetLastError(
4571 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4572 return -1;
4573 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004574 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004575 {
4576 _engineStatisticsPtr->SetLastError(
4577 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4578 "SetInitTimestamp() failed to set timestamp");
4579 return -1;
4580 }
4581 return 0;
4582}
4583
4584int
4585Channel::SetInitSequenceNumber(short sequenceNumber)
4586{
4587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4588 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004589 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004590 {
4591 _engineStatisticsPtr->SetLastError(
4592 VE_SENDING, kTraceError,
4593 "SetInitSequenceNumber() already sending");
4594 return -1;
4595 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004596 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004597 {
4598 _engineStatisticsPtr->SetLastError(
4599 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4600 "SetInitSequenceNumber() failed to set sequence number");
4601 return -1;
4602 }
4603 return 0;
4604}
4605
4606int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004607Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004608{
4609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4610 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004611 *rtpRtcpModule = _rtpRtcpModule.get();
4612 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004613 return 0;
4614}
4615
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004616// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4617// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004618int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004619Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004620{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004621 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004622 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004623
4624 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004625 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004626
4627 if (_inputFilePlayerPtr == NULL)
4628 {
4629 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4630 VoEId(_instanceId, _channelId),
4631 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4632 " doesnt exist");
4633 return -1;
4634 }
4635
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004636 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004637 fileSamples,
4638 mixingFrequency) == -1)
4639 {
4640 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4641 VoEId(_instanceId, _channelId),
4642 "Channel::MixOrReplaceAudioWithFile() file mixing "
4643 "failed");
4644 return -1;
4645 }
4646 if (fileSamples == 0)
4647 {
4648 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4649 VoEId(_instanceId, _channelId),
4650 "Channel::MixOrReplaceAudioWithFile() file is ended");
4651 return 0;
4652 }
4653 }
4654
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004655 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004656
4657 if (_mixFileWithMicrophone)
4658 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004659 // Currently file stream is always mono.
4660 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004661 MixWithSat(_audioFrame.data_,
4662 _audioFrame.num_channels_,
4663 fileBuffer.get(),
4664 1,
4665 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004666 }
4667 else
4668 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004669 // Replace ACM audio with file.
4670 // Currently file stream is always mono.
4671 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004672 _audioFrame.UpdateFrame(_channelId,
4673 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004674 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004675 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004676 mixingFrequency,
4677 AudioFrame::kNormalSpeech,
4678 AudioFrame::kVadUnknown,
4679 1);
4680
4681 }
4682 return 0;
4683}
4684
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004685int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004686Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004687 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004688{
4689 assert(mixingFrequency <= 32000);
4690
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004691 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004692 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004693
4694 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004695 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004696
4697 if (_outputFilePlayerPtr == NULL)
4698 {
4699 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4700 VoEId(_instanceId, _channelId),
4701 "Channel::MixAudioWithFile() file mixing failed");
4702 return -1;
4703 }
4704
4705 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004706 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004707 fileSamples,
4708 mixingFrequency) == -1)
4709 {
4710 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4711 VoEId(_instanceId, _channelId),
4712 "Channel::MixAudioWithFile() file mixing failed");
4713 return -1;
4714 }
4715 }
4716
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004717 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004718 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004719 // Currently file stream is always mono.
4720 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004721 MixWithSat(audioFrame.data_,
4722 audioFrame.num_channels_,
4723 fileBuffer.get(),
4724 1,
4725 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004726 }
4727 else
4728 {
4729 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004730 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004731 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004732 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004733 return -1;
4734 }
4735
4736 return 0;
4737}
4738
4739int
4740Channel::InsertInbandDtmfTone()
4741{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004742 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004743 if (_inbandDtmfQueue.PendingDtmf() &&
4744 !_inbandDtmfGenerator.IsAddingTone() &&
4745 _inbandDtmfGenerator.DelaySinceLastTone() >
4746 kMinTelephoneEventSeparationMs)
4747 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004748 int8_t eventCode(0);
4749 uint16_t lengthMs(0);
4750 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004751
4752 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4753 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4754 if (_playInbandDtmfEvent)
4755 {
4756 // Add tone to output mixer using a reduced length to minimize
4757 // risk of echo.
4758 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4759 attenuationDb);
4760 }
4761 }
4762
4763 if (_inbandDtmfGenerator.IsAddingTone())
4764 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004765 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004766 _inbandDtmfGenerator.GetSampleRate(frequency);
4767
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004768 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004769 {
4770 // Update sample rate of Dtmf tone since the mixing frequency
4771 // has changed.
4772 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004773 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004774 // Reset the tone to be added taking the new sample rate into
4775 // account.
4776 _inbandDtmfGenerator.ResetTone();
4777 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004778
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004779 int16_t toneBuffer[320];
4780 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004781 // Get 10ms tone segment and set time since last tone to zero
4782 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4783 {
4784 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4785 VoEId(_instanceId, _channelId),
4786 "Channel::EncodeAndSend() inserting Dtmf failed");
4787 return -1;
4788 }
4789
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004790 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004791 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004792 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004793 sample++)
4794 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004795 for (int channel = 0;
4796 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004797 channel++)
4798 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004799 const int index = sample * _audioFrame.num_channels_ + channel;
4800 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004801 }
4802 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004803
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004804 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004805 } else
4806 {
4807 // Add 10ms to "delay-since-last-tone" counter
4808 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4809 }
4810 return 0;
4811}
4812
niklase@google.com470e71d2011-07-07 08:21:25 +00004813void
4814Channel::ResetDeadOrAliveCounters()
4815{
4816 _countDeadDetections = 0;
4817 _countAliveDetections = 0;
4818}
4819
4820void
4821Channel::UpdateDeadOrAliveCounters(bool alive)
4822{
4823 if (alive)
4824 _countAliveDetections++;
4825 else
4826 _countDeadDetections++;
4827}
4828
4829int
4830Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
4831{
niklase@google.com470e71d2011-07-07 08:21:25 +00004832 return 0;
4833}
4834
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004835int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004836Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4837{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004838 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004839 if (_transportPtr == NULL)
4840 {
4841 return -1;
4842 }
4843 if (!RTCP)
4844 {
4845 return _transportPtr->SendPacket(_channelId, data, len);
4846 }
4847 else
4848 {
4849 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4850 }
4851}
4852
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004853// Called for incoming RTP packets after successful RTP header parsing.
4854void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4855 uint16_t sequence_number) {
4856 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4857 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4858 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004859
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004860 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004861 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004862
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004863 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004864 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004865 return;
4866 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004867
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004868 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004869 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004870
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004871 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4872 // Even though the actual sampling rate for G.722 audio is
4873 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4874 // 8,000 Hz because that value was erroneously assigned in
4875 // RFC 1890 and must remain unchanged for backward compatibility.
4876 rtp_receive_frequency = 8000;
4877 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4878 // We are resampling Opus internally to 32,000 Hz until all our
4879 // DSP routines can operate at 48,000 Hz, but the RTP clock
4880 // rate for the Opus payload format is standardized to 48,000 Hz,
4881 // because that is the maximum supported decoding sampling rate.
4882 rtp_receive_frequency = 48000;
4883 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004884
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004885 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4886 // every incoming packet.
4887 uint32_t timestamp_diff_ms = (rtp_timestamp -
4888 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004889 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4890 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4891 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4892 // timestamp, the resulting difference is negative, but is set to zero.
4893 // This can happen when a network glitch causes a packet to arrive late,
4894 // and during long comfort noise periods with clock drift.
4895 timestamp_diff_ms = 0;
4896 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004897
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004898 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4899 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004900
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004901 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004902
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004903 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004904
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004905 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4906 _recPacketDelayMs = packet_delay_ms;
4907 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004908
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004909 if (_average_jitter_buffer_delay_us == 0) {
4910 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4911 return;
4912 }
4913
4914 // Filter average delay value using exponential filter (alpha is
4915 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4916 // risk of rounding error) and compensate for it in GetDelayEstimate()
4917 // later.
4918 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4919 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004920}
4921
4922void
4923Channel::RegisterReceiveCodecsToRTPModule()
4924{
4925 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4926 "Channel::RegisterReceiveCodecsToRTPModule()");
4927
4928
4929 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004930 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004931
4932 for (int idx = 0; idx < nSupportedCodecs; idx++)
4933 {
4934 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004935 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004936 (rtp_receiver_->RegisterReceivePayload(
4937 codec.plname,
4938 codec.pltype,
4939 codec.plfreq,
4940 codec.channels,
4941 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004942 {
4943 WEBRTC_TRACE(
4944 kTraceWarning,
4945 kTraceVoice,
4946 VoEId(_instanceId, _channelId),
4947 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4948 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4949 codec.plname, codec.pltype, codec.plfreq,
4950 codec.channels, codec.rate);
4951 }
4952 else
4953 {
4954 WEBRTC_TRACE(
4955 kTraceInfo,
4956 kTraceVoice,
4957 VoEId(_instanceId, _channelId),
4958 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004959 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004960 "receiver",
4961 codec.plname, codec.pltype, codec.plfreq,
4962 codec.channels, codec.rate);
4963 }
4964 }
4965}
4966
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004967int Channel::SetSecondarySendCodec(const CodecInst& codec,
4968 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004969 // Sanity check for payload type.
4970 if (red_payload_type < 0 || red_payload_type > 127) {
4971 _engineStatisticsPtr->SetLastError(
4972 VE_PLTYPE_ERROR, kTraceError,
4973 "SetRedPayloadType() invalid RED payload type");
4974 return -1;
4975 }
4976
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004977 if (SetRedPayloadType(red_payload_type) < 0) {
4978 _engineStatisticsPtr->SetLastError(
4979 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4980 "SetSecondarySendCodec() Failed to register RED ACM");
4981 return -1;
4982 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004983 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004984 _engineStatisticsPtr->SetLastError(
4985 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4986 "SetSecondarySendCodec() Failed to register secondary send codec in "
4987 "ACM");
4988 return -1;
4989 }
4990
4991 return 0;
4992}
4993
4994void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004995 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004996}
4997
4998int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004999 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005000 _engineStatisticsPtr->SetLastError(
5001 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5002 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5003 return -1;
5004 }
5005 return 0;
5006}
5007
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005008// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005009int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005010 CodecInst codec;
5011 bool found_red = false;
5012
5013 // Get default RED settings from the ACM database
5014 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5015 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005016 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005017 if (!STR_CASE_CMP(codec.plname, "RED")) {
5018 found_red = true;
5019 break;
5020 }
5021 }
5022
5023 if (!found_red) {
5024 _engineStatisticsPtr->SetLastError(
5025 VE_CODEC_ERROR, kTraceError,
5026 "SetRedPayloadType() RED is not supported");
5027 return -1;
5028 }
5029
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005030 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005031 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005032 _engineStatisticsPtr->SetLastError(
5033 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5034 "SetRedPayloadType() RED registration in ACM module failed");
5035 return -1;
5036 }
5037
5038 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5039 _engineStatisticsPtr->SetLastError(
5040 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5041 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5042 return -1;
5043 }
5044 return 0;
5045}
5046
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00005047int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
5048 unsigned char id) {
5049 int error = 0;
5050 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
5051 if (enable) {
5052 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
5053 }
5054 return error;
5055}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005056} // namespace voe
5057} // namespace webrtc