blob: 4f310d36e2c81797fc4cfb0eb1f48692483f3c71 [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
niklase@google.com470e71d2011-07-07 08:21:25 +0000505 // Send callback to the registered observer
506 if (_connectionObserver)
507 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000508 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 if (_connectionObserverPtr)
510 {
511 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
512 }
513 }
514}
515
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000516int32_t
517Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000518 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 const WebRtcRTPHeader* rtpHeader)
520{
521 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
522 "Channel::OnReceivedPayloadData(payloadSize=%d,"
523 " payloadType=%u, audioChannel=%u)",
524 payloadSize,
525 rtpHeader->header.payloadType,
526 rtpHeader->type.Audio.channel);
527
roosa@google.com0870f022012-12-12 21:31:41 +0000528 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
529
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000530 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 {
532 // Avoid inserting into NetEQ when we are not playing. Count the
533 // packet as discarded.
534 WEBRTC_TRACE(kTraceStream, kTraceVoice,
535 VoEId(_instanceId, _channelId),
536 "received packet is discarded since playing is not"
537 " activated");
538 _numberOfDiscardedPackets++;
539 return 0;
540 }
541
542 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000543 if (audio_coding_->IncomingPacket(payloadData,
544 payloadSize,
545 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 {
547 _engineStatisticsPtr->SetLastError(
548 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
549 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
550 return -1;
551 }
552
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000553 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 UpdatePacketDelay(rtpHeader->header.timestamp,
555 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000556
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000557 uint16_t round_trip_time = 0;
558 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
559 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000560
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000561 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000562 round_trip_time);
563 if (!nack_list.empty()) {
564 // Can't use nack_list.data() since it's not supported by all
565 // compilers.
566 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000567 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 return 0;
569}
570
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000571bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
572 int rtp_packet_length) {
573 RTPHeader header;
574 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
575 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
576 "IncomingPacket invalid RTP header");
577 return false;
578 }
579 header.payload_type_frequency =
580 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
581 if (header.payload_type_frequency < 0)
582 return false;
583 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
584}
585
pbos@webrtc.org92135212013-05-14 08:31:39 +0000586int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000587{
588 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
589 "Channel::GetAudioFrame(id=%d)", id);
590
591 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000592 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
593 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 {
595 WEBRTC_TRACE(kTraceError, kTraceVoice,
596 VoEId(_instanceId,_channelId),
597 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000598 // In all likelihood, the audio in this frame is garbage. We return an
599 // error so that the audio mixer module doesn't add it to the mix. As
600 // a result, it won't be played out and the actions skipped here are
601 // irrelevant.
602 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 }
604
605 if (_RxVadDetection)
606 {
607 UpdateRxVadDetection(audioFrame);
608 }
609
610 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000611 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000613 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000615 ChannelState::State state = channel_state_.Get();
616
617 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000618 int err = rx_audioproc_->ProcessStream(&audioFrame);
619 if (err) {
620 LOG(LS_ERROR) << "ProcessStream() error: " << err;
621 assert(false);
622 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 }
624
wu@webrtc.org63420662013-10-17 18:28:55 +0000625 float output_gain = 1.0f;
626 float left_pan = 1.0f;
627 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000629 CriticalSectionScoped cs(&volume_settings_critsect_);
630 output_gain = _outputGain;
631 left_pan = _panLeft;
632 right_pan= _panRight;
633 }
634
635 // Output volume scaling
636 if (output_gain < 0.99f || output_gain > 1.01f)
637 {
638 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 }
640
641 // Scale left and/or right channel(s) if stereo and master balance is
642 // active
643
wu@webrtc.org63420662013-10-17 18:28:55 +0000644 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000646 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 {
648 // Emulate stereo mode since panning is active.
649 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000650 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 }
652 // For true stereo mode (when we are receiving a stereo signal), no
653 // action is needed.
654
655 // Do the panning operation (the audio frame contains stereo at this
656 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000657 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 }
659
660 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000661 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000663 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 }
665
666 // Place channel in on-hold state (~muted) if on-hold is activated
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000667 if (state.output_is_on_hold)
niklase@google.com470e71d2011-07-07 08:21:25 +0000668 {
669 AudioFrameOperations::Mute(audioFrame);
670 }
671
672 // External media
673 if (_outputExternalMedia)
674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000675 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000676 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 if (_outputExternalMediaCallbackPtr)
678 {
679 _outputExternalMediaCallbackPtr->Process(
680 _channelId,
681 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000682 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000683 audioFrame.samples_per_channel_,
684 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 isStereo);
686 }
687 }
688
689 // Record playout if enabled
690 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000691 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000692
693 if (_outputFileRecording && _outputFileRecorderPtr)
694 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000695 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 }
697 }
698
699 // Measure audio level (0-9)
700 _outputAudioLevel.ComputeLevel(audioFrame);
701
702 return 0;
703}
704
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000705int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000706Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000707{
708 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
709 "Channel::NeededFrequency(id=%d)", id);
710
711 int highestNeeded = 0;
712
713 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000714 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000715
716 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000717 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000719 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
721 else
722 {
723 highestNeeded = receiveFrequency;
724 }
725
726 // Special case, if we're playing a file on the playout side
727 // we take that frequency into consideration as well
728 // This is not needed on sending side, since the codec will
729 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000730 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000732 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000733 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 {
735 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
736 {
737 highestNeeded=_outputFilePlayerPtr->Frequency();
738 }
739 }
740 }
741
742 return(highestNeeded);
743}
744
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000745int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000746Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000747 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000748 uint32_t instanceId,
749 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000750{
751 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
752 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
753 channelId, instanceId);
754
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000755 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 if (channel == NULL)
757 {
758 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
759 VoEId(instanceId,channelId),
760 "Channel::CreateChannel() unable to allocate memory for"
761 " channel");
762 return -1;
763 }
764 return 0;
765}
766
767void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000768Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000769{
770 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
771 "Channel::PlayNotification(id=%d, durationMs=%d)",
772 id, durationMs);
773
774 // Not implement yet
775}
776
777void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000778Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000779{
780 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
781 "Channel::RecordNotification(id=%d, durationMs=%d)",
782 id, durationMs);
783
784 // Not implement yet
785}
786
787void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000788Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000789{
790 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
791 "Channel::PlayFileEnded(id=%d)", id);
792
793 if (id == _inputFilePlayerId)
794 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000795 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
797 VoEId(_instanceId,_channelId),
798 "Channel::PlayFileEnded() => input file player module is"
799 " shutdown");
800 }
801 else if (id == _outputFilePlayerId)
802 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000803 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
805 VoEId(_instanceId,_channelId),
806 "Channel::PlayFileEnded() => output file player module is"
807 " shutdown");
808 }
809}
810
811void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000812Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000813{
814 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
815 "Channel::RecordFileEnded(id=%d)", id);
816
817 assert(id == _outputFileRecorderId);
818
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000819 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000820
821 _outputFileRecording = false;
822 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
823 VoEId(_instanceId,_channelId),
824 "Channel::RecordFileEnded() => output file recorder module is"
825 " shutdown");
826}
827
pbos@webrtc.org92135212013-05-14 08:31:39 +0000828Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000829 uint32_t instanceId,
830 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000831 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
832 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000833 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000834 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000835 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000836 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000837 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000838 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000839 rtp_receive_statistics_(ReceiveStatistics::Create(
840 Clock::GetRealTimeClock())),
841 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
842 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
843 this, this, rtp_payload_registry_.get())),
844 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000845 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000846 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000847 _rtpDumpIn(*RtpDump::CreateRtpDump()),
848 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000851 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 _inputFilePlayerPtr(NULL),
853 _outputFilePlayerPtr(NULL),
854 _outputFileRecorderPtr(NULL),
855 // Avoid conflict with other channels by adding 1024 - 1026,
856 // won't use as much as 1024 channels.
857 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
858 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
859 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000860 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000861 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
862 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000863 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 _inputExternalMediaCallbackPtr(NULL),
865 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000866 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
867 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000868 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000869 playout_timestamp_rtp_(0),
870 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000871 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000872 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000873 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000874 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000875 _outputMixerPtr(NULL),
876 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _moduleProcessThreadPtr(NULL),
878 _audioDeviceModulePtr(NULL),
879 _voiceEngineObserverPtr(NULL),
880 _callbackCritSectPtr(NULL),
881 _transportPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000882 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000883 _rxVadObserverPtr(NULL),
884 _oldVadDecision(-1),
885 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 _rtpObserverPtr(NULL),
887 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000888 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000889 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000890 _inputIsOnHold(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000891 _mixFileWithMicrophone(false),
892 _rtpObserver(false),
893 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000894 _mute(false),
895 _panLeft(1.0f),
896 _panRight(1.0f),
897 _outputGain(1.0f),
898 _playOutbandDtmfEvent(false),
899 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000901 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000903 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _rtpPacketTimedOut(false),
905 _rtpPacketTimeOutIsEnabled(false),
906 _rtpTimeOutSeconds(0),
907 _connectionObserver(false),
908 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000910 vie_network_(NULL),
911 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000912 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000913 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 _previousTimestamp(0),
915 _recPacketDelayMs(20),
916 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000918 _rxNsIsEnabled(false),
919 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000920{
921 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
922 "Channel::Channel() - ctor");
923 _inbandDtmfQueue.ResetDtmf();
924 _inbandDtmfGenerator.Init();
925 _outputAudioLevel.Clear();
926
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000927 RtpRtcp::Configuration configuration;
928 configuration.id = VoEModuleId(instanceId, channelId);
929 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000930 configuration.outgoing_transport = this;
931 configuration.rtcp_feedback = this;
932 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000933 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000934
935 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000936
937 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
938 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
939 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000940}
941
942Channel::~Channel()
943{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000944 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000945 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
946 "Channel::~Channel() - dtor");
947
948 if (_outputExternalMedia)
949 {
950 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
951 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000952 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 {
954 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
955 }
956 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000957 StopPlayout();
958
959 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000960 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000961 if (_inputFilePlayerPtr)
962 {
963 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
964 _inputFilePlayerPtr->StopPlayingFile();
965 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
966 _inputFilePlayerPtr = NULL;
967 }
968 if (_outputFilePlayerPtr)
969 {
970 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
971 _outputFilePlayerPtr->StopPlayingFile();
972 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
973 _outputFilePlayerPtr = NULL;
974 }
975 if (_outputFileRecorderPtr)
976 {
977 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
978 _outputFileRecorderPtr->StopRecording();
979 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
980 _outputFileRecorderPtr = NULL;
981 }
982 }
983
984 // The order to safely shutdown modules in a channel is:
985 // 1. De-register callbacks in modules
986 // 2. De-register modules in process thread
987 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000988 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000989 {
990 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
991 VoEId(_instanceId,_channelId),
992 "~Channel() failed to de-register transport callback"
993 " (Audio coding module)");
994 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000995 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 {
997 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
998 VoEId(_instanceId,_channelId),
999 "~Channel() failed to de-register VAD callback"
1000 " (Audio coding module)");
1001 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001002 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001003 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 {
1005 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1006 VoEId(_instanceId,_channelId),
1007 "~Channel() failed to deregister RTP/RTCP module");
1008 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001009 // End of modules shutdown
1010
1011 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001012 if (vie_network_) {
1013 vie_network_->Release();
1014 vie_network_ = NULL;
1015 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001016 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1017 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001018 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001020 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001021}
1022
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001023int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001024Channel::Init()
1025{
1026 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1027 "Channel::Init()");
1028
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001029 channel_state_.Reset();
1030
niklase@google.com470e71d2011-07-07 08:21:25 +00001031 // --- Initial sanity
1032
1033 if ((_engineStatisticsPtr == NULL) ||
1034 (_moduleProcessThreadPtr == NULL))
1035 {
1036 WEBRTC_TRACE(kTraceError, kTraceVoice,
1037 VoEId(_instanceId,_channelId),
1038 "Channel::Init() must call SetEngineInformation() first");
1039 return -1;
1040 }
1041
1042 // --- Add modules to process thread (for periodic schedulation)
1043
1044 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001045 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 if (processThreadFail)
1048 {
1049 _engineStatisticsPtr->SetLastError(
1050 VE_CANNOT_INIT_CHANNEL, kTraceError,
1051 "Channel::Init() modules not registered");
1052 return -1;
1053 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001054 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001055
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001056 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001057#ifdef WEBRTC_CODEC_AVT
1058 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001059 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001060#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001061 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 {
1063 _engineStatisticsPtr->SetLastError(
1064 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1065 "Channel::Init() unable to initialize the ACM - 1");
1066 return -1;
1067 }
1068
1069 // --- RTP/RTCP module initialization
1070
1071 // Ensure that RTCP is enabled by default for the created channel.
1072 // Note that, the module will keep generating RTCP until it is explicitly
1073 // disabled by the user.
1074 // After StopListen (when no sockets exists), RTCP packets will no longer
1075 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001076 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1077 // RTCP is enabled by default.
1078 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 {
1080 _engineStatisticsPtr->SetLastError(
1081 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1082 "Channel::Init() RTP/RTCP module not initialized");
1083 return -1;
1084 }
1085
1086 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001087 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001088 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1089 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001090
1091 if (fail)
1092 {
1093 _engineStatisticsPtr->SetLastError(
1094 VE_CANNOT_INIT_CHANNEL, kTraceError,
1095 "Channel::Init() callbacks not registered");
1096 return -1;
1097 }
1098
1099 // --- Register all supported codecs to the receiving side of the
1100 // RTP/RTCP module
1101
1102 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001103 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001104
1105 for (int idx = 0; idx < nSupportedCodecs; idx++)
1106 {
1107 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001108 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001109 (rtp_receiver_->RegisterReceivePayload(
1110 codec.plname,
1111 codec.pltype,
1112 codec.plfreq,
1113 codec.channels,
1114 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 {
1116 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1117 VoEId(_instanceId,_channelId),
1118 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1119 "to RTP/RTCP receiver",
1120 codec.plname, codec.pltype, codec.plfreq,
1121 codec.channels, codec.rate);
1122 }
1123 else
1124 {
1125 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1126 VoEId(_instanceId,_channelId),
1127 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1128 "the RTP/RTCP receiver",
1129 codec.plname, codec.pltype, codec.plfreq,
1130 codec.channels, codec.rate);
1131 }
1132
1133 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001134 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001135 {
1136 SetSendCodec(codec);
1137 }
1138
1139 // Register default PT for outband 'telephone-event'
1140 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1141 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001142 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001143 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001144 {
1145 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1146 VoEId(_instanceId,_channelId),
1147 "Channel::Init() failed to register outband "
1148 "'telephone-event' (%d/%d) correctly",
1149 codec.pltype, codec.plfreq);
1150 }
1151 }
1152
1153 if (!STR_CASE_CMP(codec.plname, "CN"))
1154 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001155 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1156 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001157 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 {
1159 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1160 VoEId(_instanceId,_channelId),
1161 "Channel::Init() failed to register CN (%d/%d) "
1162 "correctly - 1",
1163 codec.pltype, codec.plfreq);
1164 }
1165 }
1166#ifdef WEBRTC_CODEC_RED
1167 // Register RED to the receiving side of the ACM.
1168 // We will not receive an OnInitializeDecoder() callback for RED.
1169 if (!STR_CASE_CMP(codec.plname, "RED"))
1170 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001171 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 {
1173 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1174 VoEId(_instanceId,_channelId),
1175 "Channel::Init() failed to register RED (%d/%d) "
1176 "correctly",
1177 codec.pltype, codec.plfreq);
1178 }
1179 }
1180#endif
1181 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001182
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001183 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1184 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1185 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001186 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001187 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1188 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1189 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 }
1191
1192 return 0;
1193}
1194
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001195int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001196Channel::SetEngineInformation(Statistics& engineStatistics,
1197 OutputMixer& outputMixer,
1198 voe::TransmitMixer& transmitMixer,
1199 ProcessThread& moduleProcessThread,
1200 AudioDeviceModule& audioDeviceModule,
1201 VoiceEngineObserver* voiceEngineObserver,
1202 CriticalSectionWrapper* callbackCritSect)
1203{
1204 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1205 "Channel::SetEngineInformation()");
1206 _engineStatisticsPtr = &engineStatistics;
1207 _outputMixerPtr = &outputMixer;
1208 _transmitMixerPtr = &transmitMixer,
1209 _moduleProcessThreadPtr = &moduleProcessThread;
1210 _audioDeviceModulePtr = &audioDeviceModule;
1211 _voiceEngineObserverPtr = voiceEngineObserver;
1212 _callbackCritSectPtr = callbackCritSect;
1213 return 0;
1214}
1215
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001216int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001217Channel::UpdateLocalTimeStamp()
1218{
1219
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001220 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001221 return 0;
1222}
1223
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001224int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001225Channel::StartPlayout()
1226{
1227 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1228 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001229 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 {
1231 return 0;
1232 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001233
1234 if (!_externalMixing) {
1235 // Add participant as candidates for mixing.
1236 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1237 {
1238 _engineStatisticsPtr->SetLastError(
1239 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1240 "StartPlayout() failed to add participant to mixer");
1241 return -1;
1242 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 }
1244
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001245 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001246 if (RegisterFilePlayingToMixer() != 0)
1247 return -1;
1248
niklase@google.com470e71d2011-07-07 08:21:25 +00001249 return 0;
1250}
1251
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001252int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001253Channel::StopPlayout()
1254{
1255 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1256 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001257 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 {
1259 return 0;
1260 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001261
1262 if (!_externalMixing) {
1263 // Remove participant as candidates for mixing
1264 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1265 {
1266 _engineStatisticsPtr->SetLastError(
1267 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1268 "StopPlayout() failed to remove participant from mixer");
1269 return -1;
1270 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 }
1272
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001273 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 _outputAudioLevel.Clear();
1275
1276 return 0;
1277}
1278
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001279int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001280Channel::StartSend()
1281{
1282 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1283 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001284 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001285 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001286 if (send_sequence_number_)
1287 SetInitSequenceNumber(send_sequence_number_);
1288
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001289 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001290 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001291 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001292 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001293 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001294
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001295 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001296 {
1297 _engineStatisticsPtr->SetLastError(
1298 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1299 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001300 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001301 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 return -1;
1303 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001304
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 return 0;
1306}
1307
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001308int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001309Channel::StopSend()
1310{
1311 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1312 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001313 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001315 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001316 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001317 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001318
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001319 // Store the sequence number to be able to pick up the same sequence for
1320 // the next StartSend(). This is needed for restarting device, otherwise
1321 // it might cause libSRTP to complain about packets being replayed.
1322 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1323 // CL is landed. See issue
1324 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1325 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1326
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 // Reset sending SSRC and sequence number and triggers direct transmission
1328 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001329 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1330 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001331 {
1332 _engineStatisticsPtr->SetLastError(
1333 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1334 "StartSend() RTP/RTCP failed to stop sending");
1335 }
1336
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 return 0;
1338}
1339
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001340int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001341Channel::StartReceiving()
1342{
1343 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1344 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001345 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001346 {
1347 return 0;
1348 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001349 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 _numberOfDiscardedPackets = 0;
1351 return 0;
1352}
1353
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001354int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001355Channel::StopReceiving()
1356{
1357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1358 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001359 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001360 {
1361 return 0;
1362 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001363
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001364 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001365 return 0;
1366}
1367
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001368int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001369Channel::SetNetEQPlayoutMode(NetEqModes mode)
1370{
1371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1372 "Channel::SetNetEQPlayoutMode()");
1373 AudioPlayoutMode playoutMode(voice);
1374 switch (mode)
1375 {
1376 case kNetEqDefault:
1377 playoutMode = voice;
1378 break;
1379 case kNetEqStreaming:
1380 playoutMode = streaming;
1381 break;
1382 case kNetEqFax:
1383 playoutMode = fax;
1384 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001385 case kNetEqOff:
1386 playoutMode = off;
1387 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001389 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 {
1391 _engineStatisticsPtr->SetLastError(
1392 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1393 "SetNetEQPlayoutMode() failed to set playout mode");
1394 return -1;
1395 }
1396 return 0;
1397}
1398
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001399int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001400Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1401{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001402 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 switch (playoutMode)
1404 {
1405 case voice:
1406 mode = kNetEqDefault;
1407 break;
1408 case streaming:
1409 mode = kNetEqStreaming;
1410 break;
1411 case fax:
1412 mode = kNetEqFax;
1413 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001414 case off:
1415 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 }
1417 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1418 VoEId(_instanceId,_channelId),
1419 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1420 return 0;
1421}
1422
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001423int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001424Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1425{
1426 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1427 "Channel::SetOnHoldStatus()");
1428 if (mode == kHoldSendAndPlay)
1429 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001430 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 _inputIsOnHold = enable;
1432 }
1433 else if (mode == kHoldPlayOnly)
1434 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001435 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001436 }
1437 if (mode == kHoldSendOnly)
1438 {
1439 _inputIsOnHold = enable;
1440 }
1441 return 0;
1442}
1443
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001445Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1446{
1447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1448 "Channel::GetOnHoldStatus()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001449 bool output_is_on_hold = channel_state_.Get().output_is_on_hold;
1450 enabled = (output_is_on_hold || _inputIsOnHold);
1451 if (output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
1453 mode = kHoldSendAndPlay;
1454 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001455 else if (output_is_on_hold && !_inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001456 {
1457 mode = kHoldPlayOnly;
1458 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001459 else if (!output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001460 {
1461 mode = kHoldSendOnly;
1462 }
1463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1464 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1465 enabled, mode);
1466 return 0;
1467}
1468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001469int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001470Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1471{
1472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1473 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001474 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001475
1476 if (_voiceEngineObserverPtr)
1477 {
1478 _engineStatisticsPtr->SetLastError(
1479 VE_INVALID_OPERATION, kTraceError,
1480 "RegisterVoiceEngineObserver() observer already enabled");
1481 return -1;
1482 }
1483 _voiceEngineObserverPtr = &observer;
1484 return 0;
1485}
1486
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001487int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001488Channel::DeRegisterVoiceEngineObserver()
1489{
1490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1491 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001492 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001493
1494 if (!_voiceEngineObserverPtr)
1495 {
1496 _engineStatisticsPtr->SetLastError(
1497 VE_INVALID_OPERATION, kTraceWarning,
1498 "DeRegisterVoiceEngineObserver() observer already disabled");
1499 return 0;
1500 }
1501 _voiceEngineObserverPtr = NULL;
1502 return 0;
1503}
1504
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001505int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001506Channel::GetSendCodec(CodecInst& codec)
1507{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001508 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001509}
1510
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001511int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001512Channel::GetRecCodec(CodecInst& codec)
1513{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001514 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001515}
1516
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001517int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001518Channel::SetSendCodec(const CodecInst& codec)
1519{
1520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1521 "Channel::SetSendCodec()");
1522
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001523 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
1525 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "SetSendCodec() failed to register codec to ACM");
1527 return -1;
1528 }
1529
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001530 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001532 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1533 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
1535 WEBRTC_TRACE(
1536 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1537 "SetSendCodec() failed to register codec to"
1538 " RTP/RTCP module");
1539 return -1;
1540 }
1541 }
1542
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001543 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001544 {
1545 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1546 "SetSendCodec() failed to set audio packet size");
1547 return -1;
1548 }
1549
1550 return 0;
1551}
1552
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001553int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001554Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1555{
1556 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1557 "Channel::SetVADStatus(mode=%d)", mode);
1558 // To disable VAD, DTX must be disabled too
1559 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001560 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001561 {
1562 _engineStatisticsPtr->SetLastError(
1563 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1564 "SetVADStatus() failed to set VAD");
1565 return -1;
1566 }
1567 return 0;
1568}
1569
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001571Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1572{
1573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001575 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001576 {
1577 _engineStatisticsPtr->SetLastError(
1578 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1579 "GetVADStatus() failed to get VAD status");
1580 return -1;
1581 }
1582 disabledDTX = !disabledDTX;
1583 return 0;
1584}
1585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001586int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001587Channel::SetRecPayloadType(const CodecInst& codec)
1588{
1589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590 "Channel::SetRecPayloadType()");
1591
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001592 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001593 {
1594 _engineStatisticsPtr->SetLastError(
1595 VE_ALREADY_PLAYING, kTraceError,
1596 "SetRecPayloadType() unable to set PT while playing");
1597 return -1;
1598 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001599 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001600 {
1601 _engineStatisticsPtr->SetLastError(
1602 VE_ALREADY_LISTENING, kTraceError,
1603 "SetRecPayloadType() unable to set PT while listening");
1604 return -1;
1605 }
1606
1607 if (codec.pltype == -1)
1608 {
1609 // De-register the selected codec (RTP/RTCP module and ACM)
1610
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001611 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001612 CodecInst rxCodec = codec;
1613
1614 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001615 rtp_payload_registry_->ReceivePayloadType(
1616 rxCodec.plname,
1617 rxCodec.plfreq,
1618 rxCodec.channels,
1619 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1620 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 rxCodec.pltype = pltype;
1622
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001623 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001624 {
1625 _engineStatisticsPtr->SetLastError(
1626 VE_RTP_RTCP_MODULE_ERROR,
1627 kTraceError,
1628 "SetRecPayloadType() RTP/RTCP-module deregistration "
1629 "failed");
1630 return -1;
1631 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001632 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001633 {
1634 _engineStatisticsPtr->SetLastError(
1635 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1636 "SetRecPayloadType() ACM deregistration failed - 1");
1637 return -1;
1638 }
1639 return 0;
1640 }
1641
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001642 if (rtp_receiver_->RegisterReceivePayload(
1643 codec.plname,
1644 codec.pltype,
1645 codec.plfreq,
1646 codec.channels,
1647 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001648 {
1649 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001650 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1651 if (rtp_receiver_->RegisterReceivePayload(
1652 codec.plname,
1653 codec.pltype,
1654 codec.plfreq,
1655 codec.channels,
1656 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001657 {
1658 _engineStatisticsPtr->SetLastError(
1659 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1660 "SetRecPayloadType() RTP/RTCP-module registration failed");
1661 return -1;
1662 }
1663 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001664 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001665 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001666 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1667 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 {
1669 _engineStatisticsPtr->SetLastError(
1670 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1671 "SetRecPayloadType() ACM registration failed - 1");
1672 return -1;
1673 }
1674 }
1675 return 0;
1676}
1677
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001678int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001679Channel::GetRecPayloadType(CodecInst& codec)
1680{
1681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1682 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001683 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001684 if (rtp_payload_registry_->ReceivePayloadType(
1685 codec.plname,
1686 codec.plfreq,
1687 codec.channels,
1688 (codec.rate < 0) ? 0 : codec.rate,
1689 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001690 {
1691 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001692 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001693 "GetRecPayloadType() failed to retrieve RX payload type");
1694 return -1;
1695 }
1696 codec.pltype = payloadType;
1697 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1698 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1699 return 0;
1700}
1701
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001702int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001703Channel::SetAMREncFormat(AmrMode mode)
1704{
1705 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1706 "Channel::SetAMREncFormat()");
1707
1708 // ACM doesn't support AMR
1709 return -1;
1710}
1711
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001712int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001713Channel::SetAMRDecFormat(AmrMode mode)
1714{
1715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1716 "Channel::SetAMRDecFormat()");
1717
1718 // ACM doesn't support AMR
1719 return -1;
1720}
1721
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001722int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001723Channel::SetAMRWbEncFormat(AmrMode mode)
1724{
1725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726 "Channel::SetAMRWbEncFormat()");
1727
1728 // ACM doesn't support AMR
1729 return -1;
1730
1731}
1732
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001733int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001734Channel::SetAMRWbDecFormat(AmrMode mode)
1735{
1736 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1737 "Channel::SetAMRWbDecFormat()");
1738
1739 // ACM doesn't support AMR
1740 return -1;
1741}
1742
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001743int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001744Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1745{
1746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1747 "Channel::SetSendCNPayloadType()");
1748
1749 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001750 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001751 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001752 if (frequency == kFreq32000Hz)
1753 samplingFreqHz = 32000;
1754 else if (frequency == kFreq16000Hz)
1755 samplingFreqHz = 16000;
1756
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001757 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001758 {
1759 _engineStatisticsPtr->SetLastError(
1760 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1761 "SetSendCNPayloadType() failed to retrieve default CN codec "
1762 "settings");
1763 return -1;
1764 }
1765
1766 // Modify the payload type (must be set to dynamic range)
1767 codec.pltype = type;
1768
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001769 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001770 {
1771 _engineStatisticsPtr->SetLastError(
1772 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1773 "SetSendCNPayloadType() failed to register CN to ACM");
1774 return -1;
1775 }
1776
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001777 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001778 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001779 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1780 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 {
1782 _engineStatisticsPtr->SetLastError(
1783 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1784 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1785 "module");
1786 return -1;
1787 }
1788 }
1789 return 0;
1790}
1791
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001792int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001793Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1794{
1795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1796 "Channel::SetISACInitTargetRate()");
1797
1798 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001799 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001800 {
1801 _engineStatisticsPtr->SetLastError(
1802 VE_CODEC_ERROR, kTraceError,
1803 "SetISACInitTargetRate() failed to retrieve send codec");
1804 return -1;
1805 }
1806 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1807 {
1808 // This API is only valid if iSAC is setup to run in channel-adaptive
1809 // mode.
1810 // We do not validate the adaptive mode here. It is done later in the
1811 // ConfigISACBandwidthEstimator() API.
1812 _engineStatisticsPtr->SetLastError(
1813 VE_CODEC_ERROR, kTraceError,
1814 "SetISACInitTargetRate() send codec is not iSAC");
1815 return -1;
1816 }
1817
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001818 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001819 if (16000 == sendCodec.plfreq)
1820 {
1821 // Note that 0 is a valid and corresponds to "use default
1822 if ((rateBps != 0 &&
1823 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1824 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1825 {
1826 _engineStatisticsPtr->SetLastError(
1827 VE_INVALID_ARGUMENT, kTraceError,
1828 "SetISACInitTargetRate() invalid target rate - 1");
1829 return -1;
1830 }
1831 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001832 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001833 }
1834 else if (32000 == sendCodec.plfreq)
1835 {
1836 if ((rateBps != 0 &&
1837 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1838 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1839 {
1840 _engineStatisticsPtr->SetLastError(
1841 VE_INVALID_ARGUMENT, kTraceError,
1842 "SetISACInitTargetRate() invalid target rate - 2");
1843 return -1;
1844 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001845 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001846 }
1847
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001848 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001849 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1850 {
1851 _engineStatisticsPtr->SetLastError(
1852 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1853 "SetISACInitTargetRate() iSAC BWE config failed");
1854 return -1;
1855 }
1856
1857 return 0;
1858}
1859
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001860int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001861Channel::SetISACMaxRate(int rateBps)
1862{
1863 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1864 "Channel::SetISACMaxRate()");
1865
1866 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001867 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_CODEC_ERROR, kTraceError,
1871 "SetISACMaxRate() failed to retrieve send codec");
1872 return -1;
1873 }
1874 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1875 {
1876 // This API is only valid if iSAC is selected as sending codec.
1877 _engineStatisticsPtr->SetLastError(
1878 VE_CODEC_ERROR, kTraceError,
1879 "SetISACMaxRate() send codec is not iSAC");
1880 return -1;
1881 }
1882 if (16000 == sendCodec.plfreq)
1883 {
1884 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1885 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1886 {
1887 _engineStatisticsPtr->SetLastError(
1888 VE_INVALID_ARGUMENT, kTraceError,
1889 "SetISACMaxRate() invalid max rate - 1");
1890 return -1;
1891 }
1892 }
1893 else if (32000 == sendCodec.plfreq)
1894 {
1895 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1896 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1897 {
1898 _engineStatisticsPtr->SetLastError(
1899 VE_INVALID_ARGUMENT, kTraceError,
1900 "SetISACMaxRate() invalid max rate - 2");
1901 return -1;
1902 }
1903 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001904 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_SENDING, kTraceError,
1908 "SetISACMaxRate() unable to set max rate while sending");
1909 return -1;
1910 }
1911
1912 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1913 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001914 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001915 {
1916 _engineStatisticsPtr->SetLastError(
1917 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1918 "SetISACMaxRate() failed to set max rate");
1919 return -1;
1920 }
1921
1922 return 0;
1923}
1924
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001925int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001926Channel::SetISACMaxPayloadSize(int sizeBytes)
1927{
1928 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1929 "Channel::SetISACMaxPayloadSize()");
1930 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001931 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001932 {
1933 _engineStatisticsPtr->SetLastError(
1934 VE_CODEC_ERROR, kTraceError,
1935 "SetISACMaxPayloadSize() failed to retrieve send codec");
1936 return -1;
1937 }
1938 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1939 {
1940 _engineStatisticsPtr->SetLastError(
1941 VE_CODEC_ERROR, kTraceError,
1942 "SetISACMaxPayloadSize() send codec is not iSAC");
1943 return -1;
1944 }
1945 if (16000 == sendCodec.plfreq)
1946 {
1947 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1948 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1949 {
1950 _engineStatisticsPtr->SetLastError(
1951 VE_INVALID_ARGUMENT, kTraceError,
1952 "SetISACMaxPayloadSize() invalid max payload - 1");
1953 return -1;
1954 }
1955 }
1956 else if (32000 == sendCodec.plfreq)
1957 {
1958 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1959 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1960 {
1961 _engineStatisticsPtr->SetLastError(
1962 VE_INVALID_ARGUMENT, kTraceError,
1963 "SetISACMaxPayloadSize() invalid max payload - 2");
1964 return -1;
1965 }
1966 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001967 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001968 {
1969 _engineStatisticsPtr->SetLastError(
1970 VE_SENDING, kTraceError,
1971 "SetISACMaxPayloadSize() unable to set max rate while sending");
1972 return -1;
1973 }
1974
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001975 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001976 {
1977 _engineStatisticsPtr->SetLastError(
1978 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1979 "SetISACMaxPayloadSize() failed to set max payload size");
1980 return -1;
1981 }
1982 return 0;
1983}
1984
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001985int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001986{
1987 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1988 "Channel::RegisterExternalTransport()");
1989
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001990 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001991
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 if (_externalTransport)
1993 {
1994 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1995 kTraceError,
1996 "RegisterExternalTransport() external transport already enabled");
1997 return -1;
1998 }
1999 _externalTransport = true;
2000 _transportPtr = &transport;
2001 return 0;
2002}
2003
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002004int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002005Channel::DeRegisterExternalTransport()
2006{
2007 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2008 "Channel::DeRegisterExternalTransport()");
2009
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002010 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002011
niklase@google.com470e71d2011-07-07 08:21:25 +00002012 if (!_transportPtr)
2013 {
2014 _engineStatisticsPtr->SetLastError(
2015 VE_INVALID_OPERATION, kTraceWarning,
2016 "DeRegisterExternalTransport() external transport already "
2017 "disabled");
2018 return 0;
2019 }
2020 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 _transportPtr = NULL;
2022 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2023 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002024 return 0;
2025}
2026
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002027int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
2028 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002029 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2030 "Channel::ReceivedRTPPacket()");
2031
2032 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002033 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002034
2035 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002036 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2037 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002038 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2039 VoEId(_instanceId,_channelId),
2040 "Channel::SendPacket() RTP dump to input file failed");
2041 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002042 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002043 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002044 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2045 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2046 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002047 return -1;
2048 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002049 header.payload_type_frequency =
2050 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002051 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002052 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002053 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002054 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002055 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002056 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002057
2058 // Forward any packets to ViE bandwidth estimator, if enabled.
2059 {
2060 CriticalSectionScoped cs(&_callbackCritSect);
2061 if (vie_network_) {
2062 int64_t arrival_time_ms;
2063 if (packet_time.timestamp != -1) {
2064 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
2065 } else {
2066 arrival_time_ms = TickTime::MillisecondTimestamp();
2067 }
2068 int payload_length = length - header.headerLength;
2069 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
2070 payload_length, header);
2071 }
2072 }
2073
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002074 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002075}
2076
2077bool Channel::ReceivePacket(const uint8_t* packet,
2078 int packet_length,
2079 const RTPHeader& header,
2080 bool in_order) {
2081 if (rtp_payload_registry_->IsEncapsulated(header)) {
2082 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002083 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002084 const uint8_t* payload = packet + header.headerLength;
2085 int payload_length = packet_length - header.headerLength;
2086 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002087 PayloadUnion payload_specific;
2088 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002089 &payload_specific)) {
2090 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002091 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002092 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2093 payload_specific, in_order);
2094}
2095
2096bool Channel::HandleEncapsulation(const uint8_t* packet,
2097 int packet_length,
2098 const RTPHeader& header) {
2099 if (!rtp_payload_registry_->IsRtx(header))
2100 return false;
2101
2102 // Remove the RTX header and parse the original RTP header.
2103 if (packet_length < header.headerLength)
2104 return false;
2105 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2106 return false;
2107 if (restored_packet_in_use_) {
2108 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2109 "Multiple RTX headers detected, dropping packet");
2110 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002111 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002112 uint8_t* restored_packet_ptr = restored_packet_;
2113 if (!rtp_payload_registry_->RestoreOriginalPacket(
2114 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2115 header)) {
2116 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2117 "Incoming RTX packet: invalid RTP header");
2118 return false;
2119 }
2120 restored_packet_in_use_ = true;
2121 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2122 restored_packet_in_use_ = false;
2123 return ret;
2124}
2125
2126bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2127 StreamStatistician* statistician =
2128 rtp_receive_statistics_->GetStatistician(header.ssrc);
2129 if (!statistician)
2130 return false;
2131 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002132}
2133
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002134bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2135 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002136 // Retransmissions are handled separately if RTX is enabled.
2137 if (rtp_payload_registry_->RtxEnabled())
2138 return false;
2139 StreamStatistician* statistician =
2140 rtp_receive_statistics_->GetStatistician(header.ssrc);
2141 if (!statistician)
2142 return false;
2143 // Check if this is a retransmission.
2144 uint16_t min_rtt = 0;
2145 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002146 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002147 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002148}
2149
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002150int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002151 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2152 "Channel::ReceivedRTCPPacket()");
2153 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002154 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002155
2156 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002157 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2158 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002159 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2160 VoEId(_instanceId,_channelId),
2161 "Channel::SendPacket() RTCP dump to input file failed");
2162 }
2163
2164 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002165 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2166 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002167 _engineStatisticsPtr->SetLastError(
2168 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2169 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2170 }
2171 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002172}
2173
niklase@google.com470e71d2011-07-07 08:21:25 +00002174int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002175 bool loop,
2176 FileFormats format,
2177 int startPosition,
2178 float volumeScaling,
2179 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002180 const CodecInst* codecInst)
2181{
2182 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2183 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2184 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2185 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2186 startPosition, stopPosition);
2187
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002188 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002189 {
2190 _engineStatisticsPtr->SetLastError(
2191 VE_ALREADY_PLAYING, kTraceError,
2192 "StartPlayingFileLocally() is already playing");
2193 return -1;
2194 }
2195
niklase@google.com470e71d2011-07-07 08:21:25 +00002196 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002197 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002198
2199 if (_outputFilePlayerPtr)
2200 {
2201 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2202 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2203 _outputFilePlayerPtr = NULL;
2204 }
2205
2206 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2207 _outputFilePlayerId, (const FileFormats)format);
2208
2209 if (_outputFilePlayerPtr == NULL)
2210 {
2211 _engineStatisticsPtr->SetLastError(
2212 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002213 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002214 return -1;
2215 }
2216
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002217 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002218
2219 if (_outputFilePlayerPtr->StartPlayingFile(
2220 fileName,
2221 loop,
2222 startPosition,
2223 volumeScaling,
2224 notificationTime,
2225 stopPosition,
2226 (const CodecInst*)codecInst) != 0)
2227 {
2228 _engineStatisticsPtr->SetLastError(
2229 VE_BAD_FILE, kTraceError,
2230 "StartPlayingFile() failed to start file playout");
2231 _outputFilePlayerPtr->StopPlayingFile();
2232 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2233 _outputFilePlayerPtr = NULL;
2234 return -1;
2235 }
2236 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002237 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002238 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002239
2240 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002241 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002242
2243 return 0;
2244}
2245
2246int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002247 FileFormats format,
2248 int startPosition,
2249 float volumeScaling,
2250 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002251 const CodecInst* codecInst)
2252{
2253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2254 "Channel::StartPlayingFileLocally(format=%d,"
2255 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2256 format, volumeScaling, startPosition, stopPosition);
2257
2258 if(stream == NULL)
2259 {
2260 _engineStatisticsPtr->SetLastError(
2261 VE_BAD_FILE, kTraceError,
2262 "StartPlayingFileLocally() NULL as input stream");
2263 return -1;
2264 }
2265
2266
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002267 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002268 {
2269 _engineStatisticsPtr->SetLastError(
2270 VE_ALREADY_PLAYING, kTraceError,
2271 "StartPlayingFileLocally() is already playing");
2272 return -1;
2273 }
2274
niklase@google.com470e71d2011-07-07 08:21:25 +00002275 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002276 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002277
2278 // Destroy the old instance
2279 if (_outputFilePlayerPtr)
2280 {
2281 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2282 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2283 _outputFilePlayerPtr = NULL;
2284 }
2285
2286 // Create the instance
2287 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2288 _outputFilePlayerId,
2289 (const FileFormats)format);
2290
2291 if (_outputFilePlayerPtr == NULL)
2292 {
2293 _engineStatisticsPtr->SetLastError(
2294 VE_INVALID_ARGUMENT, kTraceError,
2295 "StartPlayingFileLocally() filePlayer format isnot correct");
2296 return -1;
2297 }
2298
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002299 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002300
2301 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2302 volumeScaling,
2303 notificationTime,
2304 stopPosition, codecInst) != 0)
2305 {
2306 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2307 "StartPlayingFile() failed to "
2308 "start file playout");
2309 _outputFilePlayerPtr->StopPlayingFile();
2310 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2311 _outputFilePlayerPtr = NULL;
2312 return -1;
2313 }
2314 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002315 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002316 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002317
2318 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002319 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002320
niklase@google.com470e71d2011-07-07 08:21:25 +00002321 return 0;
2322}
2323
2324int Channel::StopPlayingFileLocally()
2325{
2326 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2327 "Channel::StopPlayingFileLocally()");
2328
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002329 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002330 {
2331 _engineStatisticsPtr->SetLastError(
2332 VE_INVALID_OPERATION, kTraceWarning,
2333 "StopPlayingFileLocally() isnot playing");
2334 return 0;
2335 }
2336
niklase@google.com470e71d2011-07-07 08:21:25 +00002337 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002338 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002339
2340 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2341 {
2342 _engineStatisticsPtr->SetLastError(
2343 VE_STOP_RECORDING_FAILED, kTraceError,
2344 "StopPlayingFile() could not stop playing");
2345 return -1;
2346 }
2347 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2348 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2349 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002350 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002351 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002352 // _fileCritSect cannot be taken while calling
2353 // SetAnonymousMixibilityStatus. Refer to comments in
2354 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002355 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2356 {
2357 _engineStatisticsPtr->SetLastError(
2358 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002359 "StopPlayingFile() failed to stop participant from playing as"
2360 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002361 return -1;
2362 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002363
2364 return 0;
2365}
2366
2367int Channel::IsPlayingFileLocally() const
2368{
2369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2370 "Channel::IsPlayingFileLocally()");
2371
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002372 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002373}
2374
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002375int Channel::RegisterFilePlayingToMixer()
2376{
2377 // Return success for not registering for file playing to mixer if:
2378 // 1. playing file before playout is started on that channel.
2379 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002380 if (!channel_state_.Get().playing ||
2381 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002382 {
2383 return 0;
2384 }
2385
2386 // |_fileCritSect| cannot be taken while calling
2387 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2388 // frames can be pulled by the mixer. Since the frames are generated from
2389 // the file, _fileCritSect will be taken. This would result in a deadlock.
2390 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2391 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002392 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002393 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002394 _engineStatisticsPtr->SetLastError(
2395 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2396 "StartPlayingFile() failed to add participant as file to mixer");
2397 _outputFilePlayerPtr->StopPlayingFile();
2398 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2399 _outputFilePlayerPtr = NULL;
2400 return -1;
2401 }
2402
2403 return 0;
2404}
2405
pbos@webrtc.org92135212013-05-14 08:31:39 +00002406int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002407{
2408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2409 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2410
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002411 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002412
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002413 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002414 {
2415 _engineStatisticsPtr->SetLastError(
2416 VE_INVALID_OPERATION, kTraceError,
2417 "ScaleLocalFilePlayout() isnot playing");
2418 return -1;
2419 }
2420 if ((_outputFilePlayerPtr == NULL) ||
2421 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2422 {
2423 _engineStatisticsPtr->SetLastError(
2424 VE_BAD_ARGUMENT, kTraceError,
2425 "SetAudioScaling() failed to scale the playout");
2426 return -1;
2427 }
2428
2429 return 0;
2430}
2431
2432int Channel::GetLocalPlayoutPosition(int& positionMs)
2433{
2434 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2435 "Channel::GetLocalPlayoutPosition(position=?)");
2436
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002437 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002438
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002439 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002440
2441 if (_outputFilePlayerPtr == NULL)
2442 {
2443 _engineStatisticsPtr->SetLastError(
2444 VE_INVALID_OPERATION, kTraceError,
2445 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2446 return -1;
2447 }
2448
2449 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2450 {
2451 _engineStatisticsPtr->SetLastError(
2452 VE_BAD_FILE, kTraceError,
2453 "GetLocalPlayoutPosition() failed");
2454 return -1;
2455 }
2456 positionMs = position;
2457
2458 return 0;
2459}
2460
2461int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002462 bool loop,
2463 FileFormats format,
2464 int startPosition,
2465 float volumeScaling,
2466 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002467 const CodecInst* codecInst)
2468{
2469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2470 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2471 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2472 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2473 startPosition, stopPosition);
2474
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002475 CriticalSectionScoped cs(&_fileCritSect);
2476
2477 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002478 {
2479 _engineStatisticsPtr->SetLastError(
2480 VE_ALREADY_PLAYING, kTraceWarning,
2481 "StartPlayingFileAsMicrophone() filePlayer is playing");
2482 return 0;
2483 }
2484
niklase@google.com470e71d2011-07-07 08:21:25 +00002485 // Destroy the old instance
2486 if (_inputFilePlayerPtr)
2487 {
2488 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2489 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2490 _inputFilePlayerPtr = NULL;
2491 }
2492
2493 // Create the instance
2494 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2495 _inputFilePlayerId, (const FileFormats)format);
2496
2497 if (_inputFilePlayerPtr == NULL)
2498 {
2499 _engineStatisticsPtr->SetLastError(
2500 VE_INVALID_ARGUMENT, kTraceError,
2501 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2502 return -1;
2503 }
2504
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002505 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002506
2507 if (_inputFilePlayerPtr->StartPlayingFile(
2508 fileName,
2509 loop,
2510 startPosition,
2511 volumeScaling,
2512 notificationTime,
2513 stopPosition,
2514 (const CodecInst*)codecInst) != 0)
2515 {
2516 _engineStatisticsPtr->SetLastError(
2517 VE_BAD_FILE, kTraceError,
2518 "StartPlayingFile() failed to start file playout");
2519 _inputFilePlayerPtr->StopPlayingFile();
2520 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2521 _inputFilePlayerPtr = NULL;
2522 return -1;
2523 }
2524 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002525 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002526
2527 return 0;
2528}
2529
2530int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002531 FileFormats format,
2532 int startPosition,
2533 float volumeScaling,
2534 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002535 const CodecInst* codecInst)
2536{
2537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2538 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2539 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2540 format, volumeScaling, startPosition, stopPosition);
2541
2542 if(stream == NULL)
2543 {
2544 _engineStatisticsPtr->SetLastError(
2545 VE_BAD_FILE, kTraceError,
2546 "StartPlayingFileAsMicrophone NULL as input stream");
2547 return -1;
2548 }
2549
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002550 CriticalSectionScoped cs(&_fileCritSect);
2551
2552 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002553 {
2554 _engineStatisticsPtr->SetLastError(
2555 VE_ALREADY_PLAYING, kTraceWarning,
2556 "StartPlayingFileAsMicrophone() is playing");
2557 return 0;
2558 }
2559
niklase@google.com470e71d2011-07-07 08:21:25 +00002560 // Destroy the old instance
2561 if (_inputFilePlayerPtr)
2562 {
2563 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2564 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2565 _inputFilePlayerPtr = NULL;
2566 }
2567
2568 // Create the instance
2569 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2570 _inputFilePlayerId, (const FileFormats)format);
2571
2572 if (_inputFilePlayerPtr == NULL)
2573 {
2574 _engineStatisticsPtr->SetLastError(
2575 VE_INVALID_ARGUMENT, kTraceError,
2576 "StartPlayingInputFile() filePlayer format isnot correct");
2577 return -1;
2578 }
2579
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002580 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002581
2582 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2583 volumeScaling, notificationTime,
2584 stopPosition, codecInst) != 0)
2585 {
2586 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2587 "StartPlayingFile() failed to start "
2588 "file playout");
2589 _inputFilePlayerPtr->StopPlayingFile();
2590 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2591 _inputFilePlayerPtr = NULL;
2592 return -1;
2593 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002594
niklase@google.com470e71d2011-07-07 08:21:25 +00002595 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002596 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002597
2598 return 0;
2599}
2600
2601int Channel::StopPlayingFileAsMicrophone()
2602{
2603 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2604 "Channel::StopPlayingFileAsMicrophone()");
2605
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002606 CriticalSectionScoped cs(&_fileCritSect);
2607
2608 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002609 {
2610 _engineStatisticsPtr->SetLastError(
2611 VE_INVALID_OPERATION, kTraceWarning,
2612 "StopPlayingFileAsMicrophone() isnot playing");
2613 return 0;
2614 }
2615
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2617 {
2618 _engineStatisticsPtr->SetLastError(
2619 VE_STOP_RECORDING_FAILED, kTraceError,
2620 "StopPlayingFile() could not stop playing");
2621 return -1;
2622 }
2623 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2624 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2625 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002626 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002627
2628 return 0;
2629}
2630
2631int Channel::IsPlayingFileAsMicrophone() const
2632{
2633 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2634 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002635 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002636}
2637
pbos@webrtc.org92135212013-05-14 08:31:39 +00002638int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002639{
2640 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2641 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2642
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002643 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002644
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002645 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002646 {
2647 _engineStatisticsPtr->SetLastError(
2648 VE_INVALID_OPERATION, kTraceError,
2649 "ScaleFileAsMicrophonePlayout() isnot playing");
2650 return -1;
2651 }
2652
2653 if ((_inputFilePlayerPtr == NULL) ||
2654 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2655 {
2656 _engineStatisticsPtr->SetLastError(
2657 VE_BAD_ARGUMENT, kTraceError,
2658 "SetAudioScaling() failed to scale playout");
2659 return -1;
2660 }
2661
2662 return 0;
2663}
2664
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002665int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002666 const CodecInst* codecInst)
2667{
2668 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2669 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2670
2671 if (_outputFileRecording)
2672 {
2673 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2674 "StartRecordingPlayout() is already recording");
2675 return 0;
2676 }
2677
2678 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002679 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2681
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002682 if ((codecInst != NULL) &&
2683 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002684 {
2685 _engineStatisticsPtr->SetLastError(
2686 VE_BAD_ARGUMENT, kTraceError,
2687 "StartRecordingPlayout() invalid compression");
2688 return(-1);
2689 }
2690 if(codecInst == NULL)
2691 {
2692 format = kFileFormatPcm16kHzFile;
2693 codecInst=&dummyCodec;
2694 }
2695 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2696 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2697 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2698 {
2699 format = kFileFormatWavFile;
2700 }
2701 else
2702 {
2703 format = kFileFormatCompressedFile;
2704 }
2705
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002706 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002707
2708 // Destroy the old instance
2709 if (_outputFileRecorderPtr)
2710 {
2711 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2712 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2713 _outputFileRecorderPtr = NULL;
2714 }
2715
2716 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2717 _outputFileRecorderId, (const FileFormats)format);
2718 if (_outputFileRecorderPtr == NULL)
2719 {
2720 _engineStatisticsPtr->SetLastError(
2721 VE_INVALID_ARGUMENT, kTraceError,
2722 "StartRecordingPlayout() fileRecorder format isnot correct");
2723 return -1;
2724 }
2725
2726 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2727 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2728 {
2729 _engineStatisticsPtr->SetLastError(
2730 VE_BAD_FILE, kTraceError,
2731 "StartRecordingAudioFile() failed to start file recording");
2732 _outputFileRecorderPtr->StopRecording();
2733 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2734 _outputFileRecorderPtr = NULL;
2735 return -1;
2736 }
2737 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2738 _outputFileRecording = true;
2739
2740 return 0;
2741}
2742
2743int Channel::StartRecordingPlayout(OutStream* stream,
2744 const CodecInst* codecInst)
2745{
2746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2747 "Channel::StartRecordingPlayout()");
2748
2749 if (_outputFileRecording)
2750 {
2751 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2752 "StartRecordingPlayout() is already recording");
2753 return 0;
2754 }
2755
2756 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002757 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002758 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2759
2760 if (codecInst != NULL && codecInst->channels != 1)
2761 {
2762 _engineStatisticsPtr->SetLastError(
2763 VE_BAD_ARGUMENT, kTraceError,
2764 "StartRecordingPlayout() invalid compression");
2765 return(-1);
2766 }
2767 if(codecInst == NULL)
2768 {
2769 format = kFileFormatPcm16kHzFile;
2770 codecInst=&dummyCodec;
2771 }
2772 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2773 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2774 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2775 {
2776 format = kFileFormatWavFile;
2777 }
2778 else
2779 {
2780 format = kFileFormatCompressedFile;
2781 }
2782
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002783 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002784
2785 // Destroy the old instance
2786 if (_outputFileRecorderPtr)
2787 {
2788 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2789 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2790 _outputFileRecorderPtr = NULL;
2791 }
2792
2793 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2794 _outputFileRecorderId, (const FileFormats)format);
2795 if (_outputFileRecorderPtr == NULL)
2796 {
2797 _engineStatisticsPtr->SetLastError(
2798 VE_INVALID_ARGUMENT, kTraceError,
2799 "StartRecordingPlayout() fileRecorder format isnot correct");
2800 return -1;
2801 }
2802
2803 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2804 notificationTime) != 0)
2805 {
2806 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2807 "StartRecordingPlayout() failed to "
2808 "start file recording");
2809 _outputFileRecorderPtr->StopRecording();
2810 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2811 _outputFileRecorderPtr = NULL;
2812 return -1;
2813 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002814
niklase@google.com470e71d2011-07-07 08:21:25 +00002815 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2816 _outputFileRecording = true;
2817
2818 return 0;
2819}
2820
2821int Channel::StopRecordingPlayout()
2822{
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2824 "Channel::StopRecordingPlayout()");
2825
2826 if (!_outputFileRecording)
2827 {
2828 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2829 "StopRecordingPlayout() isnot recording");
2830 return -1;
2831 }
2832
2833
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002834 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002835
2836 if (_outputFileRecorderPtr->StopRecording() != 0)
2837 {
2838 _engineStatisticsPtr->SetLastError(
2839 VE_STOP_RECORDING_FAILED, kTraceError,
2840 "StopRecording() could not stop recording");
2841 return(-1);
2842 }
2843 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2844 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2845 _outputFileRecorderPtr = NULL;
2846 _outputFileRecording = false;
2847
2848 return 0;
2849}
2850
2851void
2852Channel::SetMixWithMicStatus(bool mix)
2853{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002854 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002855 _mixFileWithMicrophone=mix;
2856}
2857
2858int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002859Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002860{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002861 int8_t currentLevel = _outputAudioLevel.Level();
2862 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002863 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2864 VoEId(_instanceId,_channelId),
2865 "GetSpeechOutputLevel() => level=%u", level);
2866 return 0;
2867}
2868
2869int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002870Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002871{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002872 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2873 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002874 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2875 VoEId(_instanceId,_channelId),
2876 "GetSpeechOutputLevelFullRange() => level=%u", level);
2877 return 0;
2878}
2879
2880int
2881Channel::SetMute(bool enable)
2882{
wu@webrtc.org63420662013-10-17 18:28:55 +00002883 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002884 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2885 "Channel::SetMute(enable=%d)", enable);
2886 _mute = enable;
2887 return 0;
2888}
2889
2890bool
2891Channel::Mute() const
2892{
wu@webrtc.org63420662013-10-17 18:28:55 +00002893 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002894 return _mute;
2895}
2896
2897int
2898Channel::SetOutputVolumePan(float left, float right)
2899{
wu@webrtc.org63420662013-10-17 18:28:55 +00002900 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2902 "Channel::SetOutputVolumePan()");
2903 _panLeft = left;
2904 _panRight = right;
2905 return 0;
2906}
2907
2908int
2909Channel::GetOutputVolumePan(float& left, float& right) const
2910{
wu@webrtc.org63420662013-10-17 18:28:55 +00002911 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002912 left = _panLeft;
2913 right = _panRight;
2914 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2915 VoEId(_instanceId,_channelId),
2916 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2917 return 0;
2918}
2919
2920int
2921Channel::SetChannelOutputVolumeScaling(float scaling)
2922{
wu@webrtc.org63420662013-10-17 18:28:55 +00002923 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002924 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2925 "Channel::SetChannelOutputVolumeScaling()");
2926 _outputGain = scaling;
2927 return 0;
2928}
2929
2930int
2931Channel::GetChannelOutputVolumeScaling(float& scaling) const
2932{
wu@webrtc.org63420662013-10-17 18:28:55 +00002933 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002934 scaling = _outputGain;
2935 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2936 VoEId(_instanceId,_channelId),
2937 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2938 return 0;
2939}
2940
niklase@google.com470e71d2011-07-07 08:21:25 +00002941int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002942 int lengthMs, int attenuationDb,
2943 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002944{
2945 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2946 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2947 playDtmfEvent);
2948
2949 _playOutbandDtmfEvent = playDtmfEvent;
2950
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002951 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002952 attenuationDb) != 0)
2953 {
2954 _engineStatisticsPtr->SetLastError(
2955 VE_SEND_DTMF_FAILED,
2956 kTraceWarning,
2957 "SendTelephoneEventOutband() failed to send event");
2958 return -1;
2959 }
2960 return 0;
2961}
2962
2963int Channel::SendTelephoneEventInband(unsigned char eventCode,
2964 int lengthMs,
2965 int attenuationDb,
2966 bool playDtmfEvent)
2967{
2968 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2969 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2970 playDtmfEvent);
2971
2972 _playInbandDtmfEvent = playDtmfEvent;
2973 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2974
2975 return 0;
2976}
2977
2978int
2979Channel::SetDtmfPlayoutStatus(bool enable)
2980{
2981 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2982 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002983 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002984 {
2985 _engineStatisticsPtr->SetLastError(
2986 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2987 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2988 return -1;
2989 }
2990 return 0;
2991}
2992
2993bool
2994Channel::DtmfPlayoutStatus() const
2995{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002996 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002997}
2998
2999int
3000Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3001{
3002 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3003 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003004 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003005 {
3006 _engineStatisticsPtr->SetLastError(
3007 VE_INVALID_ARGUMENT, kTraceError,
3008 "SetSendTelephoneEventPayloadType() invalid type");
3009 return -1;
3010 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003011 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003012 codec.plfreq = 8000;
3013 codec.pltype = type;
3014 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003015 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003016 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003017 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3018 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3019 _engineStatisticsPtr->SetLastError(
3020 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3021 "SetSendTelephoneEventPayloadType() failed to register send"
3022 "payload type");
3023 return -1;
3024 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003025 }
3026 _sendTelephoneEventPayloadType = type;
3027 return 0;
3028}
3029
3030int
3031Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3032{
3033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3034 "Channel::GetSendTelephoneEventPayloadType()");
3035 type = _sendTelephoneEventPayloadType;
3036 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3037 VoEId(_instanceId,_channelId),
3038 "GetSendTelephoneEventPayloadType() => type=%u", type);
3039 return 0;
3040}
3041
niklase@google.com470e71d2011-07-07 08:21:25 +00003042int
3043Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3044{
3045 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3046 "Channel::UpdateRxVadDetection()");
3047
3048 int vadDecision = 1;
3049
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003050 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003051
3052 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3053 {
3054 OnRxVadDetected(vadDecision);
3055 _oldVadDecision = vadDecision;
3056 }
3057
3058 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3059 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3060 vadDecision);
3061 return 0;
3062}
3063
3064int
3065Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3066{
3067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3068 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003069 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003070
3071 if (_rxVadObserverPtr)
3072 {
3073 _engineStatisticsPtr->SetLastError(
3074 VE_INVALID_OPERATION, kTraceError,
3075 "RegisterRxVadObserver() observer already enabled");
3076 return -1;
3077 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003078 _rxVadObserverPtr = &observer;
3079 _RxVadDetection = true;
3080 return 0;
3081}
3082
3083int
3084Channel::DeRegisterRxVadObserver()
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3087 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003088 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003089
3090 if (!_rxVadObserverPtr)
3091 {
3092 _engineStatisticsPtr->SetLastError(
3093 VE_INVALID_OPERATION, kTraceWarning,
3094 "DeRegisterRxVadObserver() observer already disabled");
3095 return 0;
3096 }
3097 _rxVadObserverPtr = NULL;
3098 _RxVadDetection = false;
3099 return 0;
3100}
3101
3102int
3103Channel::VoiceActivityIndicator(int &activity)
3104{
3105 activity = _sendFrameType;
3106
3107 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003108 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003109 return 0;
3110}
3111
3112#ifdef WEBRTC_VOICE_ENGINE_AGC
3113
3114int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003115Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003116{
3117 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3118 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3119 (int)enable, (int)mode);
3120
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003121 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003122 switch (mode)
3123 {
3124 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 break;
3126 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003127 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003128 break;
3129 case kAgcFixedDigital:
3130 agcMode = GainControl::kFixedDigital;
3131 break;
3132 case kAgcAdaptiveDigital:
3133 agcMode =GainControl::kAdaptiveDigital;
3134 break;
3135 default:
3136 _engineStatisticsPtr->SetLastError(
3137 VE_INVALID_ARGUMENT, kTraceError,
3138 "SetRxAgcStatus() invalid Agc mode");
3139 return -1;
3140 }
3141
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003142 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003143 {
3144 _engineStatisticsPtr->SetLastError(
3145 VE_APM_ERROR, kTraceError,
3146 "SetRxAgcStatus() failed to set Agc mode");
3147 return -1;
3148 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003149 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003150 {
3151 _engineStatisticsPtr->SetLastError(
3152 VE_APM_ERROR, kTraceError,
3153 "SetRxAgcStatus() failed to set Agc state");
3154 return -1;
3155 }
3156
3157 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003158 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003159
3160 return 0;
3161}
3162
3163int
3164Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3165{
3166 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3167 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3168
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003169 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003170 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003171 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003172
3173 enabled = enable;
3174
3175 switch (agcMode)
3176 {
3177 case GainControl::kFixedDigital:
3178 mode = kAgcFixedDigital;
3179 break;
3180 case GainControl::kAdaptiveDigital:
3181 mode = kAgcAdaptiveDigital;
3182 break;
3183 default:
3184 _engineStatisticsPtr->SetLastError(
3185 VE_APM_ERROR, kTraceError,
3186 "GetRxAgcStatus() invalid Agc mode");
3187 return -1;
3188 }
3189
3190 return 0;
3191}
3192
3193int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003194Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003195{
3196 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3197 "Channel::SetRxAgcConfig()");
3198
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003199 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003200 config.targetLeveldBOv) != 0)
3201 {
3202 _engineStatisticsPtr->SetLastError(
3203 VE_APM_ERROR, kTraceError,
3204 "SetRxAgcConfig() failed to set target peak |level|"
3205 "(or envelope) of the Agc");
3206 return -1;
3207 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003208 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003209 config.digitalCompressionGaindB) != 0)
3210 {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_APM_ERROR, kTraceError,
3213 "SetRxAgcConfig() failed to set the range in |gain| the"
3214 " digital compression stage may apply");
3215 return -1;
3216 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003217 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003218 config.limiterEnable) != 0)
3219 {
3220 _engineStatisticsPtr->SetLastError(
3221 VE_APM_ERROR, kTraceError,
3222 "SetRxAgcConfig() failed to set hard limiter to the signal");
3223 return -1;
3224 }
3225
3226 return 0;
3227}
3228
3229int
3230Channel::GetRxAgcConfig(AgcConfig& config)
3231{
3232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3233 "Channel::GetRxAgcConfig(config=%?)");
3234
3235 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003236 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003237 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003238 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003239 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003240 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003241
3242 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3243 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3244 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3245 " limiterEnable=%d",
3246 config.targetLeveldBOv,
3247 config.digitalCompressionGaindB,
3248 config.limiterEnable);
3249
3250 return 0;
3251}
3252
3253#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3254
3255#ifdef WEBRTC_VOICE_ENGINE_NR
3256
3257int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003258Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003259{
3260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3261 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3262 (int)enable, (int)mode);
3263
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003264 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 switch (mode)
3266 {
3267
3268 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 break;
3270 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003271 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003272 break;
3273 case kNsConference:
3274 nsLevel = NoiseSuppression::kHigh;
3275 break;
3276 case kNsLowSuppression:
3277 nsLevel = NoiseSuppression::kLow;
3278 break;
3279 case kNsModerateSuppression:
3280 nsLevel = NoiseSuppression::kModerate;
3281 break;
3282 case kNsHighSuppression:
3283 nsLevel = NoiseSuppression::kHigh;
3284 break;
3285 case kNsVeryHighSuppression:
3286 nsLevel = NoiseSuppression::kVeryHigh;
3287 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 }
3289
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003290 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003291 != 0)
3292 {
3293 _engineStatisticsPtr->SetLastError(
3294 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003295 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 return -1;
3297 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003298 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003299 {
3300 _engineStatisticsPtr->SetLastError(
3301 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003302 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003303 return -1;
3304 }
3305
3306 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003307 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003308
3309 return 0;
3310}
3311
3312int
3313Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3314{
3315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3316 "Channel::GetRxNsStatus(enable=?, mode=?)");
3317
3318 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003319 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003320 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003321 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003322
3323 enabled = enable;
3324
3325 switch (ncLevel)
3326 {
3327 case NoiseSuppression::kLow:
3328 mode = kNsLowSuppression;
3329 break;
3330 case NoiseSuppression::kModerate:
3331 mode = kNsModerateSuppression;
3332 break;
3333 case NoiseSuppression::kHigh:
3334 mode = kNsHighSuppression;
3335 break;
3336 case NoiseSuppression::kVeryHigh:
3337 mode = kNsVeryHighSuppression;
3338 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003339 }
3340
3341 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3342 VoEId(_instanceId,_channelId),
3343 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3344 return 0;
3345}
3346
3347#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3348
3349int
3350Channel::RegisterRTPObserver(VoERTPObserver& observer)
3351{
3352 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3353 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003354 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003355
3356 if (_rtpObserverPtr)
3357 {
3358 _engineStatisticsPtr->SetLastError(
3359 VE_INVALID_OPERATION, kTraceError,
3360 "RegisterRTPObserver() observer already enabled");
3361 return -1;
3362 }
3363
3364 _rtpObserverPtr = &observer;
3365 _rtpObserver = true;
3366
3367 return 0;
3368}
3369
3370int
3371Channel::DeRegisterRTPObserver()
3372{
3373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3374 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003375 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003376
3377 if (!_rtpObserverPtr)
3378 {
3379 _engineStatisticsPtr->SetLastError(
3380 VE_INVALID_OPERATION, kTraceWarning,
3381 "DeRegisterRTPObserver() observer already disabled");
3382 return 0;
3383 }
3384
3385 _rtpObserver = false;
3386 _rtpObserverPtr = NULL;
3387
3388 return 0;
3389}
3390
3391int
3392Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3393{
3394 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3395 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003396 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003397
3398 if (_rtcpObserverPtr)
3399 {
3400 _engineStatisticsPtr->SetLastError(
3401 VE_INVALID_OPERATION, kTraceError,
3402 "RegisterRTCPObserver() observer already enabled");
3403 return -1;
3404 }
3405
3406 _rtcpObserverPtr = &observer;
3407 _rtcpObserver = true;
3408
3409 return 0;
3410}
3411
3412int
3413Channel::DeRegisterRTCPObserver()
3414{
3415 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3416 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003417 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003418
3419 if (!_rtcpObserverPtr)
3420 {
3421 _engineStatisticsPtr->SetLastError(
3422 VE_INVALID_OPERATION, kTraceWarning,
3423 "DeRegisterRTCPObserver() observer already disabled");
3424 return 0;
3425 }
3426
3427 _rtcpObserver = false;
3428 _rtcpObserverPtr = NULL;
3429
3430 return 0;
3431}
3432
3433int
3434Channel::SetLocalSSRC(unsigned int ssrc)
3435{
3436 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3437 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003438 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003439 {
3440 _engineStatisticsPtr->SetLastError(
3441 VE_ALREADY_SENDING, kTraceError,
3442 "SetLocalSSRC() already sending");
3443 return -1;
3444 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003445 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003446 {
3447 _engineStatisticsPtr->SetLastError(
3448 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3449 "SetLocalSSRC() failed to set SSRC");
3450 return -1;
3451 }
3452 return 0;
3453}
3454
3455int
3456Channel::GetLocalSSRC(unsigned int& ssrc)
3457{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003458 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003459 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3460 VoEId(_instanceId,_channelId),
3461 "GetLocalSSRC() => ssrc=%lu", ssrc);
3462 return 0;
3463}
3464
3465int
3466Channel::GetRemoteSSRC(unsigned int& ssrc)
3467{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003468 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003469 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3470 VoEId(_instanceId,_channelId),
3471 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3472 return 0;
3473}
3474
3475int
3476Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3477{
3478 if (arrCSRC == NULL)
3479 {
3480 _engineStatisticsPtr->SetLastError(
3481 VE_INVALID_ARGUMENT, kTraceError,
3482 "GetRemoteCSRCs() invalid array argument");
3483 return -1;
3484 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003485 uint32_t arrOfCSRC[kRtpCsrcSize];
3486 int32_t CSRCs(0);
braveyao@webrtc.orgcdefc912014-03-11 16:19:56 +00003487 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003488 if (CSRCs > 0)
3489 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003490 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003491 for (int i = 0; i < (int) CSRCs; i++)
3492 {
3493 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3494 VoEId(_instanceId, _channelId),
3495 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3496 }
3497 } else
3498 {
3499 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3500 VoEId(_instanceId, _channelId),
3501 "GetRemoteCSRCs() => list is empty!");
3502 }
3503 return CSRCs;
3504}
3505
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003506int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003507 if (rtp_audioproc_.get() == NULL) {
3508 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3509 _channelId)));
3510 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003511
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003512 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3513 AudioProcessing::kNoError) {
3514 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3515 "Failed to enable AudioProcessing::level_estimator()");
3516 return -1;
3517 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003518
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003519 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003520
3521 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003522}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003523
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003524int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3525 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3526}
3527
3528int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3529 rtp_header_parser_->DeregisterRtpHeaderExtension(
3530 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003531 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3532 kRtpExtensionAbsoluteSendTime, id)) {
3533 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003534 }
3535 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003536}
3537
3538int
3539Channel::SetRTCPStatus(bool enable)
3540{
3541 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3542 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003543 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003544 kRtcpCompound : kRtcpOff) != 0)
3545 {
3546 _engineStatisticsPtr->SetLastError(
3547 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3548 "SetRTCPStatus() failed to set RTCP status");
3549 return -1;
3550 }
3551 return 0;
3552}
3553
3554int
3555Channel::GetRTCPStatus(bool& enabled)
3556{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003557 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003558 enabled = (method != kRtcpOff);
3559 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3560 VoEId(_instanceId,_channelId),
3561 "GetRTCPStatus() => enabled=%d", enabled);
3562 return 0;
3563}
3564
3565int
3566Channel::SetRTCP_CNAME(const char cName[256])
3567{
3568 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3569 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003570 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003571 {
3572 _engineStatisticsPtr->SetLastError(
3573 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3574 "SetRTCP_CNAME() failed to set RTCP CNAME");
3575 return -1;
3576 }
3577 return 0;
3578}
3579
3580int
3581Channel::GetRTCP_CNAME(char cName[256])
3582{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003583 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003584 {
3585 _engineStatisticsPtr->SetLastError(
3586 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3587 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3588 return -1;
3589 }
3590 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3591 VoEId(_instanceId, _channelId),
3592 "GetRTCP_CNAME() => cName=%s", cName);
3593 return 0;
3594}
3595
3596int
3597Channel::GetRemoteRTCP_CNAME(char cName[256])
3598{
3599 if (cName == NULL)
3600 {
3601 _engineStatisticsPtr->SetLastError(
3602 VE_INVALID_ARGUMENT, kTraceError,
3603 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3604 return -1;
3605 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003606 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003607 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003608 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003609 {
3610 _engineStatisticsPtr->SetLastError(
3611 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3612 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3613 return -1;
3614 }
3615 strcpy(cName, cname);
3616 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3617 VoEId(_instanceId, _channelId),
3618 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3619 return 0;
3620}
3621
3622int
3623Channel::GetRemoteRTCPData(
3624 unsigned int& NTPHigh,
3625 unsigned int& NTPLow,
3626 unsigned int& timestamp,
3627 unsigned int& playoutTimestamp,
3628 unsigned int* jitter,
3629 unsigned short* fractionLost)
3630{
3631 // --- Information from sender info in received Sender Reports
3632
3633 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003634 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003635 {
3636 _engineStatisticsPtr->SetLastError(
3637 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003638 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003639 "side");
3640 return -1;
3641 }
3642
3643 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3644 // and octet count)
3645 NTPHigh = senderInfo.NTPseconds;
3646 NTPLow = senderInfo.NTPfraction;
3647 timestamp = senderInfo.RTPtimeStamp;
3648
3649 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3650 VoEId(_instanceId, _channelId),
3651 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3652 "timestamp=%lu",
3653 NTPHigh, NTPLow, timestamp);
3654
3655 // --- Locally derived information
3656
3657 // This value is updated on each incoming RTCP packet (0 when no packet
3658 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003659 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003660
3661 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3662 VoEId(_instanceId, _channelId),
3663 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003664 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003665
3666 if (NULL != jitter || NULL != fractionLost)
3667 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003668 // Get all RTCP receiver report blocks that have been received on this
3669 // channel. If we receive RTP packets from a remote source we know the
3670 // remote SSRC and use the report block from him.
3671 // Otherwise use the first report block.
3672 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003673 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003674 remote_stats.empty()) {
3675 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3676 VoEId(_instanceId, _channelId),
3677 "GetRemoteRTCPData() failed to measure statistics due"
3678 " to lack of received RTP and/or RTCP packets");
3679 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003680 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003681
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003682 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003683 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3684 for (; it != remote_stats.end(); ++it) {
3685 if (it->remoteSSRC == remoteSSRC)
3686 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003687 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003688
3689 if (it == remote_stats.end()) {
3690 // If we have not received any RTCP packets from this SSRC it probably
3691 // means that we have not received any RTP packets.
3692 // Use the first received report block instead.
3693 it = remote_stats.begin();
3694 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003695 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003696
xians@webrtc.org79af7342012-01-31 12:22:14 +00003697 if (jitter) {
3698 *jitter = it->jitter;
3699 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3700 VoEId(_instanceId, _channelId),
3701 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3702 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003703
xians@webrtc.org79af7342012-01-31 12:22:14 +00003704 if (fractionLost) {
3705 *fractionLost = it->fractionLost;
3706 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3707 VoEId(_instanceId, _channelId),
3708 "GetRemoteRTCPData() => fractionLost = %lu",
3709 *fractionLost);
3710 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003711 }
3712 return 0;
3713}
3714
3715int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003716Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003717 unsigned int name,
3718 const char* data,
3719 unsigned short dataLengthInBytes)
3720{
3721 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3722 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003723 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 {
3725 _engineStatisticsPtr->SetLastError(
3726 VE_NOT_SENDING, kTraceError,
3727 "SendApplicationDefinedRTCPPacket() not sending");
3728 return -1;
3729 }
3730 if (NULL == data)
3731 {
3732 _engineStatisticsPtr->SetLastError(
3733 VE_INVALID_ARGUMENT, kTraceError,
3734 "SendApplicationDefinedRTCPPacket() invalid data value");
3735 return -1;
3736 }
3737 if (dataLengthInBytes % 4 != 0)
3738 {
3739 _engineStatisticsPtr->SetLastError(
3740 VE_INVALID_ARGUMENT, kTraceError,
3741 "SendApplicationDefinedRTCPPacket() invalid length value");
3742 return -1;
3743 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003744 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003745 if (status == kRtcpOff)
3746 {
3747 _engineStatisticsPtr->SetLastError(
3748 VE_RTCP_ERROR, kTraceError,
3749 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3750 return -1;
3751 }
3752
3753 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003754 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003755 subType,
3756 name,
3757 (const unsigned char*) data,
3758 dataLengthInBytes) != 0)
3759 {
3760 _engineStatisticsPtr->SetLastError(
3761 VE_SEND_ERROR, kTraceError,
3762 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3763 return -1;
3764 }
3765 return 0;
3766}
3767
3768int
3769Channel::GetRTPStatistics(
3770 unsigned int& averageJitterMs,
3771 unsigned int& maxJitterMs,
3772 unsigned int& discardedPackets)
3773{
niklase@google.com470e71d2011-07-07 08:21:25 +00003774 // The jitter statistics is updated for each received RTP packet and is
3775 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003776 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3777 // If RTCP is off, there is no timed thread in the RTCP module regularly
3778 // generating new stats, trigger the update manually here instead.
3779 StreamStatistician* statistician =
3780 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3781 if (statistician) {
3782 // Don't use returned statistics, use data from proxy instead so that
3783 // max jitter can be fetched atomically.
3784 RtcpStatistics s;
3785 statistician->GetStatistics(&s, true);
3786 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003787 }
3788
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003789 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003790 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003791 if (playoutFrequency > 0) {
3792 // Scale RTP statistics given the current playout frequency
3793 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3794 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003795 }
3796
3797 discardedPackets = _numberOfDiscardedPackets;
3798
3799 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3800 VoEId(_instanceId, _channelId),
3801 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003802 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003803 averageJitterMs, maxJitterMs, discardedPackets);
3804 return 0;
3805}
3806
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003807int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3808 if (sender_info == NULL) {
3809 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3810 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3811 return -1;
3812 }
3813
3814 // Get the sender info from the latest received RTCP Sender Report.
3815 RTCPSenderInfo rtcp_sender_info;
3816 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3817 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3818 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3819 return -1;
3820 }
3821
3822 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3823 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3824 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3825 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3826 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3827 return 0;
3828}
3829
3830int Channel::GetRemoteRTCPReportBlocks(
3831 std::vector<ReportBlock>* report_blocks) {
3832 if (report_blocks == NULL) {
3833 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3834 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3835 return -1;
3836 }
3837
3838 // Get the report blocks from the latest received RTCP Sender or Receiver
3839 // Report. Each element in the vector contains the sender's SSRC and a
3840 // report block according to RFC 3550.
3841 std::vector<RTCPReportBlock> rtcp_report_blocks;
3842 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3843 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3844 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3845 return -1;
3846 }
3847
3848 if (rtcp_report_blocks.empty())
3849 return 0;
3850
3851 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3852 for (; it != rtcp_report_blocks.end(); ++it) {
3853 ReportBlock report_block;
3854 report_block.sender_SSRC = it->remoteSSRC;
3855 report_block.source_SSRC = it->sourceSSRC;
3856 report_block.fraction_lost = it->fractionLost;
3857 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3858 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3859 report_block.interarrival_jitter = it->jitter;
3860 report_block.last_SR_timestamp = it->lastSR;
3861 report_block.delay_since_last_SR = it->delaySinceLastSR;
3862 report_blocks->push_back(report_block);
3863 }
3864 return 0;
3865}
3866
niklase@google.com470e71d2011-07-07 08:21:25 +00003867int
3868Channel::GetRTPStatistics(CallStatistics& stats)
3869{
niklase@google.com470e71d2011-07-07 08:21:25 +00003870 // --- Part one of the final structure (four values)
3871
3872 // The jitter statistics is updated for each received RTP packet and is
3873 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003874 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003875 StreamStatistician* statistician =
3876 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3877 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003878 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3879 _engineStatisticsPtr->SetLastError(
3880 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3881 "GetRTPStatistics() failed to read RTP statistics from the "
3882 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003883 }
3884
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003885 stats.fractionLost = statistics.fraction_lost;
3886 stats.cumulativeLost = statistics.cumulative_lost;
3887 stats.extendedMax = statistics.extended_max_sequence_number;
3888 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003889
3890 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3891 VoEId(_instanceId, _channelId),
3892 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003893 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003894 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3895 stats.jitterSamples);
3896
3897 // --- Part two of the final structure (one value)
3898
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003899 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003900 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003901 if (method == kRtcpOff)
3902 {
3903 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3904 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003905 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003906 "measurements cannot be retrieved");
3907 } else
3908 {
3909 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003910 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003911 if (remoteSSRC > 0)
3912 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003913 uint16_t avgRTT(0);
3914 uint16_t maxRTT(0);
3915 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003916
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003917 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003918 != 0)
3919 {
3920 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3921 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003922 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003923 "the RTP/RTCP module");
3924 }
3925 } else
3926 {
3927 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3928 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003929 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003930 "RTP packets have been received yet");
3931 }
3932 }
3933
3934 stats.rttMs = static_cast<int> (RTT);
3935
3936 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3937 VoEId(_instanceId, _channelId),
3938 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3939
3940 // --- Part three of the final structure (four values)
3941
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003942 uint32_t bytesSent(0);
3943 uint32_t packetsSent(0);
3944 uint32_t bytesReceived(0);
3945 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003946
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003947 if (statistician) {
3948 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3949 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003950
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003951 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003952 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003953 {
3954 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3955 VoEId(_instanceId, _channelId),
3956 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003957 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003958 }
3959
3960 stats.bytesSent = bytesSent;
3961 stats.packetsSent = packetsSent;
3962 stats.bytesReceived = bytesReceived;
3963 stats.packetsReceived = packetsReceived;
3964
3965 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3966 VoEId(_instanceId, _channelId),
3967 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003968 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003969 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3970 stats.packetsReceived);
3971
3972 return 0;
3973}
3974
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003975int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3976 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3977 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003978
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003979 if (enable) {
3980 if (redPayloadtype < 0 || redPayloadtype > 127) {
3981 _engineStatisticsPtr->SetLastError(
3982 VE_PLTYPE_ERROR, kTraceError,
3983 "SetFECStatus() invalid RED payload type");
3984 return -1;
3985 }
3986
3987 if (SetRedPayloadType(redPayloadtype) < 0) {
3988 _engineStatisticsPtr->SetLastError(
3989 VE_CODEC_ERROR, kTraceError,
3990 "SetSecondarySendCodec() Failed to register RED ACM");
3991 return -1;
3992 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003993 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003994
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003995 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003996 _engineStatisticsPtr->SetLastError(
3997 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3998 "SetFECStatus() failed to set FEC state in the ACM");
3999 return -1;
4000 }
4001 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004002}
4003
4004int
4005Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4006{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004007 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004008 if (enabled)
4009 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004010 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004011 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004012 {
4013 _engineStatisticsPtr->SetLastError(
4014 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4015 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4016 "module");
4017 return -1;
4018 }
4019 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4020 VoEId(_instanceId, _channelId),
4021 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4022 enabled, redPayloadtype);
4023 return 0;
4024 }
4025 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4026 VoEId(_instanceId, _channelId),
4027 "GetFECStatus() => enabled=%d", enabled);
4028 return 0;
4029}
4030
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004031void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4032 // None of these functions can fail.
4033 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004034 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4035 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004036 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004037 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004038 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004039 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004040}
4041
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004042// Called when we are missing one or more packets.
4043int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004044 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4045}
4046
niklase@google.com470e71d2011-07-07 08:21:25 +00004047int
niklase@google.com470e71d2011-07-07 08:21:25 +00004048Channel::StartRTPDump(const char fileNameUTF8[1024],
4049 RTPDirections direction)
4050{
4051 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4052 "Channel::StartRTPDump()");
4053 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4054 {
4055 _engineStatisticsPtr->SetLastError(
4056 VE_INVALID_ARGUMENT, kTraceError,
4057 "StartRTPDump() invalid RTP direction");
4058 return -1;
4059 }
4060 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4061 &_rtpDumpIn : &_rtpDumpOut;
4062 if (rtpDumpPtr == NULL)
4063 {
4064 assert(false);
4065 return -1;
4066 }
4067 if (rtpDumpPtr->IsActive())
4068 {
4069 rtpDumpPtr->Stop();
4070 }
4071 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4072 {
4073 _engineStatisticsPtr->SetLastError(
4074 VE_BAD_FILE, kTraceError,
4075 "StartRTPDump() failed to create file");
4076 return -1;
4077 }
4078 return 0;
4079}
4080
4081int
4082Channel::StopRTPDump(RTPDirections direction)
4083{
4084 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4085 "Channel::StopRTPDump()");
4086 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4087 {
4088 _engineStatisticsPtr->SetLastError(
4089 VE_INVALID_ARGUMENT, kTraceError,
4090 "StopRTPDump() invalid RTP direction");
4091 return -1;
4092 }
4093 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4094 &_rtpDumpIn : &_rtpDumpOut;
4095 if (rtpDumpPtr == NULL)
4096 {
4097 assert(false);
4098 return -1;
4099 }
4100 if (!rtpDumpPtr->IsActive())
4101 {
4102 return 0;
4103 }
4104 return rtpDumpPtr->Stop();
4105}
4106
4107bool
4108Channel::RTPDumpIsActive(RTPDirections direction)
4109{
4110 if ((direction != kRtpIncoming) &&
4111 (direction != kRtpOutgoing))
4112 {
4113 _engineStatisticsPtr->SetLastError(
4114 VE_INVALID_ARGUMENT, kTraceError,
4115 "RTPDumpIsActive() invalid RTP direction");
4116 return false;
4117 }
4118 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4119 &_rtpDumpIn : &_rtpDumpOut;
4120 return rtpDumpPtr->IsActive();
4121}
4122
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00004123void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
4124 int video_channel) {
4125 CriticalSectionScoped cs(&_callbackCritSect);
4126 if (vie_network_) {
4127 vie_network_->Release();
4128 vie_network_ = NULL;
4129 }
4130 video_channel_ = -1;
4131
4132 if (vie_network != NULL && video_channel != -1) {
4133 vie_network_ = vie_network;
4134 video_channel_ = video_channel;
4135 }
4136}
4137
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004138uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004139Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004140{
4141 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004142 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004143 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004144 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004145 return 0;
4146}
4147
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004148void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004149 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004150 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004151 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004152 CodecInst codec;
4153 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004154
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004155 if (!mono_recording_audio_.get()) {
4156 // Temporary space for DownConvertToCodecFormat.
4157 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004158 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004159 DownConvertToCodecFormat(audio_data,
4160 number_of_frames,
4161 number_of_channels,
4162 sample_rate,
4163 codec.channels,
4164 codec.plfreq,
4165 mono_recording_audio_.get(),
4166 &input_resampler_,
4167 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004168}
4169
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004170uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004171Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004172{
4173 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4174 "Channel::PrepareEncodeAndSend()");
4175
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004176 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004177 {
4178 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4179 "Channel::PrepareEncodeAndSend() invalid audio frame");
4180 return -1;
4181 }
4182
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004183 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00004184 {
4185 MixOrReplaceAudioWithFile(mixingFrequency);
4186 }
4187
wu@webrtc.org63420662013-10-17 18:28:55 +00004188 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004189 {
4190 AudioFrameOperations::Mute(_audioFrame);
4191 }
4192
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004193 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00004194 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004195 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004196 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004197 if (_inputExternalMediaCallbackPtr)
4198 {
4199 _inputExternalMediaCallbackPtr->Process(
4200 _channelId,
4201 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004202 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004203 _audioFrame.samples_per_channel_,
4204 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004205 isStereo);
4206 }
4207 }
4208
4209 InsertInbandDtmfTone();
4210
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004211 if (_includeAudioLevelIndication) {
4212 // Performs level analysis only; does not affect the signal.
4213 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4214 if (err) {
4215 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4216 assert(false);
4217 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004218 }
4219
niklase@google.com470e71d2011-07-07 08:21:25 +00004220 return 0;
4221}
4222
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004223uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004224Channel::EncodeAndSend()
4225{
4226 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4227 "Channel::EncodeAndSend()");
4228
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004229 assert(_audioFrame.num_channels_ <= 2);
4230 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004231 {
4232 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4233 "Channel::EncodeAndSend() invalid audio frame");
4234 return -1;
4235 }
4236
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004237 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004238
4239 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4240
4241 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004242 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004243 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004244 {
4245 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4246 "Channel::EncodeAndSend() ACM encoding failed");
4247 return -1;
4248 }
4249
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004250 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004251
4252 // --- Encode if complete frame is ready
4253
4254 // This call will trigger AudioPacketizationCallback::SendData if encoding
4255 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004256 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004257}
4258
4259int Channel::RegisterExternalMediaProcessing(
4260 ProcessingTypes type,
4261 VoEMediaProcess& processObject)
4262{
4263 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4264 "Channel::RegisterExternalMediaProcessing()");
4265
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004266 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004267
4268 if (kPlaybackPerChannel == type)
4269 {
4270 if (_outputExternalMediaCallbackPtr)
4271 {
4272 _engineStatisticsPtr->SetLastError(
4273 VE_INVALID_OPERATION, kTraceError,
4274 "Channel::RegisterExternalMediaProcessing() "
4275 "output external media already enabled");
4276 return -1;
4277 }
4278 _outputExternalMediaCallbackPtr = &processObject;
4279 _outputExternalMedia = true;
4280 }
4281 else if (kRecordingPerChannel == type)
4282 {
4283 if (_inputExternalMediaCallbackPtr)
4284 {
4285 _engineStatisticsPtr->SetLastError(
4286 VE_INVALID_OPERATION, kTraceError,
4287 "Channel::RegisterExternalMediaProcessing() "
4288 "output external media already enabled");
4289 return -1;
4290 }
4291 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004292 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00004293 }
4294 return 0;
4295}
4296
4297int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4298{
4299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4300 "Channel::DeRegisterExternalMediaProcessing()");
4301
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004302 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004303
4304 if (kPlaybackPerChannel == type)
4305 {
4306 if (!_outputExternalMediaCallbackPtr)
4307 {
4308 _engineStatisticsPtr->SetLastError(
4309 VE_INVALID_OPERATION, kTraceWarning,
4310 "Channel::DeRegisterExternalMediaProcessing() "
4311 "output external media already disabled");
4312 return 0;
4313 }
4314 _outputExternalMedia = false;
4315 _outputExternalMediaCallbackPtr = NULL;
4316 }
4317 else if (kRecordingPerChannel == type)
4318 {
4319 if (!_inputExternalMediaCallbackPtr)
4320 {
4321 _engineStatisticsPtr->SetLastError(
4322 VE_INVALID_OPERATION, kTraceWarning,
4323 "Channel::DeRegisterExternalMediaProcessing() "
4324 "input external media already disabled");
4325 return 0;
4326 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004327 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00004328 _inputExternalMediaCallbackPtr = NULL;
4329 }
4330
4331 return 0;
4332}
4333
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004334int Channel::SetExternalMixing(bool enabled) {
4335 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4336 "Channel::SetExternalMixing(enabled=%d)", enabled);
4337
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004338 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004339 {
4340 _engineStatisticsPtr->SetLastError(
4341 VE_INVALID_OPERATION, kTraceError,
4342 "Channel::SetExternalMixing() "
4343 "external mixing cannot be changed while playing.");
4344 return -1;
4345 }
4346
4347 _externalMixing = enabled;
4348
4349 return 0;
4350}
4351
niklase@google.com470e71d2011-07-07 08:21:25 +00004352int
niklase@google.com470e71d2011-07-07 08:21:25 +00004353Channel::GetNetworkStatistics(NetworkStatistics& stats)
4354{
4355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4356 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004357 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004358 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004359 if (return_value >= 0) {
4360 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4361 }
4362 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004363}
4364
wu@webrtc.org24301a62013-12-13 19:17:43 +00004365void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4366 audio_coding_->GetDecodingCallStatistics(stats);
4367}
4368
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004369bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4370 int* playout_buffer_delay_ms) const {
4371 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004372 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004373 "Channel::GetDelayEstimate() no valid estimate.");
4374 return false;
4375 }
4376 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4377 _recPacketDelayMs;
4378 *playout_buffer_delay_ms = playout_delay_ms_;
4379 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4380 "Channel::GetDelayEstimate()");
4381 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004382}
4383
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004384int Channel::SetInitialPlayoutDelay(int delay_ms)
4385{
4386 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4387 "Channel::SetInitialPlayoutDelay()");
4388 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4389 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4390 {
4391 _engineStatisticsPtr->SetLastError(
4392 VE_INVALID_ARGUMENT, kTraceError,
4393 "SetInitialPlayoutDelay() invalid min delay");
4394 return -1;
4395 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004396 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004397 {
4398 _engineStatisticsPtr->SetLastError(
4399 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4400 "SetInitialPlayoutDelay() failed to set min playout delay");
4401 return -1;
4402 }
4403 return 0;
4404}
4405
4406
niklase@google.com470e71d2011-07-07 08:21:25 +00004407int
4408Channel::SetMinimumPlayoutDelay(int delayMs)
4409{
4410 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4411 "Channel::SetMinimumPlayoutDelay()");
4412 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4413 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4414 {
4415 _engineStatisticsPtr->SetLastError(
4416 VE_INVALID_ARGUMENT, kTraceError,
4417 "SetMinimumPlayoutDelay() invalid min delay");
4418 return -1;
4419 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004420 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004421 {
4422 _engineStatisticsPtr->SetLastError(
4423 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4424 "SetMinimumPlayoutDelay() failed to set min playout delay");
4425 return -1;
4426 }
4427 return 0;
4428}
4429
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004430void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4431 uint32_t playout_timestamp = 0;
4432
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004433 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004434 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4435 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4436 " timestamp from the ACM");
4437 _engineStatisticsPtr->SetLastError(
4438 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4439 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4440 return;
4441 }
4442
4443 uint16_t delay_ms = 0;
4444 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4445 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4446 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4447 " delay from the ADM");
4448 _engineStatisticsPtr->SetLastError(
4449 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4450 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4451 return;
4452 }
4453
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004454 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004455 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004456 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004457 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4458 playout_frequency = 8000;
4459 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4460 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004461 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004462 }
4463
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004464 jitter_buffer_playout_timestamp_ = playout_timestamp;
4465
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004466 // Remove the playout delay.
4467 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4468
4469 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4470 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4471 playout_timestamp);
4472
4473 if (rtcp) {
4474 playout_timestamp_rtcp_ = playout_timestamp;
4475 } else {
4476 playout_timestamp_rtp_ = playout_timestamp;
4477 }
4478 playout_delay_ms_ = delay_ms;
4479}
4480
4481int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4482 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4483 "Channel::GetPlayoutTimestamp()");
4484 if (playout_timestamp_rtp_ == 0) {
4485 _engineStatisticsPtr->SetLastError(
4486 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4487 "GetPlayoutTimestamp() failed to retrieve timestamp");
4488 return -1;
4489 }
4490 timestamp = playout_timestamp_rtp_;
4491 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4492 VoEId(_instanceId,_channelId),
4493 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4494 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004495}
4496
4497int
4498Channel::SetInitTimestamp(unsigned int timestamp)
4499{
4500 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4501 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004502 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004503 {
4504 _engineStatisticsPtr->SetLastError(
4505 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4506 return -1;
4507 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004508 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004509 {
4510 _engineStatisticsPtr->SetLastError(
4511 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4512 "SetInitTimestamp() failed to set timestamp");
4513 return -1;
4514 }
4515 return 0;
4516}
4517
4518int
4519Channel::SetInitSequenceNumber(short sequenceNumber)
4520{
4521 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4522 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004523 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004524 {
4525 _engineStatisticsPtr->SetLastError(
4526 VE_SENDING, kTraceError,
4527 "SetInitSequenceNumber() already sending");
4528 return -1;
4529 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004530 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004531 {
4532 _engineStatisticsPtr->SetLastError(
4533 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4534 "SetInitSequenceNumber() failed to set sequence number");
4535 return -1;
4536 }
4537 return 0;
4538}
4539
4540int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004541Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004542{
4543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4544 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004545 *rtpRtcpModule = _rtpRtcpModule.get();
4546 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004547 return 0;
4548}
4549
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004550// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4551// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004552int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004553Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004554{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004555 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004556 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004557
4558 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004559 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004560
4561 if (_inputFilePlayerPtr == NULL)
4562 {
4563 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4564 VoEId(_instanceId, _channelId),
4565 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4566 " doesnt exist");
4567 return -1;
4568 }
4569
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004570 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004571 fileSamples,
4572 mixingFrequency) == -1)
4573 {
4574 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4575 VoEId(_instanceId, _channelId),
4576 "Channel::MixOrReplaceAudioWithFile() file mixing "
4577 "failed");
4578 return -1;
4579 }
4580 if (fileSamples == 0)
4581 {
4582 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4583 VoEId(_instanceId, _channelId),
4584 "Channel::MixOrReplaceAudioWithFile() file is ended");
4585 return 0;
4586 }
4587 }
4588
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004589 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004590
4591 if (_mixFileWithMicrophone)
4592 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004593 // Currently file stream is always mono.
4594 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004595 MixWithSat(_audioFrame.data_,
4596 _audioFrame.num_channels_,
4597 fileBuffer.get(),
4598 1,
4599 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004600 }
4601 else
4602 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004603 // Replace ACM audio with file.
4604 // Currently file stream is always mono.
4605 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004606 _audioFrame.UpdateFrame(_channelId,
4607 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004608 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004609 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004610 mixingFrequency,
4611 AudioFrame::kNormalSpeech,
4612 AudioFrame::kVadUnknown,
4613 1);
4614
4615 }
4616 return 0;
4617}
4618
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004619int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004620Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004621 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004622{
4623 assert(mixingFrequency <= 32000);
4624
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004625 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004626 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004627
4628 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004629 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004630
4631 if (_outputFilePlayerPtr == NULL)
4632 {
4633 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4634 VoEId(_instanceId, _channelId),
4635 "Channel::MixAudioWithFile() file mixing failed");
4636 return -1;
4637 }
4638
4639 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004640 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004641 fileSamples,
4642 mixingFrequency) == -1)
4643 {
4644 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4645 VoEId(_instanceId, _channelId),
4646 "Channel::MixAudioWithFile() file mixing failed");
4647 return -1;
4648 }
4649 }
4650
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004651 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004652 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004653 // Currently file stream is always mono.
4654 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004655 MixWithSat(audioFrame.data_,
4656 audioFrame.num_channels_,
4657 fileBuffer.get(),
4658 1,
4659 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004660 }
4661 else
4662 {
4663 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004664 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004665 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004666 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004667 return -1;
4668 }
4669
4670 return 0;
4671}
4672
4673int
4674Channel::InsertInbandDtmfTone()
4675{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004676 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004677 if (_inbandDtmfQueue.PendingDtmf() &&
4678 !_inbandDtmfGenerator.IsAddingTone() &&
4679 _inbandDtmfGenerator.DelaySinceLastTone() >
4680 kMinTelephoneEventSeparationMs)
4681 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004682 int8_t eventCode(0);
4683 uint16_t lengthMs(0);
4684 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004685
4686 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4687 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4688 if (_playInbandDtmfEvent)
4689 {
4690 // Add tone to output mixer using a reduced length to minimize
4691 // risk of echo.
4692 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4693 attenuationDb);
4694 }
4695 }
4696
4697 if (_inbandDtmfGenerator.IsAddingTone())
4698 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004699 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004700 _inbandDtmfGenerator.GetSampleRate(frequency);
4701
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004702 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004703 {
4704 // Update sample rate of Dtmf tone since the mixing frequency
4705 // has changed.
4706 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004707 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004708 // Reset the tone to be added taking the new sample rate into
4709 // account.
4710 _inbandDtmfGenerator.ResetTone();
4711 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004712
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004713 int16_t toneBuffer[320];
4714 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004715 // Get 10ms tone segment and set time since last tone to zero
4716 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4717 {
4718 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4719 VoEId(_instanceId, _channelId),
4720 "Channel::EncodeAndSend() inserting Dtmf failed");
4721 return -1;
4722 }
4723
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004724 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004725 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004726 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004727 sample++)
4728 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004729 for (int channel = 0;
4730 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004731 channel++)
4732 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004733 const int index = sample * _audioFrame.num_channels_ + channel;
4734 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004735 }
4736 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004737
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004738 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004739 } else
4740 {
4741 // Add 10ms to "delay-since-last-tone" counter
4742 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4743 }
4744 return 0;
4745}
4746
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004747int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004748Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4749{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004750 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004751 if (_transportPtr == NULL)
4752 {
4753 return -1;
4754 }
4755 if (!RTCP)
4756 {
4757 return _transportPtr->SendPacket(_channelId, data, len);
4758 }
4759 else
4760 {
4761 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4762 }
4763}
4764
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004765// Called for incoming RTP packets after successful RTP header parsing.
4766void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4767 uint16_t sequence_number) {
4768 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4769 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4770 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004771
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004772 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004773 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004774
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004775 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004776 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004777 return;
4778 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004779
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004780 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004781 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004782
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004783 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4784 // Even though the actual sampling rate for G.722 audio is
4785 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4786 // 8,000 Hz because that value was erroneously assigned in
4787 // RFC 1890 and must remain unchanged for backward compatibility.
4788 rtp_receive_frequency = 8000;
4789 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4790 // We are resampling Opus internally to 32,000 Hz until all our
4791 // DSP routines can operate at 48,000 Hz, but the RTP clock
4792 // rate for the Opus payload format is standardized to 48,000 Hz,
4793 // because that is the maximum supported decoding sampling rate.
4794 rtp_receive_frequency = 48000;
4795 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004796
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004797 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4798 // every incoming packet.
4799 uint32_t timestamp_diff_ms = (rtp_timestamp -
4800 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004801 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4802 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4803 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4804 // timestamp, the resulting difference is negative, but is set to zero.
4805 // This can happen when a network glitch causes a packet to arrive late,
4806 // and during long comfort noise periods with clock drift.
4807 timestamp_diff_ms = 0;
4808 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004809
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004810 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4811 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004812
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004813 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004814
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004815 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004816
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004817 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4818 _recPacketDelayMs = packet_delay_ms;
4819 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004820
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004821 if (_average_jitter_buffer_delay_us == 0) {
4822 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4823 return;
4824 }
4825
4826 // Filter average delay value using exponential filter (alpha is
4827 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4828 // risk of rounding error) and compensate for it in GetDelayEstimate()
4829 // later.
4830 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4831 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004832}
4833
4834void
4835Channel::RegisterReceiveCodecsToRTPModule()
4836{
4837 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4838 "Channel::RegisterReceiveCodecsToRTPModule()");
4839
4840
4841 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004842 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004843
4844 for (int idx = 0; idx < nSupportedCodecs; idx++)
4845 {
4846 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004847 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004848 (rtp_receiver_->RegisterReceivePayload(
4849 codec.plname,
4850 codec.pltype,
4851 codec.plfreq,
4852 codec.channels,
4853 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004854 {
4855 WEBRTC_TRACE(
4856 kTraceWarning,
4857 kTraceVoice,
4858 VoEId(_instanceId, _channelId),
4859 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4860 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4861 codec.plname, codec.pltype, codec.plfreq,
4862 codec.channels, codec.rate);
4863 }
4864 else
4865 {
4866 WEBRTC_TRACE(
4867 kTraceInfo,
4868 kTraceVoice,
4869 VoEId(_instanceId, _channelId),
4870 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004871 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004872 "receiver",
4873 codec.plname, codec.pltype, codec.plfreq,
4874 codec.channels, codec.rate);
4875 }
4876 }
4877}
4878
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004879int Channel::SetSecondarySendCodec(const CodecInst& codec,
4880 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004881 // Sanity check for payload type.
4882 if (red_payload_type < 0 || red_payload_type > 127) {
4883 _engineStatisticsPtr->SetLastError(
4884 VE_PLTYPE_ERROR, kTraceError,
4885 "SetRedPayloadType() invalid RED payload type");
4886 return -1;
4887 }
4888
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004889 if (SetRedPayloadType(red_payload_type) < 0) {
4890 _engineStatisticsPtr->SetLastError(
4891 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4892 "SetSecondarySendCodec() Failed to register RED ACM");
4893 return -1;
4894 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004895 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004896 _engineStatisticsPtr->SetLastError(
4897 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4898 "SetSecondarySendCodec() Failed to register secondary send codec in "
4899 "ACM");
4900 return -1;
4901 }
4902
4903 return 0;
4904}
4905
4906void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004907 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004908}
4909
4910int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004911 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004912 _engineStatisticsPtr->SetLastError(
4913 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4914 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4915 return -1;
4916 }
4917 return 0;
4918}
4919
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004920// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004921int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004922 CodecInst codec;
4923 bool found_red = false;
4924
4925 // Get default RED settings from the ACM database
4926 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4927 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004928 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004929 if (!STR_CASE_CMP(codec.plname, "RED")) {
4930 found_red = true;
4931 break;
4932 }
4933 }
4934
4935 if (!found_red) {
4936 _engineStatisticsPtr->SetLastError(
4937 VE_CODEC_ERROR, kTraceError,
4938 "SetRedPayloadType() RED is not supported");
4939 return -1;
4940 }
4941
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004942 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004943 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004944 _engineStatisticsPtr->SetLastError(
4945 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4946 "SetRedPayloadType() RED registration in ACM module failed");
4947 return -1;
4948 }
4949
4950 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4951 _engineStatisticsPtr->SetLastError(
4952 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4953 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4954 return -1;
4955 }
4956 return 0;
4957}
4958
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004959int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4960 unsigned char id) {
4961 int error = 0;
4962 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4963 if (enable) {
4964 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4965 }
4966 return error;
4967}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004968} // namespace voe
4969} // namespace webrtc