blob: 026b6b3cec9db36b589af9f554b089e8aa9a0b10 [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_(
840 new RTPPayloadRegistry(channelId,
841 RTPPayloadStrategy::CreateStrategy(true))),
842 rtp_receive_statistics_(ReceiveStatistics::Create(
843 Clock::GetRealTimeClock())),
844 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
845 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
846 this, this, rtp_payload_registry_.get())),
847 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000848 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000849 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 _rtpDumpIn(*RtpDump::CreateRtpDump()),
851 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000854 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 _inputFilePlayerPtr(NULL),
856 _outputFilePlayerPtr(NULL),
857 _outputFileRecorderPtr(NULL),
858 // Avoid conflict with other channels by adding 1024 - 1026,
859 // won't use as much as 1024 channels.
860 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
861 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
862 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000863 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000864 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
865 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000866 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000867 _inputExternalMediaCallbackPtr(NULL),
868 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000869 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
870 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000871 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000872 playout_timestamp_rtp_(0),
873 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000874 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000876 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000878 _outputMixerPtr(NULL),
879 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000880 _moduleProcessThreadPtr(NULL),
881 _audioDeviceModulePtr(NULL),
882 _voiceEngineObserverPtr(NULL),
883 _callbackCritSectPtr(NULL),
884 _transportPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000885 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000886 _rxVadObserverPtr(NULL),
887 _oldVadDecision(-1),
888 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000889 _rtpObserverPtr(NULL),
890 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000891 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000892 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000893 _inputIsOnHold(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000894 _mixFileWithMicrophone(false),
895 _rtpObserver(false),
896 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 _mute(false),
898 _panLeft(1.0f),
899 _panRight(1.0f),
900 _outputGain(1.0f),
901 _playOutbandDtmfEvent(false),
902 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000904 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000906 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000907 _rtpPacketTimedOut(false),
908 _rtpPacketTimeOutIsEnabled(false),
909 _rtpTimeOutSeconds(0),
910 _connectionObserver(false),
911 _connectionObserverPtr(NULL),
912 _countAliveDetections(0),
913 _countDeadDetections(0),
914 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000915 vie_network_(NULL),
916 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000917 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000918 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 _previousTimestamp(0),
920 _recPacketDelayMs(20),
921 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000923 _rxNsIsEnabled(false),
924 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000925{
926 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
927 "Channel::Channel() - ctor");
928 _inbandDtmfQueue.ResetDtmf();
929 _inbandDtmfGenerator.Init();
930 _outputAudioLevel.Clear();
931
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000932 RtpRtcp::Configuration configuration;
933 configuration.id = VoEModuleId(instanceId, channelId);
934 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000935 configuration.outgoing_transport = this;
936 configuration.rtcp_feedback = this;
937 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000938 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000939
940 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000941
942 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
943 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
944 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000945}
946
947Channel::~Channel()
948{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000949 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
951 "Channel::~Channel() - dtor");
952
953 if (_outputExternalMedia)
954 {
955 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
956 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000957 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 {
959 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
960 }
961 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 StopPlayout();
963
964 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000965 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 if (_inputFilePlayerPtr)
967 {
968 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
969 _inputFilePlayerPtr->StopPlayingFile();
970 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
971 _inputFilePlayerPtr = NULL;
972 }
973 if (_outputFilePlayerPtr)
974 {
975 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
976 _outputFilePlayerPtr->StopPlayingFile();
977 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
978 _outputFilePlayerPtr = NULL;
979 }
980 if (_outputFileRecorderPtr)
981 {
982 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
983 _outputFileRecorderPtr->StopRecording();
984 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
985 _outputFileRecorderPtr = NULL;
986 }
987 }
988
989 // The order to safely shutdown modules in a channel is:
990 // 1. De-register callbacks in modules
991 // 2. De-register modules in process thread
992 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000993 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000994 {
995 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
996 VoEId(_instanceId,_channelId),
997 "~Channel() failed to de-register transport callback"
998 " (Audio coding module)");
999 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001000 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001001 {
1002 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1003 VoEId(_instanceId,_channelId),
1004 "~Channel() failed to de-register VAD callback"
1005 " (Audio coding module)");
1006 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001008 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 {
1010 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1011 VoEId(_instanceId,_channelId),
1012 "~Channel() failed to deregister RTP/RTCP module");
1013 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001014 // End of modules shutdown
1015
1016 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001017 if (vie_network_) {
1018 vie_network_->Release();
1019 vie_network_ = NULL;
1020 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1022 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001023 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001024 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001025 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001026}
1027
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001028int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001029Channel::Init()
1030{
1031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1032 "Channel::Init()");
1033
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001034 channel_state_.Reset();
1035
niklase@google.com470e71d2011-07-07 08:21:25 +00001036 // --- Initial sanity
1037
1038 if ((_engineStatisticsPtr == NULL) ||
1039 (_moduleProcessThreadPtr == NULL))
1040 {
1041 WEBRTC_TRACE(kTraceError, kTraceVoice,
1042 VoEId(_instanceId,_channelId),
1043 "Channel::Init() must call SetEngineInformation() first");
1044 return -1;
1045 }
1046
1047 // --- Add modules to process thread (for periodic schedulation)
1048
1049 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001050 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 if (processThreadFail)
1053 {
1054 _engineStatisticsPtr->SetLastError(
1055 VE_CANNOT_INIT_CHANNEL, kTraceError,
1056 "Channel::Init() modules not registered");
1057 return -1;
1058 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001059 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001060
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001061 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001062#ifdef WEBRTC_CODEC_AVT
1063 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001064 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001065#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001066 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 {
1068 _engineStatisticsPtr->SetLastError(
1069 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1070 "Channel::Init() unable to initialize the ACM - 1");
1071 return -1;
1072 }
1073
1074 // --- RTP/RTCP module initialization
1075
1076 // Ensure that RTCP is enabled by default for the created channel.
1077 // Note that, the module will keep generating RTCP until it is explicitly
1078 // disabled by the user.
1079 // After StopListen (when no sockets exists), RTCP packets will no longer
1080 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001081 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1082 // RTCP is enabled by default.
1083 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 {
1085 _engineStatisticsPtr->SetLastError(
1086 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1087 "Channel::Init() RTP/RTCP module not initialized");
1088 return -1;
1089 }
1090
1091 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001093 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1094 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001095
1096 if (fail)
1097 {
1098 _engineStatisticsPtr->SetLastError(
1099 VE_CANNOT_INIT_CHANNEL, kTraceError,
1100 "Channel::Init() callbacks not registered");
1101 return -1;
1102 }
1103
1104 // --- Register all supported codecs to the receiving side of the
1105 // RTP/RTCP module
1106
1107 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001108 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001109
1110 for (int idx = 0; idx < nSupportedCodecs; idx++)
1111 {
1112 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001113 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001114 (rtp_receiver_->RegisterReceivePayload(
1115 codec.plname,
1116 codec.pltype,
1117 codec.plfreq,
1118 codec.channels,
1119 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 {
1121 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1122 VoEId(_instanceId,_channelId),
1123 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1124 "to RTP/RTCP receiver",
1125 codec.plname, codec.pltype, codec.plfreq,
1126 codec.channels, codec.rate);
1127 }
1128 else
1129 {
1130 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1131 VoEId(_instanceId,_channelId),
1132 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1133 "the RTP/RTCP receiver",
1134 codec.plname, codec.pltype, codec.plfreq,
1135 codec.channels, codec.rate);
1136 }
1137
1138 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001139 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 {
1141 SetSendCodec(codec);
1142 }
1143
1144 // Register default PT for outband 'telephone-event'
1145 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1146 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001147 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001148 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 {
1150 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1151 VoEId(_instanceId,_channelId),
1152 "Channel::Init() failed to register outband "
1153 "'telephone-event' (%d/%d) correctly",
1154 codec.pltype, codec.plfreq);
1155 }
1156 }
1157
1158 if (!STR_CASE_CMP(codec.plname, "CN"))
1159 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001160 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1161 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001162 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 {
1164 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1165 VoEId(_instanceId,_channelId),
1166 "Channel::Init() failed to register CN (%d/%d) "
1167 "correctly - 1",
1168 codec.pltype, codec.plfreq);
1169 }
1170 }
1171#ifdef WEBRTC_CODEC_RED
1172 // Register RED to the receiving side of the ACM.
1173 // We will not receive an OnInitializeDecoder() callback for RED.
1174 if (!STR_CASE_CMP(codec.plname, "RED"))
1175 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001176 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001177 {
1178 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1179 VoEId(_instanceId,_channelId),
1180 "Channel::Init() failed to register RED (%d/%d) "
1181 "correctly",
1182 codec.pltype, codec.plfreq);
1183 }
1184 }
1185#endif
1186 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001187
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001188 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1189 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1190 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001192 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1193 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1194 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 }
1196
1197 return 0;
1198}
1199
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001200int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001201Channel::SetEngineInformation(Statistics& engineStatistics,
1202 OutputMixer& outputMixer,
1203 voe::TransmitMixer& transmitMixer,
1204 ProcessThread& moduleProcessThread,
1205 AudioDeviceModule& audioDeviceModule,
1206 VoiceEngineObserver* voiceEngineObserver,
1207 CriticalSectionWrapper* callbackCritSect)
1208{
1209 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1210 "Channel::SetEngineInformation()");
1211 _engineStatisticsPtr = &engineStatistics;
1212 _outputMixerPtr = &outputMixer;
1213 _transmitMixerPtr = &transmitMixer,
1214 _moduleProcessThreadPtr = &moduleProcessThread;
1215 _audioDeviceModulePtr = &audioDeviceModule;
1216 _voiceEngineObserverPtr = voiceEngineObserver;
1217 _callbackCritSectPtr = callbackCritSect;
1218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::UpdateLocalTimeStamp()
1223{
1224
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001225 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 return 0;
1227}
1228
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001229int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001230Channel::StartPlayout()
1231{
1232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1233 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001234 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 {
1236 return 0;
1237 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001238
1239 if (!_externalMixing) {
1240 // Add participant as candidates for mixing.
1241 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1242 {
1243 _engineStatisticsPtr->SetLastError(
1244 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1245 "StartPlayout() failed to add participant to mixer");
1246 return -1;
1247 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001248 }
1249
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001250 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001251 if (RegisterFilePlayingToMixer() != 0)
1252 return -1;
1253
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 return 0;
1255}
1256
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001257int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001258Channel::StopPlayout()
1259{
1260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1261 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001262 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001263 {
1264 return 0;
1265 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001266
1267 if (!_externalMixing) {
1268 // Remove participant as candidates for mixing
1269 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1270 {
1271 _engineStatisticsPtr->SetLastError(
1272 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1273 "StopPlayout() failed to remove participant from mixer");
1274 return -1;
1275 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 }
1277
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001278 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001279 _outputAudioLevel.Clear();
1280
1281 return 0;
1282}
1283
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001284int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001285Channel::StartSend()
1286{
1287 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1288 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001289 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001290 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001291 if (send_sequence_number_)
1292 SetInitSequenceNumber(send_sequence_number_);
1293
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001294 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001296 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001297 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001298 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001299
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001300 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 {
1302 _engineStatisticsPtr->SetLastError(
1303 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1304 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001305 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001306 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001307 return -1;
1308 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001309
niklase@google.com470e71d2011-07-07 08:21:25 +00001310 return 0;
1311}
1312
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001313int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001314Channel::StopSend()
1315{
1316 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1317 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001318 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001320 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001321 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001322 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001323
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001324 // Store the sequence number to be able to pick up the same sequence for
1325 // the next StartSend(). This is needed for restarting device, otherwise
1326 // it might cause libSRTP to complain about packets being replayed.
1327 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1328 // CL is landed. See issue
1329 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1330 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1331
niklase@google.com470e71d2011-07-07 08:21:25 +00001332 // Reset sending SSRC and sequence number and triggers direct transmission
1333 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001334 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1335 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001336 {
1337 _engineStatisticsPtr->SetLastError(
1338 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1339 "StartSend() RTP/RTCP failed to stop sending");
1340 }
1341
niklase@google.com470e71d2011-07-07 08:21:25 +00001342 return 0;
1343}
1344
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001345int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001346Channel::StartReceiving()
1347{
1348 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1349 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001350 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001351 {
1352 return 0;
1353 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001354 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 _numberOfDiscardedPackets = 0;
1356 return 0;
1357}
1358
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001359int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001360Channel::StopReceiving()
1361{
1362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1363 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001364 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001365 {
1366 return 0;
1367 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001368
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001369 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001370 return 0;
1371}
1372
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001373int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001374Channel::SetNetEQPlayoutMode(NetEqModes mode)
1375{
1376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1377 "Channel::SetNetEQPlayoutMode()");
1378 AudioPlayoutMode playoutMode(voice);
1379 switch (mode)
1380 {
1381 case kNetEqDefault:
1382 playoutMode = voice;
1383 break;
1384 case kNetEqStreaming:
1385 playoutMode = streaming;
1386 break;
1387 case kNetEqFax:
1388 playoutMode = fax;
1389 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001390 case kNetEqOff:
1391 playoutMode = off;
1392 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001393 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001394 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001395 {
1396 _engineStatisticsPtr->SetLastError(
1397 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1398 "SetNetEQPlayoutMode() failed to set playout mode");
1399 return -1;
1400 }
1401 return 0;
1402}
1403
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001404int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001405Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1406{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001407 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001408 switch (playoutMode)
1409 {
1410 case voice:
1411 mode = kNetEqDefault;
1412 break;
1413 case streaming:
1414 mode = kNetEqStreaming;
1415 break;
1416 case fax:
1417 mode = kNetEqFax;
1418 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001419 case off:
1420 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001421 }
1422 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1423 VoEId(_instanceId,_channelId),
1424 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1425 return 0;
1426}
1427
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001428int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001429Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1430{
1431 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1432 "Channel::SetOnHoldStatus()");
1433 if (mode == kHoldSendAndPlay)
1434 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001435 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001436 _inputIsOnHold = enable;
1437 }
1438 else if (mode == kHoldPlayOnly)
1439 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001440 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001441 }
1442 if (mode == kHoldSendOnly)
1443 {
1444 _inputIsOnHold = enable;
1445 }
1446 return 0;
1447}
1448
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001449int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001450Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1451{
1452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1453 "Channel::GetOnHoldStatus()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001454 bool output_is_on_hold = channel_state_.Get().output_is_on_hold;
1455 enabled = (output_is_on_hold || _inputIsOnHold);
1456 if (output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001457 {
1458 mode = kHoldSendAndPlay;
1459 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001460 else if (output_is_on_hold && !_inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001461 {
1462 mode = kHoldPlayOnly;
1463 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001464 else if (!output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 {
1466 mode = kHoldSendOnly;
1467 }
1468 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1469 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1470 enabled, mode);
1471 return 0;
1472}
1473
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001474int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001475Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1476{
1477 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1478 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001479 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001480
1481 if (_voiceEngineObserverPtr)
1482 {
1483 _engineStatisticsPtr->SetLastError(
1484 VE_INVALID_OPERATION, kTraceError,
1485 "RegisterVoiceEngineObserver() observer already enabled");
1486 return -1;
1487 }
1488 _voiceEngineObserverPtr = &observer;
1489 return 0;
1490}
1491
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001492int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001493Channel::DeRegisterVoiceEngineObserver()
1494{
1495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1496 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001497 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001498
1499 if (!_voiceEngineObserverPtr)
1500 {
1501 _engineStatisticsPtr->SetLastError(
1502 VE_INVALID_OPERATION, kTraceWarning,
1503 "DeRegisterVoiceEngineObserver() observer already disabled");
1504 return 0;
1505 }
1506 _voiceEngineObserverPtr = NULL;
1507 return 0;
1508}
1509
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001510int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001511Channel::GetSendCodec(CodecInst& codec)
1512{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001513 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001514}
1515
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001516int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001517Channel::GetRecCodec(CodecInst& codec)
1518{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001519 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001520}
1521
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001522int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001523Channel::SetSendCodec(const CodecInst& codec)
1524{
1525 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "Channel::SetSendCodec()");
1527
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001528 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001529 {
1530 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1531 "SetSendCodec() failed to register codec to ACM");
1532 return -1;
1533 }
1534
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001535 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001536 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001537 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1538 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001539 {
1540 WEBRTC_TRACE(
1541 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1542 "SetSendCodec() failed to register codec to"
1543 " RTP/RTCP module");
1544 return -1;
1545 }
1546 }
1547
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001548 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001549 {
1550 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1551 "SetSendCodec() failed to set audio packet size");
1552 return -1;
1553 }
1554
1555 return 0;
1556}
1557
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001558int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001559Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1560{
1561 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1562 "Channel::SetVADStatus(mode=%d)", mode);
1563 // To disable VAD, DTX must be disabled too
1564 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001565 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 {
1567 _engineStatisticsPtr->SetLastError(
1568 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1569 "SetVADStatus() failed to set VAD");
1570 return -1;
1571 }
1572 return 0;
1573}
1574
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001575int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001576Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1577{
1578 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1579 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001580 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001581 {
1582 _engineStatisticsPtr->SetLastError(
1583 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1584 "GetVADStatus() failed to get VAD status");
1585 return -1;
1586 }
1587 disabledDTX = !disabledDTX;
1588 return 0;
1589}
1590
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001591int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001592Channel::SetRecPayloadType(const CodecInst& codec)
1593{
1594 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1595 "Channel::SetRecPayloadType()");
1596
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001597 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001598 {
1599 _engineStatisticsPtr->SetLastError(
1600 VE_ALREADY_PLAYING, kTraceError,
1601 "SetRecPayloadType() unable to set PT while playing");
1602 return -1;
1603 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001604 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001605 {
1606 _engineStatisticsPtr->SetLastError(
1607 VE_ALREADY_LISTENING, kTraceError,
1608 "SetRecPayloadType() unable to set PT while listening");
1609 return -1;
1610 }
1611
1612 if (codec.pltype == -1)
1613 {
1614 // De-register the selected codec (RTP/RTCP module and ACM)
1615
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001616 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001617 CodecInst rxCodec = codec;
1618
1619 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001620 rtp_payload_registry_->ReceivePayloadType(
1621 rxCodec.plname,
1622 rxCodec.plfreq,
1623 rxCodec.channels,
1624 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1625 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001626 rxCodec.pltype = pltype;
1627
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001628 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001629 {
1630 _engineStatisticsPtr->SetLastError(
1631 VE_RTP_RTCP_MODULE_ERROR,
1632 kTraceError,
1633 "SetRecPayloadType() RTP/RTCP-module deregistration "
1634 "failed");
1635 return -1;
1636 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001637 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001638 {
1639 _engineStatisticsPtr->SetLastError(
1640 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1641 "SetRecPayloadType() ACM deregistration failed - 1");
1642 return -1;
1643 }
1644 return 0;
1645 }
1646
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001647 if (rtp_receiver_->RegisterReceivePayload(
1648 codec.plname,
1649 codec.pltype,
1650 codec.plfreq,
1651 codec.channels,
1652 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001653 {
1654 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001655 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1656 if (rtp_receiver_->RegisterReceivePayload(
1657 codec.plname,
1658 codec.pltype,
1659 codec.plfreq,
1660 codec.channels,
1661 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001662 {
1663 _engineStatisticsPtr->SetLastError(
1664 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1665 "SetRecPayloadType() RTP/RTCP-module registration failed");
1666 return -1;
1667 }
1668 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001669 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001671 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1672 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001673 {
1674 _engineStatisticsPtr->SetLastError(
1675 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1676 "SetRecPayloadType() ACM registration failed - 1");
1677 return -1;
1678 }
1679 }
1680 return 0;
1681}
1682
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001683int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001684Channel::GetRecPayloadType(CodecInst& codec)
1685{
1686 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1687 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001688 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001689 if (rtp_payload_registry_->ReceivePayloadType(
1690 codec.plname,
1691 codec.plfreq,
1692 codec.channels,
1693 (codec.rate < 0) ? 0 : codec.rate,
1694 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001695 {
1696 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001697 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001698 "GetRecPayloadType() failed to retrieve RX payload type");
1699 return -1;
1700 }
1701 codec.pltype = payloadType;
1702 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1703 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1704 return 0;
1705}
1706
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001707int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001708Channel::SetAMREncFormat(AmrMode mode)
1709{
1710 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1711 "Channel::SetAMREncFormat()");
1712
1713 // ACM doesn't support AMR
1714 return -1;
1715}
1716
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001717int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001718Channel::SetAMRDecFormat(AmrMode mode)
1719{
1720 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1721 "Channel::SetAMRDecFormat()");
1722
1723 // ACM doesn't support AMR
1724 return -1;
1725}
1726
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001727int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001728Channel::SetAMRWbEncFormat(AmrMode mode)
1729{
1730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1731 "Channel::SetAMRWbEncFormat()");
1732
1733 // ACM doesn't support AMR
1734 return -1;
1735
1736}
1737
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001738int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001739Channel::SetAMRWbDecFormat(AmrMode mode)
1740{
1741 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1742 "Channel::SetAMRWbDecFormat()");
1743
1744 // ACM doesn't support AMR
1745 return -1;
1746}
1747
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001748int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001749Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1750{
1751 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1752 "Channel::SetSendCNPayloadType()");
1753
1754 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001755 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001756 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001757 if (frequency == kFreq32000Hz)
1758 samplingFreqHz = 32000;
1759 else if (frequency == kFreq16000Hz)
1760 samplingFreqHz = 16000;
1761
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001762 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 {
1764 _engineStatisticsPtr->SetLastError(
1765 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1766 "SetSendCNPayloadType() failed to retrieve default CN codec "
1767 "settings");
1768 return -1;
1769 }
1770
1771 // Modify the payload type (must be set to dynamic range)
1772 codec.pltype = type;
1773
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001774 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001775 {
1776 _engineStatisticsPtr->SetLastError(
1777 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1778 "SetSendCNPayloadType() failed to register CN to ACM");
1779 return -1;
1780 }
1781
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001782 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001783 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001784 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1785 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001786 {
1787 _engineStatisticsPtr->SetLastError(
1788 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1789 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1790 "module");
1791 return -1;
1792 }
1793 }
1794 return 0;
1795}
1796
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001797int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001798Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1799{
1800 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1801 "Channel::SetISACInitTargetRate()");
1802
1803 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001804 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001805 {
1806 _engineStatisticsPtr->SetLastError(
1807 VE_CODEC_ERROR, kTraceError,
1808 "SetISACInitTargetRate() failed to retrieve send codec");
1809 return -1;
1810 }
1811 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1812 {
1813 // This API is only valid if iSAC is setup to run in channel-adaptive
1814 // mode.
1815 // We do not validate the adaptive mode here. It is done later in the
1816 // ConfigISACBandwidthEstimator() API.
1817 _engineStatisticsPtr->SetLastError(
1818 VE_CODEC_ERROR, kTraceError,
1819 "SetISACInitTargetRate() send codec is not iSAC");
1820 return -1;
1821 }
1822
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001823 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001824 if (16000 == sendCodec.plfreq)
1825 {
1826 // Note that 0 is a valid and corresponds to "use default
1827 if ((rateBps != 0 &&
1828 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1829 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1830 {
1831 _engineStatisticsPtr->SetLastError(
1832 VE_INVALID_ARGUMENT, kTraceError,
1833 "SetISACInitTargetRate() invalid target rate - 1");
1834 return -1;
1835 }
1836 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001837 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001838 }
1839 else if (32000 == sendCodec.plfreq)
1840 {
1841 if ((rateBps != 0 &&
1842 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1843 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1844 {
1845 _engineStatisticsPtr->SetLastError(
1846 VE_INVALID_ARGUMENT, kTraceError,
1847 "SetISACInitTargetRate() invalid target rate - 2");
1848 return -1;
1849 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001850 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001851 }
1852
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001853 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001854 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1855 {
1856 _engineStatisticsPtr->SetLastError(
1857 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1858 "SetISACInitTargetRate() iSAC BWE config failed");
1859 return -1;
1860 }
1861
1862 return 0;
1863}
1864
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001865int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001866Channel::SetISACMaxRate(int rateBps)
1867{
1868 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1869 "Channel::SetISACMaxRate()");
1870
1871 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001872 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_CODEC_ERROR, kTraceError,
1876 "SetISACMaxRate() failed to retrieve send codec");
1877 return -1;
1878 }
1879 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1880 {
1881 // This API is only valid if iSAC is selected as sending codec.
1882 _engineStatisticsPtr->SetLastError(
1883 VE_CODEC_ERROR, kTraceError,
1884 "SetISACMaxRate() send codec is not iSAC");
1885 return -1;
1886 }
1887 if (16000 == sendCodec.plfreq)
1888 {
1889 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1890 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1891 {
1892 _engineStatisticsPtr->SetLastError(
1893 VE_INVALID_ARGUMENT, kTraceError,
1894 "SetISACMaxRate() invalid max rate - 1");
1895 return -1;
1896 }
1897 }
1898 else if (32000 == sendCodec.plfreq)
1899 {
1900 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1901 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1902 {
1903 _engineStatisticsPtr->SetLastError(
1904 VE_INVALID_ARGUMENT, kTraceError,
1905 "SetISACMaxRate() invalid max rate - 2");
1906 return -1;
1907 }
1908 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001909 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001910 {
1911 _engineStatisticsPtr->SetLastError(
1912 VE_SENDING, kTraceError,
1913 "SetISACMaxRate() unable to set max rate while sending");
1914 return -1;
1915 }
1916
1917 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1918 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001919 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001920 {
1921 _engineStatisticsPtr->SetLastError(
1922 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1923 "SetISACMaxRate() failed to set max rate");
1924 return -1;
1925 }
1926
1927 return 0;
1928}
1929
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001930int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001931Channel::SetISACMaxPayloadSize(int sizeBytes)
1932{
1933 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1934 "Channel::SetISACMaxPayloadSize()");
1935 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001936 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001937 {
1938 _engineStatisticsPtr->SetLastError(
1939 VE_CODEC_ERROR, kTraceError,
1940 "SetISACMaxPayloadSize() failed to retrieve send codec");
1941 return -1;
1942 }
1943 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1944 {
1945 _engineStatisticsPtr->SetLastError(
1946 VE_CODEC_ERROR, kTraceError,
1947 "SetISACMaxPayloadSize() send codec is not iSAC");
1948 return -1;
1949 }
1950 if (16000 == sendCodec.plfreq)
1951 {
1952 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1953 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1954 {
1955 _engineStatisticsPtr->SetLastError(
1956 VE_INVALID_ARGUMENT, kTraceError,
1957 "SetISACMaxPayloadSize() invalid max payload - 1");
1958 return -1;
1959 }
1960 }
1961 else if (32000 == sendCodec.plfreq)
1962 {
1963 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1964 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1965 {
1966 _engineStatisticsPtr->SetLastError(
1967 VE_INVALID_ARGUMENT, kTraceError,
1968 "SetISACMaxPayloadSize() invalid max payload - 2");
1969 return -1;
1970 }
1971 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001972 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 {
1974 _engineStatisticsPtr->SetLastError(
1975 VE_SENDING, kTraceError,
1976 "SetISACMaxPayloadSize() unable to set max rate while sending");
1977 return -1;
1978 }
1979
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001980 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001981 {
1982 _engineStatisticsPtr->SetLastError(
1983 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1984 "SetISACMaxPayloadSize() failed to set max payload size");
1985 return -1;
1986 }
1987 return 0;
1988}
1989
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001990int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001991{
1992 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1993 "Channel::RegisterExternalTransport()");
1994
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001995 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001996
niklase@google.com470e71d2011-07-07 08:21:25 +00001997 if (_externalTransport)
1998 {
1999 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2000 kTraceError,
2001 "RegisterExternalTransport() external transport already enabled");
2002 return -1;
2003 }
2004 _externalTransport = true;
2005 _transportPtr = &transport;
2006 return 0;
2007}
2008
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002009int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002010Channel::DeRegisterExternalTransport()
2011{
2012 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2013 "Channel::DeRegisterExternalTransport()");
2014
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002015 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002016
niklase@google.com470e71d2011-07-07 08:21:25 +00002017 if (!_transportPtr)
2018 {
2019 _engineStatisticsPtr->SetLastError(
2020 VE_INVALID_OPERATION, kTraceWarning,
2021 "DeRegisterExternalTransport() external transport already "
2022 "disabled");
2023 return 0;
2024 }
2025 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002026 _transportPtr = NULL;
2027 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2028 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002029 return 0;
2030}
2031
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002032int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
2033 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002034 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2035 "Channel::ReceivedRTPPacket()");
2036
2037 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002038 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002039
2040 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002041 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2042 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002043 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2044 VoEId(_instanceId,_channelId),
2045 "Channel::SendPacket() RTP dump to input file failed");
2046 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002047 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002048 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002049 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2050 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2051 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002052 return -1;
2053 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002054 header.payload_type_frequency =
2055 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002056 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002057 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002058 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002059 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002060 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002061 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002062
2063 // Forward any packets to ViE bandwidth estimator, if enabled.
2064 {
2065 CriticalSectionScoped cs(&_callbackCritSect);
2066 if (vie_network_) {
2067 int64_t arrival_time_ms;
2068 if (packet_time.timestamp != -1) {
2069 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
2070 } else {
2071 arrival_time_ms = TickTime::MillisecondTimestamp();
2072 }
2073 int payload_length = length - header.headerLength;
2074 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
2075 payload_length, header);
2076 }
2077 }
2078
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002079 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002080}
2081
2082bool Channel::ReceivePacket(const uint8_t* packet,
2083 int packet_length,
2084 const RTPHeader& header,
2085 bool in_order) {
2086 if (rtp_payload_registry_->IsEncapsulated(header)) {
2087 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002088 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002089 const uint8_t* payload = packet + header.headerLength;
2090 int payload_length = packet_length - header.headerLength;
2091 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002092 PayloadUnion payload_specific;
2093 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002094 &payload_specific)) {
2095 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002096 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002097 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2098 payload_specific, in_order);
2099}
2100
2101bool Channel::HandleEncapsulation(const uint8_t* packet,
2102 int packet_length,
2103 const RTPHeader& header) {
2104 if (!rtp_payload_registry_->IsRtx(header))
2105 return false;
2106
2107 // Remove the RTX header and parse the original RTP header.
2108 if (packet_length < header.headerLength)
2109 return false;
2110 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2111 return false;
2112 if (restored_packet_in_use_) {
2113 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2114 "Multiple RTX headers detected, dropping packet");
2115 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002116 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002117 uint8_t* restored_packet_ptr = restored_packet_;
2118 if (!rtp_payload_registry_->RestoreOriginalPacket(
2119 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2120 header)) {
2121 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2122 "Incoming RTX packet: invalid RTP header");
2123 return false;
2124 }
2125 restored_packet_in_use_ = true;
2126 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2127 restored_packet_in_use_ = false;
2128 return ret;
2129}
2130
2131bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2132 StreamStatistician* statistician =
2133 rtp_receive_statistics_->GetStatistician(header.ssrc);
2134 if (!statistician)
2135 return false;
2136 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002137}
2138
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002139bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2140 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002141 // Retransmissions are handled separately if RTX is enabled.
2142 if (rtp_payload_registry_->RtxEnabled())
2143 return false;
2144 StreamStatistician* statistician =
2145 rtp_receive_statistics_->GetStatistician(header.ssrc);
2146 if (!statistician)
2147 return false;
2148 // Check if this is a retransmission.
2149 uint16_t min_rtt = 0;
2150 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002151 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002152 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002153}
2154
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002155int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002156 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2157 "Channel::ReceivedRTCPPacket()");
2158 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002159 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002160
2161 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002162 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2163 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002164 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2165 VoEId(_instanceId,_channelId),
2166 "Channel::SendPacket() RTCP dump to input file failed");
2167 }
2168
2169 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002170 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2171 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002172 _engineStatisticsPtr->SetLastError(
2173 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2174 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2175 }
2176 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002177}
2178
niklase@google.com470e71d2011-07-07 08:21:25 +00002179int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002180 bool loop,
2181 FileFormats format,
2182 int startPosition,
2183 float volumeScaling,
2184 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002185 const CodecInst* codecInst)
2186{
2187 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2188 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2189 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2190 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2191 startPosition, stopPosition);
2192
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002193 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002194 {
2195 _engineStatisticsPtr->SetLastError(
2196 VE_ALREADY_PLAYING, kTraceError,
2197 "StartPlayingFileLocally() is already playing");
2198 return -1;
2199 }
2200
niklase@google.com470e71d2011-07-07 08:21:25 +00002201 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002202 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002203
2204 if (_outputFilePlayerPtr)
2205 {
2206 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2207 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2208 _outputFilePlayerPtr = NULL;
2209 }
2210
2211 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2212 _outputFilePlayerId, (const FileFormats)format);
2213
2214 if (_outputFilePlayerPtr == NULL)
2215 {
2216 _engineStatisticsPtr->SetLastError(
2217 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002218 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002219 return -1;
2220 }
2221
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002222 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002223
2224 if (_outputFilePlayerPtr->StartPlayingFile(
2225 fileName,
2226 loop,
2227 startPosition,
2228 volumeScaling,
2229 notificationTime,
2230 stopPosition,
2231 (const CodecInst*)codecInst) != 0)
2232 {
2233 _engineStatisticsPtr->SetLastError(
2234 VE_BAD_FILE, kTraceError,
2235 "StartPlayingFile() failed to start file playout");
2236 _outputFilePlayerPtr->StopPlayingFile();
2237 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2238 _outputFilePlayerPtr = NULL;
2239 return -1;
2240 }
2241 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002242 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002243 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002244
2245 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002246 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002247
2248 return 0;
2249}
2250
2251int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002252 FileFormats format,
2253 int startPosition,
2254 float volumeScaling,
2255 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002256 const CodecInst* codecInst)
2257{
2258 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2259 "Channel::StartPlayingFileLocally(format=%d,"
2260 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2261 format, volumeScaling, startPosition, stopPosition);
2262
2263 if(stream == NULL)
2264 {
2265 _engineStatisticsPtr->SetLastError(
2266 VE_BAD_FILE, kTraceError,
2267 "StartPlayingFileLocally() NULL as input stream");
2268 return -1;
2269 }
2270
2271
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002272 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002273 {
2274 _engineStatisticsPtr->SetLastError(
2275 VE_ALREADY_PLAYING, kTraceError,
2276 "StartPlayingFileLocally() is already playing");
2277 return -1;
2278 }
2279
niklase@google.com470e71d2011-07-07 08:21:25 +00002280 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002281 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002282
2283 // Destroy the old instance
2284 if (_outputFilePlayerPtr)
2285 {
2286 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2287 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2288 _outputFilePlayerPtr = NULL;
2289 }
2290
2291 // Create the instance
2292 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2293 _outputFilePlayerId,
2294 (const FileFormats)format);
2295
2296 if (_outputFilePlayerPtr == NULL)
2297 {
2298 _engineStatisticsPtr->SetLastError(
2299 VE_INVALID_ARGUMENT, kTraceError,
2300 "StartPlayingFileLocally() filePlayer format isnot correct");
2301 return -1;
2302 }
2303
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002304 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002305
2306 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2307 volumeScaling,
2308 notificationTime,
2309 stopPosition, codecInst) != 0)
2310 {
2311 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2312 "StartPlayingFile() failed to "
2313 "start file playout");
2314 _outputFilePlayerPtr->StopPlayingFile();
2315 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2316 _outputFilePlayerPtr = NULL;
2317 return -1;
2318 }
2319 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002320 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002321 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002322
2323 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002324 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002325
niklase@google.com470e71d2011-07-07 08:21:25 +00002326 return 0;
2327}
2328
2329int Channel::StopPlayingFileLocally()
2330{
2331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2332 "Channel::StopPlayingFileLocally()");
2333
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002334 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002335 {
2336 _engineStatisticsPtr->SetLastError(
2337 VE_INVALID_OPERATION, kTraceWarning,
2338 "StopPlayingFileLocally() isnot playing");
2339 return 0;
2340 }
2341
niklase@google.com470e71d2011-07-07 08:21:25 +00002342 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002343 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002344
2345 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2346 {
2347 _engineStatisticsPtr->SetLastError(
2348 VE_STOP_RECORDING_FAILED, kTraceError,
2349 "StopPlayingFile() could not stop playing");
2350 return -1;
2351 }
2352 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2353 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2354 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002355 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002356 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002357 // _fileCritSect cannot be taken while calling
2358 // SetAnonymousMixibilityStatus. Refer to comments in
2359 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002360 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2361 {
2362 _engineStatisticsPtr->SetLastError(
2363 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002364 "StopPlayingFile() failed to stop participant from playing as"
2365 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002366 return -1;
2367 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002368
2369 return 0;
2370}
2371
2372int Channel::IsPlayingFileLocally() const
2373{
2374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2375 "Channel::IsPlayingFileLocally()");
2376
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002377 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002378}
2379
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002380int Channel::RegisterFilePlayingToMixer()
2381{
2382 // Return success for not registering for file playing to mixer if:
2383 // 1. playing file before playout is started on that channel.
2384 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002385 if (!channel_state_.Get().playing ||
2386 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002387 {
2388 return 0;
2389 }
2390
2391 // |_fileCritSect| cannot be taken while calling
2392 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2393 // frames can be pulled by the mixer. Since the frames are generated from
2394 // the file, _fileCritSect will be taken. This would result in a deadlock.
2395 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2396 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002397 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002398 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002399 _engineStatisticsPtr->SetLastError(
2400 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2401 "StartPlayingFile() failed to add participant as file to mixer");
2402 _outputFilePlayerPtr->StopPlayingFile();
2403 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2404 _outputFilePlayerPtr = NULL;
2405 return -1;
2406 }
2407
2408 return 0;
2409}
2410
pbos@webrtc.org92135212013-05-14 08:31:39 +00002411int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002412{
2413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2414 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2415
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002416 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002417
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002418 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002419 {
2420 _engineStatisticsPtr->SetLastError(
2421 VE_INVALID_OPERATION, kTraceError,
2422 "ScaleLocalFilePlayout() isnot playing");
2423 return -1;
2424 }
2425 if ((_outputFilePlayerPtr == NULL) ||
2426 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2427 {
2428 _engineStatisticsPtr->SetLastError(
2429 VE_BAD_ARGUMENT, kTraceError,
2430 "SetAudioScaling() failed to scale the playout");
2431 return -1;
2432 }
2433
2434 return 0;
2435}
2436
2437int Channel::GetLocalPlayoutPosition(int& positionMs)
2438{
2439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2440 "Channel::GetLocalPlayoutPosition(position=?)");
2441
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002442 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002443
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002444 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002445
2446 if (_outputFilePlayerPtr == NULL)
2447 {
2448 _engineStatisticsPtr->SetLastError(
2449 VE_INVALID_OPERATION, kTraceError,
2450 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2451 return -1;
2452 }
2453
2454 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2455 {
2456 _engineStatisticsPtr->SetLastError(
2457 VE_BAD_FILE, kTraceError,
2458 "GetLocalPlayoutPosition() failed");
2459 return -1;
2460 }
2461 positionMs = position;
2462
2463 return 0;
2464}
2465
2466int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002467 bool loop,
2468 FileFormats format,
2469 int startPosition,
2470 float volumeScaling,
2471 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002472 const CodecInst* codecInst)
2473{
2474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2475 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2476 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2477 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2478 startPosition, stopPosition);
2479
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002480 CriticalSectionScoped cs(&_fileCritSect);
2481
2482 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002483 {
2484 _engineStatisticsPtr->SetLastError(
2485 VE_ALREADY_PLAYING, kTraceWarning,
2486 "StartPlayingFileAsMicrophone() filePlayer is playing");
2487 return 0;
2488 }
2489
niklase@google.com470e71d2011-07-07 08:21:25 +00002490 // Destroy the old instance
2491 if (_inputFilePlayerPtr)
2492 {
2493 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2494 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2495 _inputFilePlayerPtr = NULL;
2496 }
2497
2498 // Create the instance
2499 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2500 _inputFilePlayerId, (const FileFormats)format);
2501
2502 if (_inputFilePlayerPtr == NULL)
2503 {
2504 _engineStatisticsPtr->SetLastError(
2505 VE_INVALID_ARGUMENT, kTraceError,
2506 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2507 return -1;
2508 }
2509
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002510 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002511
2512 if (_inputFilePlayerPtr->StartPlayingFile(
2513 fileName,
2514 loop,
2515 startPosition,
2516 volumeScaling,
2517 notificationTime,
2518 stopPosition,
2519 (const CodecInst*)codecInst) != 0)
2520 {
2521 _engineStatisticsPtr->SetLastError(
2522 VE_BAD_FILE, kTraceError,
2523 "StartPlayingFile() failed to start file playout");
2524 _inputFilePlayerPtr->StopPlayingFile();
2525 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2526 _inputFilePlayerPtr = NULL;
2527 return -1;
2528 }
2529 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002530 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002531
2532 return 0;
2533}
2534
2535int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002536 FileFormats format,
2537 int startPosition,
2538 float volumeScaling,
2539 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002540 const CodecInst* codecInst)
2541{
2542 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2543 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2544 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2545 format, volumeScaling, startPosition, stopPosition);
2546
2547 if(stream == NULL)
2548 {
2549 _engineStatisticsPtr->SetLastError(
2550 VE_BAD_FILE, kTraceError,
2551 "StartPlayingFileAsMicrophone NULL as input stream");
2552 return -1;
2553 }
2554
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002555 CriticalSectionScoped cs(&_fileCritSect);
2556
2557 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002558 {
2559 _engineStatisticsPtr->SetLastError(
2560 VE_ALREADY_PLAYING, kTraceWarning,
2561 "StartPlayingFileAsMicrophone() is playing");
2562 return 0;
2563 }
2564
niklase@google.com470e71d2011-07-07 08:21:25 +00002565 // Destroy the old instance
2566 if (_inputFilePlayerPtr)
2567 {
2568 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2569 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2570 _inputFilePlayerPtr = NULL;
2571 }
2572
2573 // Create the instance
2574 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2575 _inputFilePlayerId, (const FileFormats)format);
2576
2577 if (_inputFilePlayerPtr == NULL)
2578 {
2579 _engineStatisticsPtr->SetLastError(
2580 VE_INVALID_ARGUMENT, kTraceError,
2581 "StartPlayingInputFile() filePlayer format isnot correct");
2582 return -1;
2583 }
2584
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002585 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002586
2587 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2588 volumeScaling, notificationTime,
2589 stopPosition, codecInst) != 0)
2590 {
2591 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2592 "StartPlayingFile() failed to start "
2593 "file playout");
2594 _inputFilePlayerPtr->StopPlayingFile();
2595 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2596 _inputFilePlayerPtr = NULL;
2597 return -1;
2598 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002599
niklase@google.com470e71d2011-07-07 08:21:25 +00002600 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002601 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002602
2603 return 0;
2604}
2605
2606int Channel::StopPlayingFileAsMicrophone()
2607{
2608 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2609 "Channel::StopPlayingFileAsMicrophone()");
2610
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002611 CriticalSectionScoped cs(&_fileCritSect);
2612
2613 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002614 {
2615 _engineStatisticsPtr->SetLastError(
2616 VE_INVALID_OPERATION, kTraceWarning,
2617 "StopPlayingFileAsMicrophone() isnot playing");
2618 return 0;
2619 }
2620
niklase@google.com470e71d2011-07-07 08:21:25 +00002621 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2622 {
2623 _engineStatisticsPtr->SetLastError(
2624 VE_STOP_RECORDING_FAILED, kTraceError,
2625 "StopPlayingFile() could not stop playing");
2626 return -1;
2627 }
2628 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2629 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2630 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002631 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002632
2633 return 0;
2634}
2635
2636int Channel::IsPlayingFileAsMicrophone() const
2637{
2638 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2639 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002640 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002641}
2642
pbos@webrtc.org92135212013-05-14 08:31:39 +00002643int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002644{
2645 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2646 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2647
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002648 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002649
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002650 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002651 {
2652 _engineStatisticsPtr->SetLastError(
2653 VE_INVALID_OPERATION, kTraceError,
2654 "ScaleFileAsMicrophonePlayout() isnot playing");
2655 return -1;
2656 }
2657
2658 if ((_inputFilePlayerPtr == NULL) ||
2659 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2660 {
2661 _engineStatisticsPtr->SetLastError(
2662 VE_BAD_ARGUMENT, kTraceError,
2663 "SetAudioScaling() failed to scale playout");
2664 return -1;
2665 }
2666
2667 return 0;
2668}
2669
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002670int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002671 const CodecInst* codecInst)
2672{
2673 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2674 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2675
2676 if (_outputFileRecording)
2677 {
2678 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2679 "StartRecordingPlayout() is already recording");
2680 return 0;
2681 }
2682
2683 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002684 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002685 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2686
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002687 if ((codecInst != NULL) &&
2688 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002689 {
2690 _engineStatisticsPtr->SetLastError(
2691 VE_BAD_ARGUMENT, kTraceError,
2692 "StartRecordingPlayout() invalid compression");
2693 return(-1);
2694 }
2695 if(codecInst == NULL)
2696 {
2697 format = kFileFormatPcm16kHzFile;
2698 codecInst=&dummyCodec;
2699 }
2700 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2701 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2702 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2703 {
2704 format = kFileFormatWavFile;
2705 }
2706 else
2707 {
2708 format = kFileFormatCompressedFile;
2709 }
2710
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002711 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002712
2713 // Destroy the old instance
2714 if (_outputFileRecorderPtr)
2715 {
2716 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2717 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2718 _outputFileRecorderPtr = NULL;
2719 }
2720
2721 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2722 _outputFileRecorderId, (const FileFormats)format);
2723 if (_outputFileRecorderPtr == NULL)
2724 {
2725 _engineStatisticsPtr->SetLastError(
2726 VE_INVALID_ARGUMENT, kTraceError,
2727 "StartRecordingPlayout() fileRecorder format isnot correct");
2728 return -1;
2729 }
2730
2731 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2732 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2733 {
2734 _engineStatisticsPtr->SetLastError(
2735 VE_BAD_FILE, kTraceError,
2736 "StartRecordingAudioFile() failed to start file recording");
2737 _outputFileRecorderPtr->StopRecording();
2738 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2739 _outputFileRecorderPtr = NULL;
2740 return -1;
2741 }
2742 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2743 _outputFileRecording = true;
2744
2745 return 0;
2746}
2747
2748int Channel::StartRecordingPlayout(OutStream* stream,
2749 const CodecInst* codecInst)
2750{
2751 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2752 "Channel::StartRecordingPlayout()");
2753
2754 if (_outputFileRecording)
2755 {
2756 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2757 "StartRecordingPlayout() is already recording");
2758 return 0;
2759 }
2760
2761 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002762 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002763 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2764
2765 if (codecInst != NULL && codecInst->channels != 1)
2766 {
2767 _engineStatisticsPtr->SetLastError(
2768 VE_BAD_ARGUMENT, kTraceError,
2769 "StartRecordingPlayout() invalid compression");
2770 return(-1);
2771 }
2772 if(codecInst == NULL)
2773 {
2774 format = kFileFormatPcm16kHzFile;
2775 codecInst=&dummyCodec;
2776 }
2777 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2778 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2779 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2780 {
2781 format = kFileFormatWavFile;
2782 }
2783 else
2784 {
2785 format = kFileFormatCompressedFile;
2786 }
2787
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002788 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002789
2790 // Destroy the old instance
2791 if (_outputFileRecorderPtr)
2792 {
2793 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2794 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2795 _outputFileRecorderPtr = NULL;
2796 }
2797
2798 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2799 _outputFileRecorderId, (const FileFormats)format);
2800 if (_outputFileRecorderPtr == NULL)
2801 {
2802 _engineStatisticsPtr->SetLastError(
2803 VE_INVALID_ARGUMENT, kTraceError,
2804 "StartRecordingPlayout() fileRecorder format isnot correct");
2805 return -1;
2806 }
2807
2808 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2809 notificationTime) != 0)
2810 {
2811 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2812 "StartRecordingPlayout() failed to "
2813 "start file recording");
2814 _outputFileRecorderPtr->StopRecording();
2815 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2816 _outputFileRecorderPtr = NULL;
2817 return -1;
2818 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002819
niklase@google.com470e71d2011-07-07 08:21:25 +00002820 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2821 _outputFileRecording = true;
2822
2823 return 0;
2824}
2825
2826int Channel::StopRecordingPlayout()
2827{
2828 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2829 "Channel::StopRecordingPlayout()");
2830
2831 if (!_outputFileRecording)
2832 {
2833 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2834 "StopRecordingPlayout() isnot recording");
2835 return -1;
2836 }
2837
2838
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002839 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002840
2841 if (_outputFileRecorderPtr->StopRecording() != 0)
2842 {
2843 _engineStatisticsPtr->SetLastError(
2844 VE_STOP_RECORDING_FAILED, kTraceError,
2845 "StopRecording() could not stop recording");
2846 return(-1);
2847 }
2848 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2849 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2850 _outputFileRecorderPtr = NULL;
2851 _outputFileRecording = false;
2852
2853 return 0;
2854}
2855
2856void
2857Channel::SetMixWithMicStatus(bool mix)
2858{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002859 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002860 _mixFileWithMicrophone=mix;
2861}
2862
2863int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002864Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002865{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002866 int8_t currentLevel = _outputAudioLevel.Level();
2867 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002868 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2869 VoEId(_instanceId,_channelId),
2870 "GetSpeechOutputLevel() => level=%u", level);
2871 return 0;
2872}
2873
2874int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002875Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002876{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002877 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2878 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002879 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2880 VoEId(_instanceId,_channelId),
2881 "GetSpeechOutputLevelFullRange() => level=%u", level);
2882 return 0;
2883}
2884
2885int
2886Channel::SetMute(bool enable)
2887{
wu@webrtc.org63420662013-10-17 18:28:55 +00002888 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002889 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2890 "Channel::SetMute(enable=%d)", enable);
2891 _mute = enable;
2892 return 0;
2893}
2894
2895bool
2896Channel::Mute() const
2897{
wu@webrtc.org63420662013-10-17 18:28:55 +00002898 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002899 return _mute;
2900}
2901
2902int
2903Channel::SetOutputVolumePan(float left, float right)
2904{
wu@webrtc.org63420662013-10-17 18:28:55 +00002905 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002906 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2907 "Channel::SetOutputVolumePan()");
2908 _panLeft = left;
2909 _panRight = right;
2910 return 0;
2911}
2912
2913int
2914Channel::GetOutputVolumePan(float& left, float& right) const
2915{
wu@webrtc.org63420662013-10-17 18:28:55 +00002916 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002917 left = _panLeft;
2918 right = _panRight;
2919 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2920 VoEId(_instanceId,_channelId),
2921 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2922 return 0;
2923}
2924
2925int
2926Channel::SetChannelOutputVolumeScaling(float scaling)
2927{
wu@webrtc.org63420662013-10-17 18:28:55 +00002928 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002929 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2930 "Channel::SetChannelOutputVolumeScaling()");
2931 _outputGain = scaling;
2932 return 0;
2933}
2934
2935int
2936Channel::GetChannelOutputVolumeScaling(float& scaling) const
2937{
wu@webrtc.org63420662013-10-17 18:28:55 +00002938 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002939 scaling = _outputGain;
2940 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2941 VoEId(_instanceId,_channelId),
2942 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2943 return 0;
2944}
2945
niklase@google.com470e71d2011-07-07 08:21:25 +00002946int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002947 int lengthMs, int attenuationDb,
2948 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002949{
2950 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2951 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2952 playDtmfEvent);
2953
2954 _playOutbandDtmfEvent = playDtmfEvent;
2955
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002956 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002957 attenuationDb) != 0)
2958 {
2959 _engineStatisticsPtr->SetLastError(
2960 VE_SEND_DTMF_FAILED,
2961 kTraceWarning,
2962 "SendTelephoneEventOutband() failed to send event");
2963 return -1;
2964 }
2965 return 0;
2966}
2967
2968int Channel::SendTelephoneEventInband(unsigned char eventCode,
2969 int lengthMs,
2970 int attenuationDb,
2971 bool playDtmfEvent)
2972{
2973 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2974 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2975 playDtmfEvent);
2976
2977 _playInbandDtmfEvent = playDtmfEvent;
2978 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2979
2980 return 0;
2981}
2982
2983int
2984Channel::SetDtmfPlayoutStatus(bool enable)
2985{
2986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2987 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002988 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002989 {
2990 _engineStatisticsPtr->SetLastError(
2991 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2992 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2993 return -1;
2994 }
2995 return 0;
2996}
2997
2998bool
2999Channel::DtmfPlayoutStatus() const
3000{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003001 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003002}
3003
3004int
3005Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3006{
3007 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3008 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003009 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003010 {
3011 _engineStatisticsPtr->SetLastError(
3012 VE_INVALID_ARGUMENT, kTraceError,
3013 "SetSendTelephoneEventPayloadType() invalid type");
3014 return -1;
3015 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003016 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003017 codec.plfreq = 8000;
3018 codec.pltype = type;
3019 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003020 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003021 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003022 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3023 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3024 _engineStatisticsPtr->SetLastError(
3025 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3026 "SetSendTelephoneEventPayloadType() failed to register send"
3027 "payload type");
3028 return -1;
3029 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003030 }
3031 _sendTelephoneEventPayloadType = type;
3032 return 0;
3033}
3034
3035int
3036Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3037{
3038 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3039 "Channel::GetSendTelephoneEventPayloadType()");
3040 type = _sendTelephoneEventPayloadType;
3041 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3042 VoEId(_instanceId,_channelId),
3043 "GetSendTelephoneEventPayloadType() => type=%u", type);
3044 return 0;
3045}
3046
niklase@google.com470e71d2011-07-07 08:21:25 +00003047int
3048Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3049{
3050 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3051 "Channel::UpdateRxVadDetection()");
3052
3053 int vadDecision = 1;
3054
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003055 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003056
3057 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3058 {
3059 OnRxVadDetected(vadDecision);
3060 _oldVadDecision = vadDecision;
3061 }
3062
3063 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3064 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3065 vadDecision);
3066 return 0;
3067}
3068
3069int
3070Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3071{
3072 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3073 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003074 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003075
3076 if (_rxVadObserverPtr)
3077 {
3078 _engineStatisticsPtr->SetLastError(
3079 VE_INVALID_OPERATION, kTraceError,
3080 "RegisterRxVadObserver() observer already enabled");
3081 return -1;
3082 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003083 _rxVadObserverPtr = &observer;
3084 _RxVadDetection = true;
3085 return 0;
3086}
3087
3088int
3089Channel::DeRegisterRxVadObserver()
3090{
3091 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3092 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003093 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003094
3095 if (!_rxVadObserverPtr)
3096 {
3097 _engineStatisticsPtr->SetLastError(
3098 VE_INVALID_OPERATION, kTraceWarning,
3099 "DeRegisterRxVadObserver() observer already disabled");
3100 return 0;
3101 }
3102 _rxVadObserverPtr = NULL;
3103 _RxVadDetection = false;
3104 return 0;
3105}
3106
3107int
3108Channel::VoiceActivityIndicator(int &activity)
3109{
3110 activity = _sendFrameType;
3111
3112 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003113 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003114 return 0;
3115}
3116
3117#ifdef WEBRTC_VOICE_ENGINE_AGC
3118
3119int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003120Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003121{
3122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3123 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3124 (int)enable, (int)mode);
3125
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003126 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 switch (mode)
3128 {
3129 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003130 break;
3131 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003132 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003133 break;
3134 case kAgcFixedDigital:
3135 agcMode = GainControl::kFixedDigital;
3136 break;
3137 case kAgcAdaptiveDigital:
3138 agcMode =GainControl::kAdaptiveDigital;
3139 break;
3140 default:
3141 _engineStatisticsPtr->SetLastError(
3142 VE_INVALID_ARGUMENT, kTraceError,
3143 "SetRxAgcStatus() invalid Agc mode");
3144 return -1;
3145 }
3146
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003147 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003148 {
3149 _engineStatisticsPtr->SetLastError(
3150 VE_APM_ERROR, kTraceError,
3151 "SetRxAgcStatus() failed to set Agc mode");
3152 return -1;
3153 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003154 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003155 {
3156 _engineStatisticsPtr->SetLastError(
3157 VE_APM_ERROR, kTraceError,
3158 "SetRxAgcStatus() failed to set Agc state");
3159 return -1;
3160 }
3161
3162 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003163 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003164
3165 return 0;
3166}
3167
3168int
3169Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3170{
3171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3172 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3173
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003174 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003175 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003176 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003177
3178 enabled = enable;
3179
3180 switch (agcMode)
3181 {
3182 case GainControl::kFixedDigital:
3183 mode = kAgcFixedDigital;
3184 break;
3185 case GainControl::kAdaptiveDigital:
3186 mode = kAgcAdaptiveDigital;
3187 break;
3188 default:
3189 _engineStatisticsPtr->SetLastError(
3190 VE_APM_ERROR, kTraceError,
3191 "GetRxAgcStatus() invalid Agc mode");
3192 return -1;
3193 }
3194
3195 return 0;
3196}
3197
3198int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003199Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003200{
3201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3202 "Channel::SetRxAgcConfig()");
3203
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003204 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003205 config.targetLeveldBOv) != 0)
3206 {
3207 _engineStatisticsPtr->SetLastError(
3208 VE_APM_ERROR, kTraceError,
3209 "SetRxAgcConfig() failed to set target peak |level|"
3210 "(or envelope) of the Agc");
3211 return -1;
3212 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003213 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003214 config.digitalCompressionGaindB) != 0)
3215 {
3216 _engineStatisticsPtr->SetLastError(
3217 VE_APM_ERROR, kTraceError,
3218 "SetRxAgcConfig() failed to set the range in |gain| the"
3219 " digital compression stage may apply");
3220 return -1;
3221 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003222 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003223 config.limiterEnable) != 0)
3224 {
3225 _engineStatisticsPtr->SetLastError(
3226 VE_APM_ERROR, kTraceError,
3227 "SetRxAgcConfig() failed to set hard limiter to the signal");
3228 return -1;
3229 }
3230
3231 return 0;
3232}
3233
3234int
3235Channel::GetRxAgcConfig(AgcConfig& config)
3236{
3237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3238 "Channel::GetRxAgcConfig(config=%?)");
3239
3240 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003241 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003242 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003243 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003244 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003245 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003246
3247 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3248 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3249 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3250 " limiterEnable=%d",
3251 config.targetLeveldBOv,
3252 config.digitalCompressionGaindB,
3253 config.limiterEnable);
3254
3255 return 0;
3256}
3257
3258#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3259
3260#ifdef WEBRTC_VOICE_ENGINE_NR
3261
3262int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003263Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003264{
3265 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3266 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3267 (int)enable, (int)mode);
3268
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003269 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 switch (mode)
3271 {
3272
3273 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003274 break;
3275 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003276 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003277 break;
3278 case kNsConference:
3279 nsLevel = NoiseSuppression::kHigh;
3280 break;
3281 case kNsLowSuppression:
3282 nsLevel = NoiseSuppression::kLow;
3283 break;
3284 case kNsModerateSuppression:
3285 nsLevel = NoiseSuppression::kModerate;
3286 break;
3287 case kNsHighSuppression:
3288 nsLevel = NoiseSuppression::kHigh;
3289 break;
3290 case kNsVeryHighSuppression:
3291 nsLevel = NoiseSuppression::kVeryHigh;
3292 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003293 }
3294
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003295 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 != 0)
3297 {
3298 _engineStatisticsPtr->SetLastError(
3299 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003300 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003301 return -1;
3302 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003303 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003304 {
3305 _engineStatisticsPtr->SetLastError(
3306 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003307 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003308 return -1;
3309 }
3310
3311 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003312 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003313
3314 return 0;
3315}
3316
3317int
3318Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3319{
3320 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3321 "Channel::GetRxNsStatus(enable=?, mode=?)");
3322
3323 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003324 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003325 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003326 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003327
3328 enabled = enable;
3329
3330 switch (ncLevel)
3331 {
3332 case NoiseSuppression::kLow:
3333 mode = kNsLowSuppression;
3334 break;
3335 case NoiseSuppression::kModerate:
3336 mode = kNsModerateSuppression;
3337 break;
3338 case NoiseSuppression::kHigh:
3339 mode = kNsHighSuppression;
3340 break;
3341 case NoiseSuppression::kVeryHigh:
3342 mode = kNsVeryHighSuppression;
3343 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003344 }
3345
3346 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3347 VoEId(_instanceId,_channelId),
3348 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3349 return 0;
3350}
3351
3352#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3353
3354int
3355Channel::RegisterRTPObserver(VoERTPObserver& observer)
3356{
3357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3358 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003359 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003360
3361 if (_rtpObserverPtr)
3362 {
3363 _engineStatisticsPtr->SetLastError(
3364 VE_INVALID_OPERATION, kTraceError,
3365 "RegisterRTPObserver() observer already enabled");
3366 return -1;
3367 }
3368
3369 _rtpObserverPtr = &observer;
3370 _rtpObserver = true;
3371
3372 return 0;
3373}
3374
3375int
3376Channel::DeRegisterRTPObserver()
3377{
3378 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3379 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003380 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003381
3382 if (!_rtpObserverPtr)
3383 {
3384 _engineStatisticsPtr->SetLastError(
3385 VE_INVALID_OPERATION, kTraceWarning,
3386 "DeRegisterRTPObserver() observer already disabled");
3387 return 0;
3388 }
3389
3390 _rtpObserver = false;
3391 _rtpObserverPtr = NULL;
3392
3393 return 0;
3394}
3395
3396int
3397Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3398{
3399 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3400 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003401 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003402
3403 if (_rtcpObserverPtr)
3404 {
3405 _engineStatisticsPtr->SetLastError(
3406 VE_INVALID_OPERATION, kTraceError,
3407 "RegisterRTCPObserver() observer already enabled");
3408 return -1;
3409 }
3410
3411 _rtcpObserverPtr = &observer;
3412 _rtcpObserver = true;
3413
3414 return 0;
3415}
3416
3417int
3418Channel::DeRegisterRTCPObserver()
3419{
3420 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3421 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003422 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003423
3424 if (!_rtcpObserverPtr)
3425 {
3426 _engineStatisticsPtr->SetLastError(
3427 VE_INVALID_OPERATION, kTraceWarning,
3428 "DeRegisterRTCPObserver() observer already disabled");
3429 return 0;
3430 }
3431
3432 _rtcpObserver = false;
3433 _rtcpObserverPtr = NULL;
3434
3435 return 0;
3436}
3437
3438int
3439Channel::SetLocalSSRC(unsigned int ssrc)
3440{
3441 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3442 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003443 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003444 {
3445 _engineStatisticsPtr->SetLastError(
3446 VE_ALREADY_SENDING, kTraceError,
3447 "SetLocalSSRC() already sending");
3448 return -1;
3449 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003450 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003451 {
3452 _engineStatisticsPtr->SetLastError(
3453 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3454 "SetLocalSSRC() failed to set SSRC");
3455 return -1;
3456 }
3457 return 0;
3458}
3459
3460int
3461Channel::GetLocalSSRC(unsigned int& ssrc)
3462{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003463 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003464 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3465 VoEId(_instanceId,_channelId),
3466 "GetLocalSSRC() => ssrc=%lu", ssrc);
3467 return 0;
3468}
3469
3470int
3471Channel::GetRemoteSSRC(unsigned int& ssrc)
3472{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003473 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003474 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3475 VoEId(_instanceId,_channelId),
3476 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3477 return 0;
3478}
3479
3480int
3481Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3482{
3483 if (arrCSRC == NULL)
3484 {
3485 _engineStatisticsPtr->SetLastError(
3486 VE_INVALID_ARGUMENT, kTraceError,
3487 "GetRemoteCSRCs() invalid array argument");
3488 return -1;
3489 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003490 uint32_t arrOfCSRC[kRtpCsrcSize];
3491 int32_t CSRCs(0);
braveyao@webrtc.orgcdefc912014-03-11 16:19:56 +00003492 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003493 if (CSRCs > 0)
3494 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003495 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003496 for (int i = 0; i < (int) CSRCs; i++)
3497 {
3498 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3499 VoEId(_instanceId, _channelId),
3500 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3501 }
3502 } else
3503 {
3504 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3505 VoEId(_instanceId, _channelId),
3506 "GetRemoteCSRCs() => list is empty!");
3507 }
3508 return CSRCs;
3509}
3510
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003511int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003512 if (rtp_audioproc_.get() == NULL) {
3513 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3514 _channelId)));
3515 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003516
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003517 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3518 AudioProcessing::kNoError) {
3519 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3520 "Failed to enable AudioProcessing::level_estimator()");
3521 return -1;
3522 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003523
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003524 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003525
3526 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003527}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003528
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003529int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3530 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3531}
3532
3533int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3534 rtp_header_parser_->DeregisterRtpHeaderExtension(
3535 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003536 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3537 kRtpExtensionAbsoluteSendTime, id)) {
3538 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003539 }
3540 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003541}
3542
3543int
3544Channel::SetRTCPStatus(bool enable)
3545{
3546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3547 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003548 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003549 kRtcpCompound : kRtcpOff) != 0)
3550 {
3551 _engineStatisticsPtr->SetLastError(
3552 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3553 "SetRTCPStatus() failed to set RTCP status");
3554 return -1;
3555 }
3556 return 0;
3557}
3558
3559int
3560Channel::GetRTCPStatus(bool& enabled)
3561{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003562 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003563 enabled = (method != kRtcpOff);
3564 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3565 VoEId(_instanceId,_channelId),
3566 "GetRTCPStatus() => enabled=%d", enabled);
3567 return 0;
3568}
3569
3570int
3571Channel::SetRTCP_CNAME(const char cName[256])
3572{
3573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3574 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003575 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003576 {
3577 _engineStatisticsPtr->SetLastError(
3578 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3579 "SetRTCP_CNAME() failed to set RTCP CNAME");
3580 return -1;
3581 }
3582 return 0;
3583}
3584
3585int
3586Channel::GetRTCP_CNAME(char cName[256])
3587{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003588 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003589 {
3590 _engineStatisticsPtr->SetLastError(
3591 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3592 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3593 return -1;
3594 }
3595 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3596 VoEId(_instanceId, _channelId),
3597 "GetRTCP_CNAME() => cName=%s", cName);
3598 return 0;
3599}
3600
3601int
3602Channel::GetRemoteRTCP_CNAME(char cName[256])
3603{
3604 if (cName == NULL)
3605 {
3606 _engineStatisticsPtr->SetLastError(
3607 VE_INVALID_ARGUMENT, kTraceError,
3608 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3609 return -1;
3610 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003611 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003612 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003613 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003614 {
3615 _engineStatisticsPtr->SetLastError(
3616 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3617 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3618 return -1;
3619 }
3620 strcpy(cName, cname);
3621 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3622 VoEId(_instanceId, _channelId),
3623 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3624 return 0;
3625}
3626
3627int
3628Channel::GetRemoteRTCPData(
3629 unsigned int& NTPHigh,
3630 unsigned int& NTPLow,
3631 unsigned int& timestamp,
3632 unsigned int& playoutTimestamp,
3633 unsigned int* jitter,
3634 unsigned short* fractionLost)
3635{
3636 // --- Information from sender info in received Sender Reports
3637
3638 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003639 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003640 {
3641 _engineStatisticsPtr->SetLastError(
3642 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003643 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003644 "side");
3645 return -1;
3646 }
3647
3648 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3649 // and octet count)
3650 NTPHigh = senderInfo.NTPseconds;
3651 NTPLow = senderInfo.NTPfraction;
3652 timestamp = senderInfo.RTPtimeStamp;
3653
3654 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3655 VoEId(_instanceId, _channelId),
3656 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3657 "timestamp=%lu",
3658 NTPHigh, NTPLow, timestamp);
3659
3660 // --- Locally derived information
3661
3662 // This value is updated on each incoming RTCP packet (0 when no packet
3663 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003664 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003665
3666 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3667 VoEId(_instanceId, _channelId),
3668 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003669 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003670
3671 if (NULL != jitter || NULL != fractionLost)
3672 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003673 // Get all RTCP receiver report blocks that have been received on this
3674 // channel. If we receive RTP packets from a remote source we know the
3675 // remote SSRC and use the report block from him.
3676 // Otherwise use the first report block.
3677 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003678 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003679 remote_stats.empty()) {
3680 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3681 VoEId(_instanceId, _channelId),
3682 "GetRemoteRTCPData() failed to measure statistics due"
3683 " to lack of received RTP and/or RTCP packets");
3684 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003685 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003686
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003687 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003688 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3689 for (; it != remote_stats.end(); ++it) {
3690 if (it->remoteSSRC == remoteSSRC)
3691 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003692 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003693
3694 if (it == remote_stats.end()) {
3695 // If we have not received any RTCP packets from this SSRC it probably
3696 // means that we have not received any RTP packets.
3697 // Use the first received report block instead.
3698 it = remote_stats.begin();
3699 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003700 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003701
xians@webrtc.org79af7342012-01-31 12:22:14 +00003702 if (jitter) {
3703 *jitter = it->jitter;
3704 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3705 VoEId(_instanceId, _channelId),
3706 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3707 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003708
xians@webrtc.org79af7342012-01-31 12:22:14 +00003709 if (fractionLost) {
3710 *fractionLost = it->fractionLost;
3711 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3712 VoEId(_instanceId, _channelId),
3713 "GetRemoteRTCPData() => fractionLost = %lu",
3714 *fractionLost);
3715 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003716 }
3717 return 0;
3718}
3719
3720int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003721Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003722 unsigned int name,
3723 const char* data,
3724 unsigned short dataLengthInBytes)
3725{
3726 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3727 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003728 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003729 {
3730 _engineStatisticsPtr->SetLastError(
3731 VE_NOT_SENDING, kTraceError,
3732 "SendApplicationDefinedRTCPPacket() not sending");
3733 return -1;
3734 }
3735 if (NULL == data)
3736 {
3737 _engineStatisticsPtr->SetLastError(
3738 VE_INVALID_ARGUMENT, kTraceError,
3739 "SendApplicationDefinedRTCPPacket() invalid data value");
3740 return -1;
3741 }
3742 if (dataLengthInBytes % 4 != 0)
3743 {
3744 _engineStatisticsPtr->SetLastError(
3745 VE_INVALID_ARGUMENT, kTraceError,
3746 "SendApplicationDefinedRTCPPacket() invalid length value");
3747 return -1;
3748 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003749 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003750 if (status == kRtcpOff)
3751 {
3752 _engineStatisticsPtr->SetLastError(
3753 VE_RTCP_ERROR, kTraceError,
3754 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3755 return -1;
3756 }
3757
3758 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003759 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003760 subType,
3761 name,
3762 (const unsigned char*) data,
3763 dataLengthInBytes) != 0)
3764 {
3765 _engineStatisticsPtr->SetLastError(
3766 VE_SEND_ERROR, kTraceError,
3767 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3768 return -1;
3769 }
3770 return 0;
3771}
3772
3773int
3774Channel::GetRTPStatistics(
3775 unsigned int& averageJitterMs,
3776 unsigned int& maxJitterMs,
3777 unsigned int& discardedPackets)
3778{
niklase@google.com470e71d2011-07-07 08:21:25 +00003779 // The jitter statistics is updated for each received RTP packet and is
3780 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003781 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3782 // If RTCP is off, there is no timed thread in the RTCP module regularly
3783 // generating new stats, trigger the update manually here instead.
3784 StreamStatistician* statistician =
3785 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3786 if (statistician) {
3787 // Don't use returned statistics, use data from proxy instead so that
3788 // max jitter can be fetched atomically.
3789 RtcpStatistics s;
3790 statistician->GetStatistics(&s, true);
3791 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003792 }
3793
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003794 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003795 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003796 if (playoutFrequency > 0) {
3797 // Scale RTP statistics given the current playout frequency
3798 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3799 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003800 }
3801
3802 discardedPackets = _numberOfDiscardedPackets;
3803
3804 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3805 VoEId(_instanceId, _channelId),
3806 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003807 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003808 averageJitterMs, maxJitterMs, discardedPackets);
3809 return 0;
3810}
3811
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003812int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3813 if (sender_info == NULL) {
3814 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3815 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3816 return -1;
3817 }
3818
3819 // Get the sender info from the latest received RTCP Sender Report.
3820 RTCPSenderInfo rtcp_sender_info;
3821 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3822 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3823 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3824 return -1;
3825 }
3826
3827 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3828 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3829 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3830 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3831 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3832 return 0;
3833}
3834
3835int Channel::GetRemoteRTCPReportBlocks(
3836 std::vector<ReportBlock>* report_blocks) {
3837 if (report_blocks == NULL) {
3838 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3839 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3840 return -1;
3841 }
3842
3843 // Get the report blocks from the latest received RTCP Sender or Receiver
3844 // Report. Each element in the vector contains the sender's SSRC and a
3845 // report block according to RFC 3550.
3846 std::vector<RTCPReportBlock> rtcp_report_blocks;
3847 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3848 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3849 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3850 return -1;
3851 }
3852
3853 if (rtcp_report_blocks.empty())
3854 return 0;
3855
3856 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3857 for (; it != rtcp_report_blocks.end(); ++it) {
3858 ReportBlock report_block;
3859 report_block.sender_SSRC = it->remoteSSRC;
3860 report_block.source_SSRC = it->sourceSSRC;
3861 report_block.fraction_lost = it->fractionLost;
3862 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3863 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3864 report_block.interarrival_jitter = it->jitter;
3865 report_block.last_SR_timestamp = it->lastSR;
3866 report_block.delay_since_last_SR = it->delaySinceLastSR;
3867 report_blocks->push_back(report_block);
3868 }
3869 return 0;
3870}
3871
niklase@google.com470e71d2011-07-07 08:21:25 +00003872int
3873Channel::GetRTPStatistics(CallStatistics& stats)
3874{
niklase@google.com470e71d2011-07-07 08:21:25 +00003875 // --- Part one of the final structure (four values)
3876
3877 // The jitter statistics is updated for each received RTP packet and is
3878 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003879 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003880 StreamStatistician* statistician =
3881 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3882 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003883 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3884 _engineStatisticsPtr->SetLastError(
3885 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3886 "GetRTPStatistics() failed to read RTP statistics from the "
3887 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003888 }
3889
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003890 stats.fractionLost = statistics.fraction_lost;
3891 stats.cumulativeLost = statistics.cumulative_lost;
3892 stats.extendedMax = statistics.extended_max_sequence_number;
3893 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003894
3895 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3896 VoEId(_instanceId, _channelId),
3897 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003898 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003899 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3900 stats.jitterSamples);
3901
3902 // --- Part two of the final structure (one value)
3903
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003904 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003905 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003906 if (method == kRtcpOff)
3907 {
3908 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3909 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003910 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003911 "measurements cannot be retrieved");
3912 } else
3913 {
3914 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003915 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003916 if (remoteSSRC > 0)
3917 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003918 uint16_t avgRTT(0);
3919 uint16_t maxRTT(0);
3920 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003921
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003922 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 != 0)
3924 {
3925 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3926 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003927 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003928 "the RTP/RTCP module");
3929 }
3930 } else
3931 {
3932 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3933 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003934 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003935 "RTP packets have been received yet");
3936 }
3937 }
3938
3939 stats.rttMs = static_cast<int> (RTT);
3940
3941 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3942 VoEId(_instanceId, _channelId),
3943 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3944
3945 // --- Part three of the final structure (four values)
3946
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003947 uint32_t bytesSent(0);
3948 uint32_t packetsSent(0);
3949 uint32_t bytesReceived(0);
3950 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003951
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003952 if (statistician) {
3953 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3954 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003955
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003956 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003957 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003958 {
3959 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3960 VoEId(_instanceId, _channelId),
3961 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003962 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003963 }
3964
3965 stats.bytesSent = bytesSent;
3966 stats.packetsSent = packetsSent;
3967 stats.bytesReceived = bytesReceived;
3968 stats.packetsReceived = packetsReceived;
3969
3970 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3971 VoEId(_instanceId, _channelId),
3972 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003973 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003974 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3975 stats.packetsReceived);
3976
3977 return 0;
3978}
3979
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003980int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3981 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3982 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003983
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003984 if (enable) {
3985 if (redPayloadtype < 0 || redPayloadtype > 127) {
3986 _engineStatisticsPtr->SetLastError(
3987 VE_PLTYPE_ERROR, kTraceError,
3988 "SetFECStatus() invalid RED payload type");
3989 return -1;
3990 }
3991
3992 if (SetRedPayloadType(redPayloadtype) < 0) {
3993 _engineStatisticsPtr->SetLastError(
3994 VE_CODEC_ERROR, kTraceError,
3995 "SetSecondarySendCodec() Failed to register RED ACM");
3996 return -1;
3997 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003998 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003999
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004000 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004001 _engineStatisticsPtr->SetLastError(
4002 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4003 "SetFECStatus() failed to set FEC state in the ACM");
4004 return -1;
4005 }
4006 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004007}
4008
4009int
4010Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4011{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004012 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004013 if (enabled)
4014 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004015 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004016 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004017 {
4018 _engineStatisticsPtr->SetLastError(
4019 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4020 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4021 "module");
4022 return -1;
4023 }
4024 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4025 VoEId(_instanceId, _channelId),
4026 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4027 enabled, redPayloadtype);
4028 return 0;
4029 }
4030 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4031 VoEId(_instanceId, _channelId),
4032 "GetFECStatus() => enabled=%d", enabled);
4033 return 0;
4034}
4035
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004036void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4037 // None of these functions can fail.
4038 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004039 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4040 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004041 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004042 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004043 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004044 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004045}
4046
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004047// Called when we are missing one or more packets.
4048int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004049 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4050}
4051
niklase@google.com470e71d2011-07-07 08:21:25 +00004052int
niklase@google.com470e71d2011-07-07 08:21:25 +00004053Channel::StartRTPDump(const char fileNameUTF8[1024],
4054 RTPDirections direction)
4055{
4056 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4057 "Channel::StartRTPDump()");
4058 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4059 {
4060 _engineStatisticsPtr->SetLastError(
4061 VE_INVALID_ARGUMENT, kTraceError,
4062 "StartRTPDump() invalid RTP direction");
4063 return -1;
4064 }
4065 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4066 &_rtpDumpIn : &_rtpDumpOut;
4067 if (rtpDumpPtr == NULL)
4068 {
4069 assert(false);
4070 return -1;
4071 }
4072 if (rtpDumpPtr->IsActive())
4073 {
4074 rtpDumpPtr->Stop();
4075 }
4076 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4077 {
4078 _engineStatisticsPtr->SetLastError(
4079 VE_BAD_FILE, kTraceError,
4080 "StartRTPDump() failed to create file");
4081 return -1;
4082 }
4083 return 0;
4084}
4085
4086int
4087Channel::StopRTPDump(RTPDirections direction)
4088{
4089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4090 "Channel::StopRTPDump()");
4091 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4092 {
4093 _engineStatisticsPtr->SetLastError(
4094 VE_INVALID_ARGUMENT, kTraceError,
4095 "StopRTPDump() invalid RTP direction");
4096 return -1;
4097 }
4098 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4099 &_rtpDumpIn : &_rtpDumpOut;
4100 if (rtpDumpPtr == NULL)
4101 {
4102 assert(false);
4103 return -1;
4104 }
4105 if (!rtpDumpPtr->IsActive())
4106 {
4107 return 0;
4108 }
4109 return rtpDumpPtr->Stop();
4110}
4111
4112bool
4113Channel::RTPDumpIsActive(RTPDirections direction)
4114{
4115 if ((direction != kRtpIncoming) &&
4116 (direction != kRtpOutgoing))
4117 {
4118 _engineStatisticsPtr->SetLastError(
4119 VE_INVALID_ARGUMENT, kTraceError,
4120 "RTPDumpIsActive() invalid RTP direction");
4121 return false;
4122 }
4123 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4124 &_rtpDumpIn : &_rtpDumpOut;
4125 return rtpDumpPtr->IsActive();
4126}
4127
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00004128void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
4129 int video_channel) {
4130 CriticalSectionScoped cs(&_callbackCritSect);
4131 if (vie_network_) {
4132 vie_network_->Release();
4133 vie_network_ = NULL;
4134 }
4135 video_channel_ = -1;
4136
4137 if (vie_network != NULL && video_channel != -1) {
4138 vie_network_ = vie_network;
4139 video_channel_ = video_channel;
4140 }
4141}
4142
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004143uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004144Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004145{
4146 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004147 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004148 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004149 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004150 return 0;
4151}
4152
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004153void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004154 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004155 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004156 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004157 CodecInst codec;
4158 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004159
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004160 if (!mono_recording_audio_.get()) {
4161 // Temporary space for DownConvertToCodecFormat.
4162 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004163 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004164 DownConvertToCodecFormat(audio_data,
4165 number_of_frames,
4166 number_of_channels,
4167 sample_rate,
4168 codec.channels,
4169 codec.plfreq,
4170 mono_recording_audio_.get(),
4171 &input_resampler_,
4172 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004173}
4174
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004175uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004176Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004177{
4178 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4179 "Channel::PrepareEncodeAndSend()");
4180
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004181 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004182 {
4183 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4184 "Channel::PrepareEncodeAndSend() invalid audio frame");
4185 return -1;
4186 }
4187
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004188 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00004189 {
4190 MixOrReplaceAudioWithFile(mixingFrequency);
4191 }
4192
wu@webrtc.org63420662013-10-17 18:28:55 +00004193 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004194 {
4195 AudioFrameOperations::Mute(_audioFrame);
4196 }
4197
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004198 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00004199 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004200 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004201 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004202 if (_inputExternalMediaCallbackPtr)
4203 {
4204 _inputExternalMediaCallbackPtr->Process(
4205 _channelId,
4206 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004207 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004208 _audioFrame.samples_per_channel_,
4209 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004210 isStereo);
4211 }
4212 }
4213
4214 InsertInbandDtmfTone();
4215
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004216 if (_includeAudioLevelIndication) {
4217 // Performs level analysis only; does not affect the signal.
4218 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4219 if (err) {
4220 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4221 assert(false);
4222 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004223 }
4224
niklase@google.com470e71d2011-07-07 08:21:25 +00004225 return 0;
4226}
4227
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004228uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004229Channel::EncodeAndSend()
4230{
4231 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4232 "Channel::EncodeAndSend()");
4233
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004234 assert(_audioFrame.num_channels_ <= 2);
4235 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004236 {
4237 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4238 "Channel::EncodeAndSend() invalid audio frame");
4239 return -1;
4240 }
4241
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004242 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004243
4244 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4245
4246 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004247 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004248 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004249 {
4250 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4251 "Channel::EncodeAndSend() ACM encoding failed");
4252 return -1;
4253 }
4254
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004255 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004256
4257 // --- Encode if complete frame is ready
4258
4259 // This call will trigger AudioPacketizationCallback::SendData if encoding
4260 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004261 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004262}
4263
4264int Channel::RegisterExternalMediaProcessing(
4265 ProcessingTypes type,
4266 VoEMediaProcess& processObject)
4267{
4268 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4269 "Channel::RegisterExternalMediaProcessing()");
4270
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004271 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004272
4273 if (kPlaybackPerChannel == type)
4274 {
4275 if (_outputExternalMediaCallbackPtr)
4276 {
4277 _engineStatisticsPtr->SetLastError(
4278 VE_INVALID_OPERATION, kTraceError,
4279 "Channel::RegisterExternalMediaProcessing() "
4280 "output external media already enabled");
4281 return -1;
4282 }
4283 _outputExternalMediaCallbackPtr = &processObject;
4284 _outputExternalMedia = true;
4285 }
4286 else if (kRecordingPerChannel == type)
4287 {
4288 if (_inputExternalMediaCallbackPtr)
4289 {
4290 _engineStatisticsPtr->SetLastError(
4291 VE_INVALID_OPERATION, kTraceError,
4292 "Channel::RegisterExternalMediaProcessing() "
4293 "output external media already enabled");
4294 return -1;
4295 }
4296 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004297 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00004298 }
4299 return 0;
4300}
4301
4302int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4303{
4304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4305 "Channel::DeRegisterExternalMediaProcessing()");
4306
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004307 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004308
4309 if (kPlaybackPerChannel == type)
4310 {
4311 if (!_outputExternalMediaCallbackPtr)
4312 {
4313 _engineStatisticsPtr->SetLastError(
4314 VE_INVALID_OPERATION, kTraceWarning,
4315 "Channel::DeRegisterExternalMediaProcessing() "
4316 "output external media already disabled");
4317 return 0;
4318 }
4319 _outputExternalMedia = false;
4320 _outputExternalMediaCallbackPtr = NULL;
4321 }
4322 else if (kRecordingPerChannel == type)
4323 {
4324 if (!_inputExternalMediaCallbackPtr)
4325 {
4326 _engineStatisticsPtr->SetLastError(
4327 VE_INVALID_OPERATION, kTraceWarning,
4328 "Channel::DeRegisterExternalMediaProcessing() "
4329 "input external media already disabled");
4330 return 0;
4331 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004332 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00004333 _inputExternalMediaCallbackPtr = NULL;
4334 }
4335
4336 return 0;
4337}
4338
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004339int Channel::SetExternalMixing(bool enabled) {
4340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4341 "Channel::SetExternalMixing(enabled=%d)", enabled);
4342
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004343 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004344 {
4345 _engineStatisticsPtr->SetLastError(
4346 VE_INVALID_OPERATION, kTraceError,
4347 "Channel::SetExternalMixing() "
4348 "external mixing cannot be changed while playing.");
4349 return -1;
4350 }
4351
4352 _externalMixing = enabled;
4353
4354 return 0;
4355}
4356
niklase@google.com470e71d2011-07-07 08:21:25 +00004357int
4358Channel::ResetRTCPStatistics()
4359{
4360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4361 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004362 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004363 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004364 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004365}
4366
4367int
4368Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4369{
4370 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4371 "Channel::GetRoundTripTimeSummary()");
4372 // Override default module outputs for the case when RTCP is disabled.
4373 // This is done to ensure that we are backward compatible with the
4374 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004375 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004376 {
4377 delaysMs.min = -1;
4378 delaysMs.max = -1;
4379 delaysMs.average = -1;
4380 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4381 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4382 " valid RTT measurements cannot be retrieved");
4383 return 0;
4384 }
4385
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004386 uint32_t remoteSSRC;
4387 uint16_t RTT;
4388 uint16_t avgRTT;
4389 uint16_t maxRTT;
4390 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004391 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004392 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004393 if (remoteSSRC == 0)
4394 {
4395 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4396 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4397 " since no RTP packet has been received yet");
4398 }
4399
4400 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4401 // channel and SSRC. The SSRC is required to parse out the correct source
4402 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004403 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004404 {
4405 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4406 "GetRoundTripTimeSummary unable to retrieve RTT values"
4407 " from the RTCP layer");
4408 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4409 }
4410 else
4411 {
4412 delaysMs.min = minRTT;
4413 delaysMs.max = maxRTT;
4414 delaysMs.average = avgRTT;
4415 }
4416 return 0;
4417}
4418
4419int
4420Channel::GetNetworkStatistics(NetworkStatistics& stats)
4421{
4422 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4423 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004424 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004425 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004426 if (return_value >= 0) {
4427 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4428 }
4429 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004430}
4431
wu@webrtc.org24301a62013-12-13 19:17:43 +00004432void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4433 audio_coding_->GetDecodingCallStatistics(stats);
4434}
4435
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004436bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4437 int* playout_buffer_delay_ms) const {
4438 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004440 "Channel::GetDelayEstimate() no valid estimate.");
4441 return false;
4442 }
4443 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4444 _recPacketDelayMs;
4445 *playout_buffer_delay_ms = playout_delay_ms_;
4446 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4447 "Channel::GetDelayEstimate()");
4448 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004449}
4450
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004451int Channel::SetInitialPlayoutDelay(int delay_ms)
4452{
4453 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4454 "Channel::SetInitialPlayoutDelay()");
4455 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4456 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4457 {
4458 _engineStatisticsPtr->SetLastError(
4459 VE_INVALID_ARGUMENT, kTraceError,
4460 "SetInitialPlayoutDelay() invalid min delay");
4461 return -1;
4462 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004463 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004464 {
4465 _engineStatisticsPtr->SetLastError(
4466 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4467 "SetInitialPlayoutDelay() failed to set min playout delay");
4468 return -1;
4469 }
4470 return 0;
4471}
4472
4473
niklase@google.com470e71d2011-07-07 08:21:25 +00004474int
4475Channel::SetMinimumPlayoutDelay(int delayMs)
4476{
4477 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4478 "Channel::SetMinimumPlayoutDelay()");
4479 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4480 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4481 {
4482 _engineStatisticsPtr->SetLastError(
4483 VE_INVALID_ARGUMENT, kTraceError,
4484 "SetMinimumPlayoutDelay() invalid min delay");
4485 return -1;
4486 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004487 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004488 {
4489 _engineStatisticsPtr->SetLastError(
4490 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4491 "SetMinimumPlayoutDelay() failed to set min playout delay");
4492 return -1;
4493 }
4494 return 0;
4495}
4496
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004497void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4498 uint32_t playout_timestamp = 0;
4499
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004500 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004501 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4502 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4503 " timestamp from the ACM");
4504 _engineStatisticsPtr->SetLastError(
4505 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4506 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4507 return;
4508 }
4509
4510 uint16_t delay_ms = 0;
4511 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4512 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4513 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4514 " delay from the ADM");
4515 _engineStatisticsPtr->SetLastError(
4516 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4517 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4518 return;
4519 }
4520
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004521 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004522 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004523 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004524 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4525 playout_frequency = 8000;
4526 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4527 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004528 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004529 }
4530
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004531 jitter_buffer_playout_timestamp_ = playout_timestamp;
4532
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004533 // Remove the playout delay.
4534 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4535
4536 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4537 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4538 playout_timestamp);
4539
4540 if (rtcp) {
4541 playout_timestamp_rtcp_ = playout_timestamp;
4542 } else {
4543 playout_timestamp_rtp_ = playout_timestamp;
4544 }
4545 playout_delay_ms_ = delay_ms;
4546}
4547
4548int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4550 "Channel::GetPlayoutTimestamp()");
4551 if (playout_timestamp_rtp_ == 0) {
4552 _engineStatisticsPtr->SetLastError(
4553 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4554 "GetPlayoutTimestamp() failed to retrieve timestamp");
4555 return -1;
4556 }
4557 timestamp = playout_timestamp_rtp_;
4558 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4559 VoEId(_instanceId,_channelId),
4560 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4561 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004562}
4563
4564int
4565Channel::SetInitTimestamp(unsigned int timestamp)
4566{
4567 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4568 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004569 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004570 {
4571 _engineStatisticsPtr->SetLastError(
4572 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4573 return -1;
4574 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004575 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004576 {
4577 _engineStatisticsPtr->SetLastError(
4578 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4579 "SetInitTimestamp() failed to set timestamp");
4580 return -1;
4581 }
4582 return 0;
4583}
4584
4585int
4586Channel::SetInitSequenceNumber(short sequenceNumber)
4587{
4588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4589 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004590 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004591 {
4592 _engineStatisticsPtr->SetLastError(
4593 VE_SENDING, kTraceError,
4594 "SetInitSequenceNumber() already sending");
4595 return -1;
4596 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004597 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004598 {
4599 _engineStatisticsPtr->SetLastError(
4600 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4601 "SetInitSequenceNumber() failed to set sequence number");
4602 return -1;
4603 }
4604 return 0;
4605}
4606
4607int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004608Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004609{
4610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4611 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004612 *rtpRtcpModule = _rtpRtcpModule.get();
4613 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004614 return 0;
4615}
4616
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004617// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4618// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004619int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004620Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004621{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004622 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004623 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004624
4625 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004626 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004627
4628 if (_inputFilePlayerPtr == NULL)
4629 {
4630 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4631 VoEId(_instanceId, _channelId),
4632 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4633 " doesnt exist");
4634 return -1;
4635 }
4636
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004637 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004638 fileSamples,
4639 mixingFrequency) == -1)
4640 {
4641 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4642 VoEId(_instanceId, _channelId),
4643 "Channel::MixOrReplaceAudioWithFile() file mixing "
4644 "failed");
4645 return -1;
4646 }
4647 if (fileSamples == 0)
4648 {
4649 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4650 VoEId(_instanceId, _channelId),
4651 "Channel::MixOrReplaceAudioWithFile() file is ended");
4652 return 0;
4653 }
4654 }
4655
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004656 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004657
4658 if (_mixFileWithMicrophone)
4659 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004660 // Currently file stream is always mono.
4661 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004662 MixWithSat(_audioFrame.data_,
4663 _audioFrame.num_channels_,
4664 fileBuffer.get(),
4665 1,
4666 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004667 }
4668 else
4669 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004670 // Replace ACM audio with file.
4671 // Currently file stream is always mono.
4672 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004673 _audioFrame.UpdateFrame(_channelId,
4674 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004675 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004676 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004677 mixingFrequency,
4678 AudioFrame::kNormalSpeech,
4679 AudioFrame::kVadUnknown,
4680 1);
4681
4682 }
4683 return 0;
4684}
4685
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004686int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004687Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004688 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004689{
4690 assert(mixingFrequency <= 32000);
4691
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004692 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004693 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004694
4695 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004696 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004697
4698 if (_outputFilePlayerPtr == NULL)
4699 {
4700 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4701 VoEId(_instanceId, _channelId),
4702 "Channel::MixAudioWithFile() file mixing failed");
4703 return -1;
4704 }
4705
4706 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004707 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004708 fileSamples,
4709 mixingFrequency) == -1)
4710 {
4711 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4712 VoEId(_instanceId, _channelId),
4713 "Channel::MixAudioWithFile() file mixing failed");
4714 return -1;
4715 }
4716 }
4717
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004718 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004719 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004720 // Currently file stream is always mono.
4721 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004722 MixWithSat(audioFrame.data_,
4723 audioFrame.num_channels_,
4724 fileBuffer.get(),
4725 1,
4726 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004727 }
4728 else
4729 {
4730 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004731 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004732 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004733 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004734 return -1;
4735 }
4736
4737 return 0;
4738}
4739
4740int
4741Channel::InsertInbandDtmfTone()
4742{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004743 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004744 if (_inbandDtmfQueue.PendingDtmf() &&
4745 !_inbandDtmfGenerator.IsAddingTone() &&
4746 _inbandDtmfGenerator.DelaySinceLastTone() >
4747 kMinTelephoneEventSeparationMs)
4748 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004749 int8_t eventCode(0);
4750 uint16_t lengthMs(0);
4751 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004752
4753 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4754 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4755 if (_playInbandDtmfEvent)
4756 {
4757 // Add tone to output mixer using a reduced length to minimize
4758 // risk of echo.
4759 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4760 attenuationDb);
4761 }
4762 }
4763
4764 if (_inbandDtmfGenerator.IsAddingTone())
4765 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004766 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004767 _inbandDtmfGenerator.GetSampleRate(frequency);
4768
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004769 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004770 {
4771 // Update sample rate of Dtmf tone since the mixing frequency
4772 // has changed.
4773 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004774 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004775 // Reset the tone to be added taking the new sample rate into
4776 // account.
4777 _inbandDtmfGenerator.ResetTone();
4778 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004779
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004780 int16_t toneBuffer[320];
4781 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004782 // Get 10ms tone segment and set time since last tone to zero
4783 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4784 {
4785 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4786 VoEId(_instanceId, _channelId),
4787 "Channel::EncodeAndSend() inserting Dtmf failed");
4788 return -1;
4789 }
4790
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004791 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004792 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004793 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004794 sample++)
4795 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004796 for (int channel = 0;
4797 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004798 channel++)
4799 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004800 const int index = sample * _audioFrame.num_channels_ + channel;
4801 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004802 }
4803 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004804
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004805 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004806 } else
4807 {
4808 // Add 10ms to "delay-since-last-tone" counter
4809 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4810 }
4811 return 0;
4812}
4813
niklase@google.com470e71d2011-07-07 08:21:25 +00004814void
4815Channel::ResetDeadOrAliveCounters()
4816{
4817 _countDeadDetections = 0;
4818 _countAliveDetections = 0;
4819}
4820
4821void
4822Channel::UpdateDeadOrAliveCounters(bool alive)
4823{
4824 if (alive)
4825 _countAliveDetections++;
4826 else
4827 _countDeadDetections++;
4828}
4829
4830int
4831Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
4832{
niklase@google.com470e71d2011-07-07 08:21:25 +00004833 return 0;
4834}
4835
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004836int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004837Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4838{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004839 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004840 if (_transportPtr == NULL)
4841 {
4842 return -1;
4843 }
4844 if (!RTCP)
4845 {
4846 return _transportPtr->SendPacket(_channelId, data, len);
4847 }
4848 else
4849 {
4850 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4851 }
4852}
4853
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004854// Called for incoming RTP packets after successful RTP header parsing.
4855void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4856 uint16_t sequence_number) {
4857 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4858 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4859 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004860
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004861 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004862 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004863
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004864 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004865 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004866 return;
4867 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004868
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004869 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004870 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004871
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004872 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4873 // Even though the actual sampling rate for G.722 audio is
4874 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4875 // 8,000 Hz because that value was erroneously assigned in
4876 // RFC 1890 and must remain unchanged for backward compatibility.
4877 rtp_receive_frequency = 8000;
4878 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4879 // We are resampling Opus internally to 32,000 Hz until all our
4880 // DSP routines can operate at 48,000 Hz, but the RTP clock
4881 // rate for the Opus payload format is standardized to 48,000 Hz,
4882 // because that is the maximum supported decoding sampling rate.
4883 rtp_receive_frequency = 48000;
4884 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004885
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004886 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4887 // every incoming packet.
4888 uint32_t timestamp_diff_ms = (rtp_timestamp -
4889 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004890 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4891 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4892 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4893 // timestamp, the resulting difference is negative, but is set to zero.
4894 // This can happen when a network glitch causes a packet to arrive late,
4895 // and during long comfort noise periods with clock drift.
4896 timestamp_diff_ms = 0;
4897 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004898
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004899 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4900 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004901
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004902 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004903
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004904 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004905
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004906 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4907 _recPacketDelayMs = packet_delay_ms;
4908 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004909
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004910 if (_average_jitter_buffer_delay_us == 0) {
4911 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4912 return;
4913 }
4914
4915 // Filter average delay value using exponential filter (alpha is
4916 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4917 // risk of rounding error) and compensate for it in GetDelayEstimate()
4918 // later.
4919 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4920 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004921}
4922
4923void
4924Channel::RegisterReceiveCodecsToRTPModule()
4925{
4926 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4927 "Channel::RegisterReceiveCodecsToRTPModule()");
4928
4929
4930 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004931 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004932
4933 for (int idx = 0; idx < nSupportedCodecs; idx++)
4934 {
4935 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004936 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004937 (rtp_receiver_->RegisterReceivePayload(
4938 codec.plname,
4939 codec.pltype,
4940 codec.plfreq,
4941 codec.channels,
4942 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004943 {
4944 WEBRTC_TRACE(
4945 kTraceWarning,
4946 kTraceVoice,
4947 VoEId(_instanceId, _channelId),
4948 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4949 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4950 codec.plname, codec.pltype, codec.plfreq,
4951 codec.channels, codec.rate);
4952 }
4953 else
4954 {
4955 WEBRTC_TRACE(
4956 kTraceInfo,
4957 kTraceVoice,
4958 VoEId(_instanceId, _channelId),
4959 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004960 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004961 "receiver",
4962 codec.plname, codec.pltype, codec.plfreq,
4963 codec.channels, codec.rate);
4964 }
4965 }
4966}
4967
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004968int Channel::SetSecondarySendCodec(const CodecInst& codec,
4969 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004970 // Sanity check for payload type.
4971 if (red_payload_type < 0 || red_payload_type > 127) {
4972 _engineStatisticsPtr->SetLastError(
4973 VE_PLTYPE_ERROR, kTraceError,
4974 "SetRedPayloadType() invalid RED payload type");
4975 return -1;
4976 }
4977
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004978 if (SetRedPayloadType(red_payload_type) < 0) {
4979 _engineStatisticsPtr->SetLastError(
4980 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4981 "SetSecondarySendCodec() Failed to register RED ACM");
4982 return -1;
4983 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004984 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004985 _engineStatisticsPtr->SetLastError(
4986 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4987 "SetSecondarySendCodec() Failed to register secondary send codec in "
4988 "ACM");
4989 return -1;
4990 }
4991
4992 return 0;
4993}
4994
4995void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004996 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004997}
4998
4999int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005000 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005001 _engineStatisticsPtr->SetLastError(
5002 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5003 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5004 return -1;
5005 }
5006 return 0;
5007}
5008
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005009// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005010int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005011 CodecInst codec;
5012 bool found_red = false;
5013
5014 // Get default RED settings from the ACM database
5015 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5016 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005017 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005018 if (!STR_CASE_CMP(codec.plname, "RED")) {
5019 found_red = true;
5020 break;
5021 }
5022 }
5023
5024 if (!found_red) {
5025 _engineStatisticsPtr->SetLastError(
5026 VE_CODEC_ERROR, kTraceError,
5027 "SetRedPayloadType() RED is not supported");
5028 return -1;
5029 }
5030
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005031 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005032 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005033 _engineStatisticsPtr->SetLastError(
5034 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5035 "SetRedPayloadType() RED registration in ACM module failed");
5036 return -1;
5037 }
5038
5039 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5040 _engineStatisticsPtr->SetLastError(
5041 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5042 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5043 return -1;
5044 }
5045 return 0;
5046}
5047
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00005048int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
5049 unsigned char id) {
5050 int error = 0;
5051 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
5052 if (enable) {
5053 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
5054 }
5055 return error;
5056}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005057} // namespace voe
5058} // namespace webrtc