blob: 56a2d6c54ac7e6fda1d60b8a9390ab7286e49e57 [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),
xians@google.com22963ab2011-08-03 12:40:23 +0000882 _rxVadObserverPtr(NULL),
883 _oldVadDecision(-1),
884 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 _rtpObserverPtr(NULL),
886 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000887 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000888 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _inputIsOnHold(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000890 _mixFileWithMicrophone(false),
891 _rtpObserver(false),
892 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 _mute(false),
894 _panLeft(1.0f),
895 _panRight(1.0f),
896 _outputGain(1.0f),
897 _playOutbandDtmfEvent(false),
898 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000899 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000900 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000902 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _rtpPacketTimedOut(false),
904 _rtpPacketTimeOutIsEnabled(false),
905 _rtpTimeOutSeconds(0),
906 _connectionObserver(false),
907 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000908 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000909 vie_network_(NULL),
910 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000911 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000912 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000913 _previousTimestamp(0),
914 _recPacketDelayMs(20),
915 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000917 _rxNsIsEnabled(false),
918 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000919{
920 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
921 "Channel::Channel() - ctor");
922 _inbandDtmfQueue.ResetDtmf();
923 _inbandDtmfGenerator.Init();
924 _outputAudioLevel.Clear();
925
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000926 RtpRtcp::Configuration configuration;
927 configuration.id = VoEModuleId(instanceId, channelId);
928 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000929 configuration.outgoing_transport = this;
930 configuration.rtcp_feedback = this;
931 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000932 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000933
934 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000935
936 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
937 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
938 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000939
940 Config audioproc_config;
941 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
942 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000943}
944
945Channel::~Channel()
946{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000947 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
949 "Channel::~Channel() - dtor");
950
951 if (_outputExternalMedia)
952 {
953 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
954 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000955 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 {
957 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
958 }
959 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 StopPlayout();
961
962 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000963 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000964 if (_inputFilePlayerPtr)
965 {
966 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
967 _inputFilePlayerPtr->StopPlayingFile();
968 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
969 _inputFilePlayerPtr = NULL;
970 }
971 if (_outputFilePlayerPtr)
972 {
973 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
974 _outputFilePlayerPtr->StopPlayingFile();
975 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
976 _outputFilePlayerPtr = NULL;
977 }
978 if (_outputFileRecorderPtr)
979 {
980 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
981 _outputFileRecorderPtr->StopRecording();
982 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
983 _outputFileRecorderPtr = NULL;
984 }
985 }
986
987 // The order to safely shutdown modules in a channel is:
988 // 1. De-register callbacks in modules
989 // 2. De-register modules in process thread
990 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000991 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
993 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
994 VoEId(_instanceId,_channelId),
995 "~Channel() failed to de-register transport callback"
996 " (Audio coding module)");
997 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000998 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000999 {
1000 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1001 VoEId(_instanceId,_channelId),
1002 "~Channel() failed to de-register VAD callback"
1003 " (Audio coding module)");
1004 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001006 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 {
1008 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1009 VoEId(_instanceId,_channelId),
1010 "~Channel() failed to deregister RTP/RTCP module");
1011 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001012 // End of modules shutdown
1013
1014 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001015 if (vie_network_) {
1016 vie_network_->Release();
1017 vie_network_ = NULL;
1018 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1020 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001022 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001023 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001024}
1025
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001026int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001027Channel::Init()
1028{
1029 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1030 "Channel::Init()");
1031
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001032 channel_state_.Reset();
1033
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 // --- Initial sanity
1035
1036 if ((_engineStatisticsPtr == NULL) ||
1037 (_moduleProcessThreadPtr == NULL))
1038 {
1039 WEBRTC_TRACE(kTraceError, kTraceVoice,
1040 VoEId(_instanceId,_channelId),
1041 "Channel::Init() must call SetEngineInformation() first");
1042 return -1;
1043 }
1044
1045 // --- Add modules to process thread (for periodic schedulation)
1046
1047 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001048 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 if (processThreadFail)
1051 {
1052 _engineStatisticsPtr->SetLastError(
1053 VE_CANNOT_INIT_CHANNEL, kTraceError,
1054 "Channel::Init() modules not registered");
1055 return -1;
1056 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001057 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001058
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001059 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001060#ifdef WEBRTC_CODEC_AVT
1061 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001062 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001063#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001064 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 {
1066 _engineStatisticsPtr->SetLastError(
1067 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1068 "Channel::Init() unable to initialize the ACM - 1");
1069 return -1;
1070 }
1071
1072 // --- RTP/RTCP module initialization
1073
1074 // Ensure that RTCP is enabled by default for the created channel.
1075 // Note that, the module will keep generating RTCP until it is explicitly
1076 // disabled by the user.
1077 // After StopListen (when no sockets exists), RTCP packets will no longer
1078 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001079 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1080 // RTCP is enabled by default.
1081 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001082 {
1083 _engineStatisticsPtr->SetLastError(
1084 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1085 "Channel::Init() RTP/RTCP module not initialized");
1086 return -1;
1087 }
1088
1089 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001091 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1092 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001093
1094 if (fail)
1095 {
1096 _engineStatisticsPtr->SetLastError(
1097 VE_CANNOT_INIT_CHANNEL, kTraceError,
1098 "Channel::Init() callbacks not registered");
1099 return -1;
1100 }
1101
1102 // --- Register all supported codecs to the receiving side of the
1103 // RTP/RTCP module
1104
1105 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001106 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001107
1108 for (int idx = 0; idx < nSupportedCodecs; idx++)
1109 {
1110 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001111 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001112 (rtp_receiver_->RegisterReceivePayload(
1113 codec.plname,
1114 codec.pltype,
1115 codec.plfreq,
1116 codec.channels,
1117 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001118 {
1119 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1120 VoEId(_instanceId,_channelId),
1121 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1122 "to RTP/RTCP receiver",
1123 codec.plname, codec.pltype, codec.plfreq,
1124 codec.channels, codec.rate);
1125 }
1126 else
1127 {
1128 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1129 VoEId(_instanceId,_channelId),
1130 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1131 "the RTP/RTCP receiver",
1132 codec.plname, codec.pltype, codec.plfreq,
1133 codec.channels, codec.rate);
1134 }
1135
1136 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001137 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001138 {
1139 SetSendCodec(codec);
1140 }
1141
1142 // Register default PT for outband 'telephone-event'
1143 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1144 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001145 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001146 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 {
1148 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1149 VoEId(_instanceId,_channelId),
1150 "Channel::Init() failed to register outband "
1151 "'telephone-event' (%d/%d) correctly",
1152 codec.pltype, codec.plfreq);
1153 }
1154 }
1155
1156 if (!STR_CASE_CMP(codec.plname, "CN"))
1157 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001158 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1159 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001160 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 {
1162 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1163 VoEId(_instanceId,_channelId),
1164 "Channel::Init() failed to register CN (%d/%d) "
1165 "correctly - 1",
1166 codec.pltype, codec.plfreq);
1167 }
1168 }
1169#ifdef WEBRTC_CODEC_RED
1170 // Register RED to the receiving side of the ACM.
1171 // We will not receive an OnInitializeDecoder() callback for RED.
1172 if (!STR_CASE_CMP(codec.plname, "RED"))
1173 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001174 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001175 {
1176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1177 VoEId(_instanceId,_channelId),
1178 "Channel::Init() failed to register RED (%d/%d) "
1179 "correctly",
1180 codec.pltype, codec.plfreq);
1181 }
1182 }
1183#endif
1184 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001185
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001186 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1187 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1188 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001189 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001190 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1191 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1192 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001193 }
1194
1195 return 0;
1196}
1197
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001198int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001199Channel::SetEngineInformation(Statistics& engineStatistics,
1200 OutputMixer& outputMixer,
1201 voe::TransmitMixer& transmitMixer,
1202 ProcessThread& moduleProcessThread,
1203 AudioDeviceModule& audioDeviceModule,
1204 VoiceEngineObserver* voiceEngineObserver,
1205 CriticalSectionWrapper* callbackCritSect)
1206{
1207 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1208 "Channel::SetEngineInformation()");
1209 _engineStatisticsPtr = &engineStatistics;
1210 _outputMixerPtr = &outputMixer;
1211 _transmitMixerPtr = &transmitMixer,
1212 _moduleProcessThreadPtr = &moduleProcessThread;
1213 _audioDeviceModulePtr = &audioDeviceModule;
1214 _voiceEngineObserverPtr = voiceEngineObserver;
1215 _callbackCritSectPtr = callbackCritSect;
1216 return 0;
1217}
1218
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001219int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001220Channel::UpdateLocalTimeStamp()
1221{
1222
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001223 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001224 return 0;
1225}
1226
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001227int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001228Channel::StartPlayout()
1229{
1230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1231 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001232 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001233 {
1234 return 0;
1235 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001236
1237 if (!_externalMixing) {
1238 // Add participant as candidates for mixing.
1239 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1240 {
1241 _engineStatisticsPtr->SetLastError(
1242 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1243 "StartPlayout() failed to add participant to mixer");
1244 return -1;
1245 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 }
1247
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001248 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001249 if (RegisterFilePlayingToMixer() != 0)
1250 return -1;
1251
niklase@google.com470e71d2011-07-07 08:21:25 +00001252 return 0;
1253}
1254
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001255int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001256Channel::StopPlayout()
1257{
1258 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1259 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001260 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 {
1262 return 0;
1263 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001264
1265 if (!_externalMixing) {
1266 // Remove participant as candidates for mixing
1267 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1268 {
1269 _engineStatisticsPtr->SetLastError(
1270 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1271 "StopPlayout() failed to remove participant from mixer");
1272 return -1;
1273 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 }
1275
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001276 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 _outputAudioLevel.Clear();
1278
1279 return 0;
1280}
1281
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001282int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001283Channel::StartSend()
1284{
1285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1286 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001287 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001288 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001289 if (send_sequence_number_)
1290 SetInitSequenceNumber(send_sequence_number_);
1291
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001292 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001294 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001296 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001297
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001298 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 {
1300 _engineStatisticsPtr->SetLastError(
1301 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1302 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001303 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001304 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 return -1;
1306 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001307
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 return 0;
1309}
1310
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001311int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001312Channel::StopSend()
1313{
1314 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1315 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001316 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001317 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001318 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001320 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001321
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001322 // Store the sequence number to be able to pick up the same sequence for
1323 // the next StartSend(). This is needed for restarting device, otherwise
1324 // it might cause libSRTP to complain about packets being replayed.
1325 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1326 // CL is landed. See issue
1327 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1328 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1329
niklase@google.com470e71d2011-07-07 08:21:25 +00001330 // Reset sending SSRC and sequence number and triggers direct transmission
1331 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001332 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1333 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001334 {
1335 _engineStatisticsPtr->SetLastError(
1336 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1337 "StartSend() RTP/RTCP failed to stop sending");
1338 }
1339
niklase@google.com470e71d2011-07-07 08:21:25 +00001340 return 0;
1341}
1342
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001343int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001344Channel::StartReceiving()
1345{
1346 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1347 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001348 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001349 {
1350 return 0;
1351 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001352 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 _numberOfDiscardedPackets = 0;
1354 return 0;
1355}
1356
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001357int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001358Channel::StopReceiving()
1359{
1360 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1361 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001362 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 {
1364 return 0;
1365 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001366
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001367 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001368 return 0;
1369}
1370
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001371int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001372Channel::SetNetEQPlayoutMode(NetEqModes mode)
1373{
1374 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1375 "Channel::SetNetEQPlayoutMode()");
1376 AudioPlayoutMode playoutMode(voice);
1377 switch (mode)
1378 {
1379 case kNetEqDefault:
1380 playoutMode = voice;
1381 break;
1382 case kNetEqStreaming:
1383 playoutMode = streaming;
1384 break;
1385 case kNetEqFax:
1386 playoutMode = fax;
1387 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001388 case kNetEqOff:
1389 playoutMode = off;
1390 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001392 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001393 {
1394 _engineStatisticsPtr->SetLastError(
1395 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1396 "SetNetEQPlayoutMode() failed to set playout mode");
1397 return -1;
1398 }
1399 return 0;
1400}
1401
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001402int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001403Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1404{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001405 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001406 switch (playoutMode)
1407 {
1408 case voice:
1409 mode = kNetEqDefault;
1410 break;
1411 case streaming:
1412 mode = kNetEqStreaming;
1413 break;
1414 case fax:
1415 mode = kNetEqFax;
1416 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001417 case off:
1418 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001419 }
1420 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1421 VoEId(_instanceId,_channelId),
1422 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1423 return 0;
1424}
1425
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001426int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001427Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1428{
1429 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1430 "Channel::SetOnHoldStatus()");
1431 if (mode == kHoldSendAndPlay)
1432 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001433 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001434 _inputIsOnHold = enable;
1435 }
1436 else if (mode == kHoldPlayOnly)
1437 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001438 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001439 }
1440 if (mode == kHoldSendOnly)
1441 {
1442 _inputIsOnHold = enable;
1443 }
1444 return 0;
1445}
1446
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001447int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001448Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1449{
1450 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1451 "Channel::GetOnHoldStatus()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001452 bool output_is_on_hold = channel_state_.Get().output_is_on_hold;
1453 enabled = (output_is_on_hold || _inputIsOnHold);
1454 if (output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001455 {
1456 mode = kHoldSendAndPlay;
1457 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001458 else if (output_is_on_hold && !_inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001459 {
1460 mode = kHoldPlayOnly;
1461 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001462 else if (!output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001463 {
1464 mode = kHoldSendOnly;
1465 }
1466 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1467 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1468 enabled, mode);
1469 return 0;
1470}
1471
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001472int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001473Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1474{
1475 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1476 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001477 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001478
1479 if (_voiceEngineObserverPtr)
1480 {
1481 _engineStatisticsPtr->SetLastError(
1482 VE_INVALID_OPERATION, kTraceError,
1483 "RegisterVoiceEngineObserver() observer already enabled");
1484 return -1;
1485 }
1486 _voiceEngineObserverPtr = &observer;
1487 return 0;
1488}
1489
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001490int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001491Channel::DeRegisterVoiceEngineObserver()
1492{
1493 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1494 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001495 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001496
1497 if (!_voiceEngineObserverPtr)
1498 {
1499 _engineStatisticsPtr->SetLastError(
1500 VE_INVALID_OPERATION, kTraceWarning,
1501 "DeRegisterVoiceEngineObserver() observer already disabled");
1502 return 0;
1503 }
1504 _voiceEngineObserverPtr = NULL;
1505 return 0;
1506}
1507
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001508int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001509Channel::GetSendCodec(CodecInst& codec)
1510{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001511 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001512}
1513
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001514int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001515Channel::GetRecCodec(CodecInst& codec)
1516{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001517 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001518}
1519
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001520int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001521Channel::SetSendCodec(const CodecInst& codec)
1522{
1523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1524 "Channel::SetSendCodec()");
1525
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001526 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001527 {
1528 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1529 "SetSendCodec() failed to register codec to ACM");
1530 return -1;
1531 }
1532
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001533 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001535 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1536 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001537 {
1538 WEBRTC_TRACE(
1539 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1540 "SetSendCodec() failed to register codec to"
1541 " RTP/RTCP module");
1542 return -1;
1543 }
1544 }
1545
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001546 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001547 {
1548 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1549 "SetSendCodec() failed to set audio packet size");
1550 return -1;
1551 }
1552
1553 return 0;
1554}
1555
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001556int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001557Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1558{
1559 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1560 "Channel::SetVADStatus(mode=%d)", mode);
1561 // To disable VAD, DTX must be disabled too
1562 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001563 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001564 {
1565 _engineStatisticsPtr->SetLastError(
1566 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1567 "SetVADStatus() failed to set VAD");
1568 return -1;
1569 }
1570 return 0;
1571}
1572
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001573int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001574Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1575{
1576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1577 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001578 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001579 {
1580 _engineStatisticsPtr->SetLastError(
1581 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1582 "GetVADStatus() failed to get VAD status");
1583 return -1;
1584 }
1585 disabledDTX = !disabledDTX;
1586 return 0;
1587}
1588
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001589int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001590Channel::SetRecPayloadType(const CodecInst& codec)
1591{
1592 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1593 "Channel::SetRecPayloadType()");
1594
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001595 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 {
1597 _engineStatisticsPtr->SetLastError(
1598 VE_ALREADY_PLAYING, kTraceError,
1599 "SetRecPayloadType() unable to set PT while playing");
1600 return -1;
1601 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001602 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001603 {
1604 _engineStatisticsPtr->SetLastError(
1605 VE_ALREADY_LISTENING, kTraceError,
1606 "SetRecPayloadType() unable to set PT while listening");
1607 return -1;
1608 }
1609
1610 if (codec.pltype == -1)
1611 {
1612 // De-register the selected codec (RTP/RTCP module and ACM)
1613
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001614 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001615 CodecInst rxCodec = codec;
1616
1617 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001618 rtp_payload_registry_->ReceivePayloadType(
1619 rxCodec.plname,
1620 rxCodec.plfreq,
1621 rxCodec.channels,
1622 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1623 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001624 rxCodec.pltype = pltype;
1625
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001626 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001627 {
1628 _engineStatisticsPtr->SetLastError(
1629 VE_RTP_RTCP_MODULE_ERROR,
1630 kTraceError,
1631 "SetRecPayloadType() RTP/RTCP-module deregistration "
1632 "failed");
1633 return -1;
1634 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001635 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001636 {
1637 _engineStatisticsPtr->SetLastError(
1638 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1639 "SetRecPayloadType() ACM deregistration failed - 1");
1640 return -1;
1641 }
1642 return 0;
1643 }
1644
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001645 if (rtp_receiver_->RegisterReceivePayload(
1646 codec.plname,
1647 codec.pltype,
1648 codec.plfreq,
1649 codec.channels,
1650 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001651 {
1652 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001653 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1654 if (rtp_receiver_->RegisterReceivePayload(
1655 codec.plname,
1656 codec.pltype,
1657 codec.plfreq,
1658 codec.channels,
1659 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001660 {
1661 _engineStatisticsPtr->SetLastError(
1662 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1663 "SetRecPayloadType() RTP/RTCP-module registration failed");
1664 return -1;
1665 }
1666 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001667 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001669 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1670 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674 "SetRecPayloadType() ACM registration failed - 1");
1675 return -1;
1676 }
1677 }
1678 return 0;
1679}
1680
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001681int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001682Channel::GetRecPayloadType(CodecInst& codec)
1683{
1684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1685 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001686 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001687 if (rtp_payload_registry_->ReceivePayloadType(
1688 codec.plname,
1689 codec.plfreq,
1690 codec.channels,
1691 (codec.rate < 0) ? 0 : codec.rate,
1692 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001693 {
1694 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001695 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001696 "GetRecPayloadType() failed to retrieve RX payload type");
1697 return -1;
1698 }
1699 codec.pltype = payloadType;
1700 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1701 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1702 return 0;
1703}
1704
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001705int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001706Channel::SetAMREncFormat(AmrMode mode)
1707{
1708 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1709 "Channel::SetAMREncFormat()");
1710
1711 // ACM doesn't support AMR
1712 return -1;
1713}
1714
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001715int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001716Channel::SetAMRDecFormat(AmrMode mode)
1717{
1718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1719 "Channel::SetAMRDecFormat()");
1720
1721 // ACM doesn't support AMR
1722 return -1;
1723}
1724
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001725int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001726Channel::SetAMRWbEncFormat(AmrMode mode)
1727{
1728 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1729 "Channel::SetAMRWbEncFormat()");
1730
1731 // ACM doesn't support AMR
1732 return -1;
1733
1734}
1735
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001736int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001737Channel::SetAMRWbDecFormat(AmrMode mode)
1738{
1739 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1740 "Channel::SetAMRWbDecFormat()");
1741
1742 // ACM doesn't support AMR
1743 return -1;
1744}
1745
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001746int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001747Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1748{
1749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1750 "Channel::SetSendCNPayloadType()");
1751
1752 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001753 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001754 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001755 if (frequency == kFreq32000Hz)
1756 samplingFreqHz = 32000;
1757 else if (frequency == kFreq16000Hz)
1758 samplingFreqHz = 16000;
1759
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001760 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001761 {
1762 _engineStatisticsPtr->SetLastError(
1763 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1764 "SetSendCNPayloadType() failed to retrieve default CN codec "
1765 "settings");
1766 return -1;
1767 }
1768
1769 // Modify the payload type (must be set to dynamic range)
1770 codec.pltype = type;
1771
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001772 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001773 {
1774 _engineStatisticsPtr->SetLastError(
1775 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1776 "SetSendCNPayloadType() failed to register CN to ACM");
1777 return -1;
1778 }
1779
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001780 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001782 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1783 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001784 {
1785 _engineStatisticsPtr->SetLastError(
1786 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1787 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1788 "module");
1789 return -1;
1790 }
1791 }
1792 return 0;
1793}
1794
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001795int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001796Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1797{
1798 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1799 "Channel::SetISACInitTargetRate()");
1800
1801 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001802 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001803 {
1804 _engineStatisticsPtr->SetLastError(
1805 VE_CODEC_ERROR, kTraceError,
1806 "SetISACInitTargetRate() failed to retrieve send codec");
1807 return -1;
1808 }
1809 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1810 {
1811 // This API is only valid if iSAC is setup to run in channel-adaptive
1812 // mode.
1813 // We do not validate the adaptive mode here. It is done later in the
1814 // ConfigISACBandwidthEstimator() API.
1815 _engineStatisticsPtr->SetLastError(
1816 VE_CODEC_ERROR, kTraceError,
1817 "SetISACInitTargetRate() send codec is not iSAC");
1818 return -1;
1819 }
1820
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001821 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001822 if (16000 == sendCodec.plfreq)
1823 {
1824 // Note that 0 is a valid and corresponds to "use default
1825 if ((rateBps != 0 &&
1826 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1827 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1828 {
1829 _engineStatisticsPtr->SetLastError(
1830 VE_INVALID_ARGUMENT, kTraceError,
1831 "SetISACInitTargetRate() invalid target rate - 1");
1832 return -1;
1833 }
1834 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001835 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001836 }
1837 else if (32000 == sendCodec.plfreq)
1838 {
1839 if ((rateBps != 0 &&
1840 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1841 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1842 {
1843 _engineStatisticsPtr->SetLastError(
1844 VE_INVALID_ARGUMENT, kTraceError,
1845 "SetISACInitTargetRate() invalid target rate - 2");
1846 return -1;
1847 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001849 }
1850
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001851 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001852 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1853 {
1854 _engineStatisticsPtr->SetLastError(
1855 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1856 "SetISACInitTargetRate() iSAC BWE config failed");
1857 return -1;
1858 }
1859
1860 return 0;
1861}
1862
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001863int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001864Channel::SetISACMaxRate(int rateBps)
1865{
1866 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1867 "Channel::SetISACMaxRate()");
1868
1869 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001870 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001871 {
1872 _engineStatisticsPtr->SetLastError(
1873 VE_CODEC_ERROR, kTraceError,
1874 "SetISACMaxRate() failed to retrieve send codec");
1875 return -1;
1876 }
1877 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1878 {
1879 // This API is only valid if iSAC is selected as sending codec.
1880 _engineStatisticsPtr->SetLastError(
1881 VE_CODEC_ERROR, kTraceError,
1882 "SetISACMaxRate() send codec is not iSAC");
1883 return -1;
1884 }
1885 if (16000 == sendCodec.plfreq)
1886 {
1887 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1888 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1889 {
1890 _engineStatisticsPtr->SetLastError(
1891 VE_INVALID_ARGUMENT, kTraceError,
1892 "SetISACMaxRate() invalid max rate - 1");
1893 return -1;
1894 }
1895 }
1896 else if (32000 == sendCodec.plfreq)
1897 {
1898 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1899 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1900 {
1901 _engineStatisticsPtr->SetLastError(
1902 VE_INVALID_ARGUMENT, kTraceError,
1903 "SetISACMaxRate() invalid max rate - 2");
1904 return -1;
1905 }
1906 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001907 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001908 {
1909 _engineStatisticsPtr->SetLastError(
1910 VE_SENDING, kTraceError,
1911 "SetISACMaxRate() unable to set max rate while sending");
1912 return -1;
1913 }
1914
1915 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1916 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001917 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001918 {
1919 _engineStatisticsPtr->SetLastError(
1920 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1921 "SetISACMaxRate() failed to set max rate");
1922 return -1;
1923 }
1924
1925 return 0;
1926}
1927
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001928int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001929Channel::SetISACMaxPayloadSize(int sizeBytes)
1930{
1931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1932 "Channel::SetISACMaxPayloadSize()");
1933 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001934 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 {
1936 _engineStatisticsPtr->SetLastError(
1937 VE_CODEC_ERROR, kTraceError,
1938 "SetISACMaxPayloadSize() failed to retrieve send codec");
1939 return -1;
1940 }
1941 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1942 {
1943 _engineStatisticsPtr->SetLastError(
1944 VE_CODEC_ERROR, kTraceError,
1945 "SetISACMaxPayloadSize() send codec is not iSAC");
1946 return -1;
1947 }
1948 if (16000 == sendCodec.plfreq)
1949 {
1950 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1951 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1952 {
1953 _engineStatisticsPtr->SetLastError(
1954 VE_INVALID_ARGUMENT, kTraceError,
1955 "SetISACMaxPayloadSize() invalid max payload - 1");
1956 return -1;
1957 }
1958 }
1959 else if (32000 == sendCodec.plfreq)
1960 {
1961 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1962 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1963 {
1964 _engineStatisticsPtr->SetLastError(
1965 VE_INVALID_ARGUMENT, kTraceError,
1966 "SetISACMaxPayloadSize() invalid max payload - 2");
1967 return -1;
1968 }
1969 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001970 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001971 {
1972 _engineStatisticsPtr->SetLastError(
1973 VE_SENDING, kTraceError,
1974 "SetISACMaxPayloadSize() unable to set max rate while sending");
1975 return -1;
1976 }
1977
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001978 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001979 {
1980 _engineStatisticsPtr->SetLastError(
1981 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1982 "SetISACMaxPayloadSize() failed to set max payload size");
1983 return -1;
1984 }
1985 return 0;
1986}
1987
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001988int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001989{
1990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1991 "Channel::RegisterExternalTransport()");
1992
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001993 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001994
niklase@google.com470e71d2011-07-07 08:21:25 +00001995 if (_externalTransport)
1996 {
1997 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1998 kTraceError,
1999 "RegisterExternalTransport() external transport already enabled");
2000 return -1;
2001 }
2002 _externalTransport = true;
2003 _transportPtr = &transport;
2004 return 0;
2005}
2006
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002007int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002008Channel::DeRegisterExternalTransport()
2009{
2010 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2011 "Channel::DeRegisterExternalTransport()");
2012
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002013 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002014
niklase@google.com470e71d2011-07-07 08:21:25 +00002015 if (!_transportPtr)
2016 {
2017 _engineStatisticsPtr->SetLastError(
2018 VE_INVALID_OPERATION, kTraceWarning,
2019 "DeRegisterExternalTransport() external transport already "
2020 "disabled");
2021 return 0;
2022 }
2023 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002024 _transportPtr = NULL;
2025 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2026 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002027 return 0;
2028}
2029
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002030int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
2031 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002032 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2033 "Channel::ReceivedRTPPacket()");
2034
2035 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002036 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002037
2038 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002039 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2040 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002041 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2042 VoEId(_instanceId,_channelId),
2043 "Channel::SendPacket() RTP dump to input file failed");
2044 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002045 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002046 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002047 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2048 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2049 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002050 return -1;
2051 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002052 header.payload_type_frequency =
2053 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002054 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002055 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002056 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002057 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002058 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002059 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00002060
2061 // Forward any packets to ViE bandwidth estimator, if enabled.
2062 {
2063 CriticalSectionScoped cs(&_callbackCritSect);
2064 if (vie_network_) {
2065 int64_t arrival_time_ms;
2066 if (packet_time.timestamp != -1) {
2067 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
2068 } else {
2069 arrival_time_ms = TickTime::MillisecondTimestamp();
2070 }
2071 int payload_length = length - header.headerLength;
2072 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
2073 payload_length, header);
2074 }
2075 }
2076
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002077 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002078}
2079
2080bool Channel::ReceivePacket(const uint8_t* packet,
2081 int packet_length,
2082 const RTPHeader& header,
2083 bool in_order) {
2084 if (rtp_payload_registry_->IsEncapsulated(header)) {
2085 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002086 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002087 const uint8_t* payload = packet + header.headerLength;
2088 int payload_length = packet_length - header.headerLength;
2089 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002090 PayloadUnion payload_specific;
2091 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002092 &payload_specific)) {
2093 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002094 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002095 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2096 payload_specific, in_order);
2097}
2098
2099bool Channel::HandleEncapsulation(const uint8_t* packet,
2100 int packet_length,
2101 const RTPHeader& header) {
2102 if (!rtp_payload_registry_->IsRtx(header))
2103 return false;
2104
2105 // Remove the RTX header and parse the original RTP header.
2106 if (packet_length < header.headerLength)
2107 return false;
2108 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2109 return false;
2110 if (restored_packet_in_use_) {
2111 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2112 "Multiple RTX headers detected, dropping packet");
2113 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002114 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002115 uint8_t* restored_packet_ptr = restored_packet_;
2116 if (!rtp_payload_registry_->RestoreOriginalPacket(
2117 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2118 header)) {
2119 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2120 "Incoming RTX packet: invalid RTP header");
2121 return false;
2122 }
2123 restored_packet_in_use_ = true;
2124 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2125 restored_packet_in_use_ = false;
2126 return ret;
2127}
2128
2129bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2130 StreamStatistician* statistician =
2131 rtp_receive_statistics_->GetStatistician(header.ssrc);
2132 if (!statistician)
2133 return false;
2134 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002135}
2136
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002137bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2138 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002139 // Retransmissions are handled separately if RTX is enabled.
2140 if (rtp_payload_registry_->RtxEnabled())
2141 return false;
2142 StreamStatistician* statistician =
2143 rtp_receive_statistics_->GetStatistician(header.ssrc);
2144 if (!statistician)
2145 return false;
2146 // Check if this is a retransmission.
2147 uint16_t min_rtt = 0;
2148 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002149 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002150 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002151}
2152
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002153int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002154 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2155 "Channel::ReceivedRTCPPacket()");
2156 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002157 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002158
2159 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002160 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2161 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002162 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2163 VoEId(_instanceId,_channelId),
2164 "Channel::SendPacket() RTCP dump to input file failed");
2165 }
2166
2167 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002168 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2169 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002170 _engineStatisticsPtr->SetLastError(
2171 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2172 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2173 }
2174 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002175}
2176
niklase@google.com470e71d2011-07-07 08:21:25 +00002177int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002178 bool loop,
2179 FileFormats format,
2180 int startPosition,
2181 float volumeScaling,
2182 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002183 const CodecInst* codecInst)
2184{
2185 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2186 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2187 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2188 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2189 startPosition, stopPosition);
2190
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002191 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002192 {
2193 _engineStatisticsPtr->SetLastError(
2194 VE_ALREADY_PLAYING, kTraceError,
2195 "StartPlayingFileLocally() is already playing");
2196 return -1;
2197 }
2198
niklase@google.com470e71d2011-07-07 08:21:25 +00002199 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002200 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002201
2202 if (_outputFilePlayerPtr)
2203 {
2204 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2205 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2206 _outputFilePlayerPtr = NULL;
2207 }
2208
2209 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2210 _outputFilePlayerId, (const FileFormats)format);
2211
2212 if (_outputFilePlayerPtr == NULL)
2213 {
2214 _engineStatisticsPtr->SetLastError(
2215 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002216 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002217 return -1;
2218 }
2219
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002220 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002221
2222 if (_outputFilePlayerPtr->StartPlayingFile(
2223 fileName,
2224 loop,
2225 startPosition,
2226 volumeScaling,
2227 notificationTime,
2228 stopPosition,
2229 (const CodecInst*)codecInst) != 0)
2230 {
2231 _engineStatisticsPtr->SetLastError(
2232 VE_BAD_FILE, kTraceError,
2233 "StartPlayingFile() failed to start file playout");
2234 _outputFilePlayerPtr->StopPlayingFile();
2235 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2236 _outputFilePlayerPtr = NULL;
2237 return -1;
2238 }
2239 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002240 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002241 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002242
2243 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002244 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002245
2246 return 0;
2247}
2248
2249int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002250 FileFormats format,
2251 int startPosition,
2252 float volumeScaling,
2253 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002254 const CodecInst* codecInst)
2255{
2256 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2257 "Channel::StartPlayingFileLocally(format=%d,"
2258 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2259 format, volumeScaling, startPosition, stopPosition);
2260
2261 if(stream == NULL)
2262 {
2263 _engineStatisticsPtr->SetLastError(
2264 VE_BAD_FILE, kTraceError,
2265 "StartPlayingFileLocally() NULL as input stream");
2266 return -1;
2267 }
2268
2269
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002270 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002271 {
2272 _engineStatisticsPtr->SetLastError(
2273 VE_ALREADY_PLAYING, kTraceError,
2274 "StartPlayingFileLocally() is already playing");
2275 return -1;
2276 }
2277
niklase@google.com470e71d2011-07-07 08:21:25 +00002278 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002279 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002280
2281 // Destroy the old instance
2282 if (_outputFilePlayerPtr)
2283 {
2284 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2285 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2286 _outputFilePlayerPtr = NULL;
2287 }
2288
2289 // Create the instance
2290 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2291 _outputFilePlayerId,
2292 (const FileFormats)format);
2293
2294 if (_outputFilePlayerPtr == NULL)
2295 {
2296 _engineStatisticsPtr->SetLastError(
2297 VE_INVALID_ARGUMENT, kTraceError,
2298 "StartPlayingFileLocally() filePlayer format isnot correct");
2299 return -1;
2300 }
2301
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002302 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002303
2304 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2305 volumeScaling,
2306 notificationTime,
2307 stopPosition, codecInst) != 0)
2308 {
2309 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2310 "StartPlayingFile() failed to "
2311 "start file playout");
2312 _outputFilePlayerPtr->StopPlayingFile();
2313 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2314 _outputFilePlayerPtr = NULL;
2315 return -1;
2316 }
2317 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002318 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002319 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002320
2321 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002322 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002323
niklase@google.com470e71d2011-07-07 08:21:25 +00002324 return 0;
2325}
2326
2327int Channel::StopPlayingFileLocally()
2328{
2329 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2330 "Channel::StopPlayingFileLocally()");
2331
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002332 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002333 {
2334 _engineStatisticsPtr->SetLastError(
2335 VE_INVALID_OPERATION, kTraceWarning,
2336 "StopPlayingFileLocally() isnot playing");
2337 return 0;
2338 }
2339
niklase@google.com470e71d2011-07-07 08:21:25 +00002340 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002341 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002342
2343 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2344 {
2345 _engineStatisticsPtr->SetLastError(
2346 VE_STOP_RECORDING_FAILED, kTraceError,
2347 "StopPlayingFile() could not stop playing");
2348 return -1;
2349 }
2350 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2351 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2352 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002353 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002354 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002355 // _fileCritSect cannot be taken while calling
2356 // SetAnonymousMixibilityStatus. Refer to comments in
2357 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002358 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2359 {
2360 _engineStatisticsPtr->SetLastError(
2361 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002362 "StopPlayingFile() failed to stop participant from playing as"
2363 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002364 return -1;
2365 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002366
2367 return 0;
2368}
2369
2370int Channel::IsPlayingFileLocally() const
2371{
2372 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2373 "Channel::IsPlayingFileLocally()");
2374
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002375 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002376}
2377
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002378int Channel::RegisterFilePlayingToMixer()
2379{
2380 // Return success for not registering for file playing to mixer if:
2381 // 1. playing file before playout is started on that channel.
2382 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002383 if (!channel_state_.Get().playing ||
2384 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002385 {
2386 return 0;
2387 }
2388
2389 // |_fileCritSect| cannot be taken while calling
2390 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2391 // frames can be pulled by the mixer. Since the frames are generated from
2392 // the file, _fileCritSect will be taken. This would result in a deadlock.
2393 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2394 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002395 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002396 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002397 _engineStatisticsPtr->SetLastError(
2398 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2399 "StartPlayingFile() failed to add participant as file to mixer");
2400 _outputFilePlayerPtr->StopPlayingFile();
2401 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2402 _outputFilePlayerPtr = NULL;
2403 return -1;
2404 }
2405
2406 return 0;
2407}
2408
pbos@webrtc.org92135212013-05-14 08:31:39 +00002409int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002410{
2411 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2412 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2413
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002414 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002415
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002416 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002417 {
2418 _engineStatisticsPtr->SetLastError(
2419 VE_INVALID_OPERATION, kTraceError,
2420 "ScaleLocalFilePlayout() isnot playing");
2421 return -1;
2422 }
2423 if ((_outputFilePlayerPtr == NULL) ||
2424 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2425 {
2426 _engineStatisticsPtr->SetLastError(
2427 VE_BAD_ARGUMENT, kTraceError,
2428 "SetAudioScaling() failed to scale the playout");
2429 return -1;
2430 }
2431
2432 return 0;
2433}
2434
2435int Channel::GetLocalPlayoutPosition(int& positionMs)
2436{
2437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2438 "Channel::GetLocalPlayoutPosition(position=?)");
2439
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002440 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002441
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002442 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002443
2444 if (_outputFilePlayerPtr == NULL)
2445 {
2446 _engineStatisticsPtr->SetLastError(
2447 VE_INVALID_OPERATION, kTraceError,
2448 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2449 return -1;
2450 }
2451
2452 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2453 {
2454 _engineStatisticsPtr->SetLastError(
2455 VE_BAD_FILE, kTraceError,
2456 "GetLocalPlayoutPosition() failed");
2457 return -1;
2458 }
2459 positionMs = position;
2460
2461 return 0;
2462}
2463
2464int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002465 bool loop,
2466 FileFormats format,
2467 int startPosition,
2468 float volumeScaling,
2469 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002470 const CodecInst* codecInst)
2471{
2472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2473 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2474 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2475 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2476 startPosition, stopPosition);
2477
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002478 CriticalSectionScoped cs(&_fileCritSect);
2479
2480 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002481 {
2482 _engineStatisticsPtr->SetLastError(
2483 VE_ALREADY_PLAYING, kTraceWarning,
2484 "StartPlayingFileAsMicrophone() filePlayer is playing");
2485 return 0;
2486 }
2487
niklase@google.com470e71d2011-07-07 08:21:25 +00002488 // Destroy the old instance
2489 if (_inputFilePlayerPtr)
2490 {
2491 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2492 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2493 _inputFilePlayerPtr = NULL;
2494 }
2495
2496 // Create the instance
2497 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2498 _inputFilePlayerId, (const FileFormats)format);
2499
2500 if (_inputFilePlayerPtr == NULL)
2501 {
2502 _engineStatisticsPtr->SetLastError(
2503 VE_INVALID_ARGUMENT, kTraceError,
2504 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2505 return -1;
2506 }
2507
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002508 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002509
2510 if (_inputFilePlayerPtr->StartPlayingFile(
2511 fileName,
2512 loop,
2513 startPosition,
2514 volumeScaling,
2515 notificationTime,
2516 stopPosition,
2517 (const CodecInst*)codecInst) != 0)
2518 {
2519 _engineStatisticsPtr->SetLastError(
2520 VE_BAD_FILE, kTraceError,
2521 "StartPlayingFile() failed to start file playout");
2522 _inputFilePlayerPtr->StopPlayingFile();
2523 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2524 _inputFilePlayerPtr = NULL;
2525 return -1;
2526 }
2527 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002528 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002529
2530 return 0;
2531}
2532
2533int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002534 FileFormats format,
2535 int startPosition,
2536 float volumeScaling,
2537 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002538 const CodecInst* codecInst)
2539{
2540 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2541 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2542 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2543 format, volumeScaling, startPosition, stopPosition);
2544
2545 if(stream == NULL)
2546 {
2547 _engineStatisticsPtr->SetLastError(
2548 VE_BAD_FILE, kTraceError,
2549 "StartPlayingFileAsMicrophone NULL as input stream");
2550 return -1;
2551 }
2552
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002553 CriticalSectionScoped cs(&_fileCritSect);
2554
2555 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002556 {
2557 _engineStatisticsPtr->SetLastError(
2558 VE_ALREADY_PLAYING, kTraceWarning,
2559 "StartPlayingFileAsMicrophone() is playing");
2560 return 0;
2561 }
2562
niklase@google.com470e71d2011-07-07 08:21:25 +00002563 // Destroy the old instance
2564 if (_inputFilePlayerPtr)
2565 {
2566 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2567 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2568 _inputFilePlayerPtr = NULL;
2569 }
2570
2571 // Create the instance
2572 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2573 _inputFilePlayerId, (const FileFormats)format);
2574
2575 if (_inputFilePlayerPtr == NULL)
2576 {
2577 _engineStatisticsPtr->SetLastError(
2578 VE_INVALID_ARGUMENT, kTraceError,
2579 "StartPlayingInputFile() filePlayer format isnot correct");
2580 return -1;
2581 }
2582
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002583 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002584
2585 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2586 volumeScaling, notificationTime,
2587 stopPosition, codecInst) != 0)
2588 {
2589 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2590 "StartPlayingFile() failed to start "
2591 "file playout");
2592 _inputFilePlayerPtr->StopPlayingFile();
2593 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2594 _inputFilePlayerPtr = NULL;
2595 return -1;
2596 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002597
niklase@google.com470e71d2011-07-07 08:21:25 +00002598 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002599 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002600
2601 return 0;
2602}
2603
2604int Channel::StopPlayingFileAsMicrophone()
2605{
2606 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2607 "Channel::StopPlayingFileAsMicrophone()");
2608
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002609 CriticalSectionScoped cs(&_fileCritSect);
2610
2611 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002612 {
2613 _engineStatisticsPtr->SetLastError(
2614 VE_INVALID_OPERATION, kTraceWarning,
2615 "StopPlayingFileAsMicrophone() isnot playing");
2616 return 0;
2617 }
2618
niklase@google.com470e71d2011-07-07 08:21:25 +00002619 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2620 {
2621 _engineStatisticsPtr->SetLastError(
2622 VE_STOP_RECORDING_FAILED, kTraceError,
2623 "StopPlayingFile() could not stop playing");
2624 return -1;
2625 }
2626 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2627 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2628 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002629 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002630
2631 return 0;
2632}
2633
2634int Channel::IsPlayingFileAsMicrophone() const
2635{
2636 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2637 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002638 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002639}
2640
pbos@webrtc.org92135212013-05-14 08:31:39 +00002641int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002642{
2643 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2644 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2645
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002646 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002647
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002648 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002649 {
2650 _engineStatisticsPtr->SetLastError(
2651 VE_INVALID_OPERATION, kTraceError,
2652 "ScaleFileAsMicrophonePlayout() isnot playing");
2653 return -1;
2654 }
2655
2656 if ((_inputFilePlayerPtr == NULL) ||
2657 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2658 {
2659 _engineStatisticsPtr->SetLastError(
2660 VE_BAD_ARGUMENT, kTraceError,
2661 "SetAudioScaling() failed to scale playout");
2662 return -1;
2663 }
2664
2665 return 0;
2666}
2667
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002668int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002669 const CodecInst* codecInst)
2670{
2671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2672 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2673
2674 if (_outputFileRecording)
2675 {
2676 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2677 "StartRecordingPlayout() is already recording");
2678 return 0;
2679 }
2680
2681 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002682 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002683 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2684
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002685 if ((codecInst != NULL) &&
2686 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002687 {
2688 _engineStatisticsPtr->SetLastError(
2689 VE_BAD_ARGUMENT, kTraceError,
2690 "StartRecordingPlayout() invalid compression");
2691 return(-1);
2692 }
2693 if(codecInst == NULL)
2694 {
2695 format = kFileFormatPcm16kHzFile;
2696 codecInst=&dummyCodec;
2697 }
2698 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2699 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2700 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2701 {
2702 format = kFileFormatWavFile;
2703 }
2704 else
2705 {
2706 format = kFileFormatCompressedFile;
2707 }
2708
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002709 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002710
2711 // Destroy the old instance
2712 if (_outputFileRecorderPtr)
2713 {
2714 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2715 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2716 _outputFileRecorderPtr = NULL;
2717 }
2718
2719 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2720 _outputFileRecorderId, (const FileFormats)format);
2721 if (_outputFileRecorderPtr == NULL)
2722 {
2723 _engineStatisticsPtr->SetLastError(
2724 VE_INVALID_ARGUMENT, kTraceError,
2725 "StartRecordingPlayout() fileRecorder format isnot correct");
2726 return -1;
2727 }
2728
2729 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2730 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2731 {
2732 _engineStatisticsPtr->SetLastError(
2733 VE_BAD_FILE, kTraceError,
2734 "StartRecordingAudioFile() failed to start file recording");
2735 _outputFileRecorderPtr->StopRecording();
2736 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2737 _outputFileRecorderPtr = NULL;
2738 return -1;
2739 }
2740 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2741 _outputFileRecording = true;
2742
2743 return 0;
2744}
2745
2746int Channel::StartRecordingPlayout(OutStream* stream,
2747 const CodecInst* codecInst)
2748{
2749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2750 "Channel::StartRecordingPlayout()");
2751
2752 if (_outputFileRecording)
2753 {
2754 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2755 "StartRecordingPlayout() is already recording");
2756 return 0;
2757 }
2758
2759 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002760 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002761 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2762
2763 if (codecInst != NULL && codecInst->channels != 1)
2764 {
2765 _engineStatisticsPtr->SetLastError(
2766 VE_BAD_ARGUMENT, kTraceError,
2767 "StartRecordingPlayout() invalid compression");
2768 return(-1);
2769 }
2770 if(codecInst == NULL)
2771 {
2772 format = kFileFormatPcm16kHzFile;
2773 codecInst=&dummyCodec;
2774 }
2775 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2776 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2777 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2778 {
2779 format = kFileFormatWavFile;
2780 }
2781 else
2782 {
2783 format = kFileFormatCompressedFile;
2784 }
2785
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002786 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002787
2788 // Destroy the old instance
2789 if (_outputFileRecorderPtr)
2790 {
2791 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2792 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2793 _outputFileRecorderPtr = NULL;
2794 }
2795
2796 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2797 _outputFileRecorderId, (const FileFormats)format);
2798 if (_outputFileRecorderPtr == NULL)
2799 {
2800 _engineStatisticsPtr->SetLastError(
2801 VE_INVALID_ARGUMENT, kTraceError,
2802 "StartRecordingPlayout() fileRecorder format isnot correct");
2803 return -1;
2804 }
2805
2806 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2807 notificationTime) != 0)
2808 {
2809 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2810 "StartRecordingPlayout() failed to "
2811 "start file recording");
2812 _outputFileRecorderPtr->StopRecording();
2813 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2814 _outputFileRecorderPtr = NULL;
2815 return -1;
2816 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002817
niklase@google.com470e71d2011-07-07 08:21:25 +00002818 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2819 _outputFileRecording = true;
2820
2821 return 0;
2822}
2823
2824int Channel::StopRecordingPlayout()
2825{
2826 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2827 "Channel::StopRecordingPlayout()");
2828
2829 if (!_outputFileRecording)
2830 {
2831 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2832 "StopRecordingPlayout() isnot recording");
2833 return -1;
2834 }
2835
2836
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002837 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002838
2839 if (_outputFileRecorderPtr->StopRecording() != 0)
2840 {
2841 _engineStatisticsPtr->SetLastError(
2842 VE_STOP_RECORDING_FAILED, kTraceError,
2843 "StopRecording() could not stop recording");
2844 return(-1);
2845 }
2846 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2847 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2848 _outputFileRecorderPtr = NULL;
2849 _outputFileRecording = false;
2850
2851 return 0;
2852}
2853
2854void
2855Channel::SetMixWithMicStatus(bool mix)
2856{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002857 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002858 _mixFileWithMicrophone=mix;
2859}
2860
2861int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002862Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002863{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002864 int8_t currentLevel = _outputAudioLevel.Level();
2865 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002866 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2867 VoEId(_instanceId,_channelId),
2868 "GetSpeechOutputLevel() => level=%u", level);
2869 return 0;
2870}
2871
2872int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002873Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002874{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002875 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2876 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002877 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2878 VoEId(_instanceId,_channelId),
2879 "GetSpeechOutputLevelFullRange() => level=%u", level);
2880 return 0;
2881}
2882
2883int
2884Channel::SetMute(bool enable)
2885{
wu@webrtc.org63420662013-10-17 18:28:55 +00002886 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002887 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2888 "Channel::SetMute(enable=%d)", enable);
2889 _mute = enable;
2890 return 0;
2891}
2892
2893bool
2894Channel::Mute() const
2895{
wu@webrtc.org63420662013-10-17 18:28:55 +00002896 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002897 return _mute;
2898}
2899
2900int
2901Channel::SetOutputVolumePan(float left, float right)
2902{
wu@webrtc.org63420662013-10-17 18:28:55 +00002903 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002904 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2905 "Channel::SetOutputVolumePan()");
2906 _panLeft = left;
2907 _panRight = right;
2908 return 0;
2909}
2910
2911int
2912Channel::GetOutputVolumePan(float& left, float& right) const
2913{
wu@webrtc.org63420662013-10-17 18:28:55 +00002914 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002915 left = _panLeft;
2916 right = _panRight;
2917 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2918 VoEId(_instanceId,_channelId),
2919 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2920 return 0;
2921}
2922
2923int
2924Channel::SetChannelOutputVolumeScaling(float scaling)
2925{
wu@webrtc.org63420662013-10-17 18:28:55 +00002926 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002927 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2928 "Channel::SetChannelOutputVolumeScaling()");
2929 _outputGain = scaling;
2930 return 0;
2931}
2932
2933int
2934Channel::GetChannelOutputVolumeScaling(float& scaling) const
2935{
wu@webrtc.org63420662013-10-17 18:28:55 +00002936 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002937 scaling = _outputGain;
2938 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2939 VoEId(_instanceId,_channelId),
2940 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2941 return 0;
2942}
2943
niklase@google.com470e71d2011-07-07 08:21:25 +00002944int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002945 int lengthMs, int attenuationDb,
2946 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002947{
2948 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2949 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2950 playDtmfEvent);
2951
2952 _playOutbandDtmfEvent = playDtmfEvent;
2953
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002954 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002955 attenuationDb) != 0)
2956 {
2957 _engineStatisticsPtr->SetLastError(
2958 VE_SEND_DTMF_FAILED,
2959 kTraceWarning,
2960 "SendTelephoneEventOutband() failed to send event");
2961 return -1;
2962 }
2963 return 0;
2964}
2965
2966int Channel::SendTelephoneEventInband(unsigned char eventCode,
2967 int lengthMs,
2968 int attenuationDb,
2969 bool playDtmfEvent)
2970{
2971 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2972 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2973 playDtmfEvent);
2974
2975 _playInbandDtmfEvent = playDtmfEvent;
2976 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2977
2978 return 0;
2979}
2980
2981int
2982Channel::SetDtmfPlayoutStatus(bool enable)
2983{
2984 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2985 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002986 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002987 {
2988 _engineStatisticsPtr->SetLastError(
2989 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2990 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2991 return -1;
2992 }
2993 return 0;
2994}
2995
2996bool
2997Channel::DtmfPlayoutStatus() const
2998{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002999 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003000}
3001
3002int
3003Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3004{
3005 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3006 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003007 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003008 {
3009 _engineStatisticsPtr->SetLastError(
3010 VE_INVALID_ARGUMENT, kTraceError,
3011 "SetSendTelephoneEventPayloadType() invalid type");
3012 return -1;
3013 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003014 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003015 codec.plfreq = 8000;
3016 codec.pltype = type;
3017 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003018 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003019 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003020 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3021 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3022 _engineStatisticsPtr->SetLastError(
3023 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3024 "SetSendTelephoneEventPayloadType() failed to register send"
3025 "payload type");
3026 return -1;
3027 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003028 }
3029 _sendTelephoneEventPayloadType = type;
3030 return 0;
3031}
3032
3033int
3034Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3035{
3036 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3037 "Channel::GetSendTelephoneEventPayloadType()");
3038 type = _sendTelephoneEventPayloadType;
3039 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3040 VoEId(_instanceId,_channelId),
3041 "GetSendTelephoneEventPayloadType() => type=%u", type);
3042 return 0;
3043}
3044
niklase@google.com470e71d2011-07-07 08:21:25 +00003045int
3046Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3047{
3048 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3049 "Channel::UpdateRxVadDetection()");
3050
3051 int vadDecision = 1;
3052
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003053 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003054
3055 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3056 {
3057 OnRxVadDetected(vadDecision);
3058 _oldVadDecision = vadDecision;
3059 }
3060
3061 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3062 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3063 vadDecision);
3064 return 0;
3065}
3066
3067int
3068Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3069{
3070 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3071 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003072 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003073
3074 if (_rxVadObserverPtr)
3075 {
3076 _engineStatisticsPtr->SetLastError(
3077 VE_INVALID_OPERATION, kTraceError,
3078 "RegisterRxVadObserver() observer already enabled");
3079 return -1;
3080 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003081 _rxVadObserverPtr = &observer;
3082 _RxVadDetection = true;
3083 return 0;
3084}
3085
3086int
3087Channel::DeRegisterRxVadObserver()
3088{
3089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3090 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003091 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003092
3093 if (!_rxVadObserverPtr)
3094 {
3095 _engineStatisticsPtr->SetLastError(
3096 VE_INVALID_OPERATION, kTraceWarning,
3097 "DeRegisterRxVadObserver() observer already disabled");
3098 return 0;
3099 }
3100 _rxVadObserverPtr = NULL;
3101 _RxVadDetection = false;
3102 return 0;
3103}
3104
3105int
3106Channel::VoiceActivityIndicator(int &activity)
3107{
3108 activity = _sendFrameType;
3109
3110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003111 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003112 return 0;
3113}
3114
3115#ifdef WEBRTC_VOICE_ENGINE_AGC
3116
3117int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003118Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003119{
3120 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3121 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3122 (int)enable, (int)mode);
3123
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003124 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 switch (mode)
3126 {
3127 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003128 break;
3129 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003130 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003131 break;
3132 case kAgcFixedDigital:
3133 agcMode = GainControl::kFixedDigital;
3134 break;
3135 case kAgcAdaptiveDigital:
3136 agcMode =GainControl::kAdaptiveDigital;
3137 break;
3138 default:
3139 _engineStatisticsPtr->SetLastError(
3140 VE_INVALID_ARGUMENT, kTraceError,
3141 "SetRxAgcStatus() invalid Agc mode");
3142 return -1;
3143 }
3144
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003145 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003146 {
3147 _engineStatisticsPtr->SetLastError(
3148 VE_APM_ERROR, kTraceError,
3149 "SetRxAgcStatus() failed to set Agc mode");
3150 return -1;
3151 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003152 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003153 {
3154 _engineStatisticsPtr->SetLastError(
3155 VE_APM_ERROR, kTraceError,
3156 "SetRxAgcStatus() failed to set Agc state");
3157 return -1;
3158 }
3159
3160 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003161 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003162
3163 return 0;
3164}
3165
3166int
3167Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3168{
3169 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3170 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3171
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003172 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003173 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003174 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003175
3176 enabled = enable;
3177
3178 switch (agcMode)
3179 {
3180 case GainControl::kFixedDigital:
3181 mode = kAgcFixedDigital;
3182 break;
3183 case GainControl::kAdaptiveDigital:
3184 mode = kAgcAdaptiveDigital;
3185 break;
3186 default:
3187 _engineStatisticsPtr->SetLastError(
3188 VE_APM_ERROR, kTraceError,
3189 "GetRxAgcStatus() invalid Agc mode");
3190 return -1;
3191 }
3192
3193 return 0;
3194}
3195
3196int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003197Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003198{
3199 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3200 "Channel::SetRxAgcConfig()");
3201
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003202 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003203 config.targetLeveldBOv) != 0)
3204 {
3205 _engineStatisticsPtr->SetLastError(
3206 VE_APM_ERROR, kTraceError,
3207 "SetRxAgcConfig() failed to set target peak |level|"
3208 "(or envelope) of the Agc");
3209 return -1;
3210 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003211 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003212 config.digitalCompressionGaindB) != 0)
3213 {
3214 _engineStatisticsPtr->SetLastError(
3215 VE_APM_ERROR, kTraceError,
3216 "SetRxAgcConfig() failed to set the range in |gain| the"
3217 " digital compression stage may apply");
3218 return -1;
3219 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003220 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003221 config.limiterEnable) != 0)
3222 {
3223 _engineStatisticsPtr->SetLastError(
3224 VE_APM_ERROR, kTraceError,
3225 "SetRxAgcConfig() failed to set hard limiter to the signal");
3226 return -1;
3227 }
3228
3229 return 0;
3230}
3231
3232int
3233Channel::GetRxAgcConfig(AgcConfig& config)
3234{
3235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3236 "Channel::GetRxAgcConfig(config=%?)");
3237
3238 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003239 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003240 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003241 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003242 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003243 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003244
3245 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3246 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3247 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3248 " limiterEnable=%d",
3249 config.targetLeveldBOv,
3250 config.digitalCompressionGaindB,
3251 config.limiterEnable);
3252
3253 return 0;
3254}
3255
3256#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3257
3258#ifdef WEBRTC_VOICE_ENGINE_NR
3259
3260int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003261Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003262{
3263 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3264 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3265 (int)enable, (int)mode);
3266
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003267 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003268 switch (mode)
3269 {
3270
3271 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003272 break;
3273 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003274 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003275 break;
3276 case kNsConference:
3277 nsLevel = NoiseSuppression::kHigh;
3278 break;
3279 case kNsLowSuppression:
3280 nsLevel = NoiseSuppression::kLow;
3281 break;
3282 case kNsModerateSuppression:
3283 nsLevel = NoiseSuppression::kModerate;
3284 break;
3285 case kNsHighSuppression:
3286 nsLevel = NoiseSuppression::kHigh;
3287 break;
3288 case kNsVeryHighSuppression:
3289 nsLevel = NoiseSuppression::kVeryHigh;
3290 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003291 }
3292
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003293 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003294 != 0)
3295 {
3296 _engineStatisticsPtr->SetLastError(
3297 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003298 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003299 return -1;
3300 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003301 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003302 {
3303 _engineStatisticsPtr->SetLastError(
3304 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003305 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003306 return -1;
3307 }
3308
3309 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003310 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003311
3312 return 0;
3313}
3314
3315int
3316Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3317{
3318 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3319 "Channel::GetRxNsStatus(enable=?, mode=?)");
3320
3321 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003322 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003323 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003324 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003325
3326 enabled = enable;
3327
3328 switch (ncLevel)
3329 {
3330 case NoiseSuppression::kLow:
3331 mode = kNsLowSuppression;
3332 break;
3333 case NoiseSuppression::kModerate:
3334 mode = kNsModerateSuppression;
3335 break;
3336 case NoiseSuppression::kHigh:
3337 mode = kNsHighSuppression;
3338 break;
3339 case NoiseSuppression::kVeryHigh:
3340 mode = kNsVeryHighSuppression;
3341 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003342 }
3343
3344 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3345 VoEId(_instanceId,_channelId),
3346 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3347 return 0;
3348}
3349
3350#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3351
3352int
3353Channel::RegisterRTPObserver(VoERTPObserver& observer)
3354{
3355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3356 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003357 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003358
3359 if (_rtpObserverPtr)
3360 {
3361 _engineStatisticsPtr->SetLastError(
3362 VE_INVALID_OPERATION, kTraceError,
3363 "RegisterRTPObserver() observer already enabled");
3364 return -1;
3365 }
3366
3367 _rtpObserverPtr = &observer;
3368 _rtpObserver = true;
3369
3370 return 0;
3371}
3372
3373int
3374Channel::DeRegisterRTPObserver()
3375{
3376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3377 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003378 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003379
3380 if (!_rtpObserverPtr)
3381 {
3382 _engineStatisticsPtr->SetLastError(
3383 VE_INVALID_OPERATION, kTraceWarning,
3384 "DeRegisterRTPObserver() observer already disabled");
3385 return 0;
3386 }
3387
3388 _rtpObserver = false;
3389 _rtpObserverPtr = NULL;
3390
3391 return 0;
3392}
3393
3394int
3395Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3396{
3397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3398 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003399 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003400
3401 if (_rtcpObserverPtr)
3402 {
3403 _engineStatisticsPtr->SetLastError(
3404 VE_INVALID_OPERATION, kTraceError,
3405 "RegisterRTCPObserver() observer already enabled");
3406 return -1;
3407 }
3408
3409 _rtcpObserverPtr = &observer;
3410 _rtcpObserver = true;
3411
3412 return 0;
3413}
3414
3415int
3416Channel::DeRegisterRTCPObserver()
3417{
3418 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3419 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003420 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003421
3422 if (!_rtcpObserverPtr)
3423 {
3424 _engineStatisticsPtr->SetLastError(
3425 VE_INVALID_OPERATION, kTraceWarning,
3426 "DeRegisterRTCPObserver() observer already disabled");
3427 return 0;
3428 }
3429
3430 _rtcpObserver = false;
3431 _rtcpObserverPtr = NULL;
3432
3433 return 0;
3434}
3435
3436int
3437Channel::SetLocalSSRC(unsigned int ssrc)
3438{
3439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3440 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003441 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003442 {
3443 _engineStatisticsPtr->SetLastError(
3444 VE_ALREADY_SENDING, kTraceError,
3445 "SetLocalSSRC() already sending");
3446 return -1;
3447 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003448 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003449 {
3450 _engineStatisticsPtr->SetLastError(
3451 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3452 "SetLocalSSRC() failed to set SSRC");
3453 return -1;
3454 }
3455 return 0;
3456}
3457
3458int
3459Channel::GetLocalSSRC(unsigned int& ssrc)
3460{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003461 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003462 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3463 VoEId(_instanceId,_channelId),
3464 "GetLocalSSRC() => ssrc=%lu", ssrc);
3465 return 0;
3466}
3467
3468int
3469Channel::GetRemoteSSRC(unsigned int& ssrc)
3470{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003471 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003472 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3473 VoEId(_instanceId,_channelId),
3474 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3475 return 0;
3476}
3477
3478int
3479Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3480{
3481 if (arrCSRC == NULL)
3482 {
3483 _engineStatisticsPtr->SetLastError(
3484 VE_INVALID_ARGUMENT, kTraceError,
3485 "GetRemoteCSRCs() invalid array argument");
3486 return -1;
3487 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003488 uint32_t arrOfCSRC[kRtpCsrcSize];
3489 int32_t CSRCs(0);
braveyao@webrtc.orgcdefc912014-03-11 16:19:56 +00003490 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003491 if (CSRCs > 0)
3492 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003493 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003494 for (int i = 0; i < (int) CSRCs; i++)
3495 {
3496 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3497 VoEId(_instanceId, _channelId),
3498 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3499 }
3500 } else
3501 {
3502 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3503 VoEId(_instanceId, _channelId),
3504 "GetRemoteCSRCs() => list is empty!");
3505 }
3506 return CSRCs;
3507}
3508
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003509int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003510 if (rtp_audioproc_.get() == NULL) {
3511 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3512 _channelId)));
3513 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003514
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003515 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3516 AudioProcessing::kNoError) {
3517 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3518 "Failed to enable AudioProcessing::level_estimator()");
3519 return -1;
3520 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003521
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003522 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003523
3524 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003525}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003526
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003527int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3528 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3529}
3530
3531int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3532 rtp_header_parser_->DeregisterRtpHeaderExtension(
3533 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003534 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3535 kRtpExtensionAbsoluteSendTime, id)) {
3536 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003537 }
3538 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003539}
3540
3541int
3542Channel::SetRTCPStatus(bool enable)
3543{
3544 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3545 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003546 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003547 kRtcpCompound : kRtcpOff) != 0)
3548 {
3549 _engineStatisticsPtr->SetLastError(
3550 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3551 "SetRTCPStatus() failed to set RTCP status");
3552 return -1;
3553 }
3554 return 0;
3555}
3556
3557int
3558Channel::GetRTCPStatus(bool& enabled)
3559{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003560 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003561 enabled = (method != kRtcpOff);
3562 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3563 VoEId(_instanceId,_channelId),
3564 "GetRTCPStatus() => enabled=%d", enabled);
3565 return 0;
3566}
3567
3568int
3569Channel::SetRTCP_CNAME(const char cName[256])
3570{
3571 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3572 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003573 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003574 {
3575 _engineStatisticsPtr->SetLastError(
3576 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3577 "SetRTCP_CNAME() failed to set RTCP CNAME");
3578 return -1;
3579 }
3580 return 0;
3581}
3582
3583int
3584Channel::GetRTCP_CNAME(char cName[256])
3585{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003586 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003587 {
3588 _engineStatisticsPtr->SetLastError(
3589 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3590 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3591 return -1;
3592 }
3593 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3594 VoEId(_instanceId, _channelId),
3595 "GetRTCP_CNAME() => cName=%s", cName);
3596 return 0;
3597}
3598
3599int
3600Channel::GetRemoteRTCP_CNAME(char cName[256])
3601{
3602 if (cName == NULL)
3603 {
3604 _engineStatisticsPtr->SetLastError(
3605 VE_INVALID_ARGUMENT, kTraceError,
3606 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3607 return -1;
3608 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003609 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003610 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003611 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003612 {
3613 _engineStatisticsPtr->SetLastError(
3614 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3615 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3616 return -1;
3617 }
3618 strcpy(cName, cname);
3619 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3620 VoEId(_instanceId, _channelId),
3621 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3622 return 0;
3623}
3624
3625int
3626Channel::GetRemoteRTCPData(
3627 unsigned int& NTPHigh,
3628 unsigned int& NTPLow,
3629 unsigned int& timestamp,
3630 unsigned int& playoutTimestamp,
3631 unsigned int* jitter,
3632 unsigned short* fractionLost)
3633{
3634 // --- Information from sender info in received Sender Reports
3635
3636 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003637 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003638 {
3639 _engineStatisticsPtr->SetLastError(
3640 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003641 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003642 "side");
3643 return -1;
3644 }
3645
3646 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3647 // and octet count)
3648 NTPHigh = senderInfo.NTPseconds;
3649 NTPLow = senderInfo.NTPfraction;
3650 timestamp = senderInfo.RTPtimeStamp;
3651
3652 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3653 VoEId(_instanceId, _channelId),
3654 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3655 "timestamp=%lu",
3656 NTPHigh, NTPLow, timestamp);
3657
3658 // --- Locally derived information
3659
3660 // This value is updated on each incoming RTCP packet (0 when no packet
3661 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003662 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003663
3664 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3665 VoEId(_instanceId, _channelId),
3666 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003667 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003668
3669 if (NULL != jitter || NULL != fractionLost)
3670 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003671 // Get all RTCP receiver report blocks that have been received on this
3672 // channel. If we receive RTP packets from a remote source we know the
3673 // remote SSRC and use the report block from him.
3674 // Otherwise use the first report block.
3675 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003676 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003677 remote_stats.empty()) {
3678 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3679 VoEId(_instanceId, _channelId),
3680 "GetRemoteRTCPData() failed to measure statistics due"
3681 " to lack of received RTP and/or RTCP packets");
3682 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003683 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003684
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003685 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003686 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3687 for (; it != remote_stats.end(); ++it) {
3688 if (it->remoteSSRC == remoteSSRC)
3689 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003690 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003691
3692 if (it == remote_stats.end()) {
3693 // If we have not received any RTCP packets from this SSRC it probably
3694 // means that we have not received any RTP packets.
3695 // Use the first received report block instead.
3696 it = remote_stats.begin();
3697 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003698 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003699
xians@webrtc.org79af7342012-01-31 12:22:14 +00003700 if (jitter) {
3701 *jitter = it->jitter;
3702 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3703 VoEId(_instanceId, _channelId),
3704 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3705 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003706
xians@webrtc.org79af7342012-01-31 12:22:14 +00003707 if (fractionLost) {
3708 *fractionLost = it->fractionLost;
3709 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3710 VoEId(_instanceId, _channelId),
3711 "GetRemoteRTCPData() => fractionLost = %lu",
3712 *fractionLost);
3713 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003714 }
3715 return 0;
3716}
3717
3718int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003719Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003720 unsigned int name,
3721 const char* data,
3722 unsigned short dataLengthInBytes)
3723{
3724 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3725 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003726 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003727 {
3728 _engineStatisticsPtr->SetLastError(
3729 VE_NOT_SENDING, kTraceError,
3730 "SendApplicationDefinedRTCPPacket() not sending");
3731 return -1;
3732 }
3733 if (NULL == data)
3734 {
3735 _engineStatisticsPtr->SetLastError(
3736 VE_INVALID_ARGUMENT, kTraceError,
3737 "SendApplicationDefinedRTCPPacket() invalid data value");
3738 return -1;
3739 }
3740 if (dataLengthInBytes % 4 != 0)
3741 {
3742 _engineStatisticsPtr->SetLastError(
3743 VE_INVALID_ARGUMENT, kTraceError,
3744 "SendApplicationDefinedRTCPPacket() invalid length value");
3745 return -1;
3746 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003747 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003748 if (status == kRtcpOff)
3749 {
3750 _engineStatisticsPtr->SetLastError(
3751 VE_RTCP_ERROR, kTraceError,
3752 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3753 return -1;
3754 }
3755
3756 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003757 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003758 subType,
3759 name,
3760 (const unsigned char*) data,
3761 dataLengthInBytes) != 0)
3762 {
3763 _engineStatisticsPtr->SetLastError(
3764 VE_SEND_ERROR, kTraceError,
3765 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3766 return -1;
3767 }
3768 return 0;
3769}
3770
3771int
3772Channel::GetRTPStatistics(
3773 unsigned int& averageJitterMs,
3774 unsigned int& maxJitterMs,
3775 unsigned int& discardedPackets)
3776{
niklase@google.com470e71d2011-07-07 08:21:25 +00003777 // The jitter statistics is updated for each received RTP packet and is
3778 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003779 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3780 // If RTCP is off, there is no timed thread in the RTCP module regularly
3781 // generating new stats, trigger the update manually here instead.
3782 StreamStatistician* statistician =
3783 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3784 if (statistician) {
3785 // Don't use returned statistics, use data from proxy instead so that
3786 // max jitter can be fetched atomically.
3787 RtcpStatistics s;
3788 statistician->GetStatistics(&s, true);
3789 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003790 }
3791
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003792 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003793 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003794 if (playoutFrequency > 0) {
3795 // Scale RTP statistics given the current playout frequency
3796 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3797 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003798 }
3799
3800 discardedPackets = _numberOfDiscardedPackets;
3801
3802 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3803 VoEId(_instanceId, _channelId),
3804 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003805 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003806 averageJitterMs, maxJitterMs, discardedPackets);
3807 return 0;
3808}
3809
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003810int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3811 if (sender_info == NULL) {
3812 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3813 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3814 return -1;
3815 }
3816
3817 // Get the sender info from the latest received RTCP Sender Report.
3818 RTCPSenderInfo rtcp_sender_info;
3819 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3820 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3821 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3822 return -1;
3823 }
3824
3825 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3826 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3827 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3828 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3829 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3830 return 0;
3831}
3832
3833int Channel::GetRemoteRTCPReportBlocks(
3834 std::vector<ReportBlock>* report_blocks) {
3835 if (report_blocks == NULL) {
3836 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3837 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3838 return -1;
3839 }
3840
3841 // Get the report blocks from the latest received RTCP Sender or Receiver
3842 // Report. Each element in the vector contains the sender's SSRC and a
3843 // report block according to RFC 3550.
3844 std::vector<RTCPReportBlock> rtcp_report_blocks;
3845 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3846 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3847 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3848 return -1;
3849 }
3850
3851 if (rtcp_report_blocks.empty())
3852 return 0;
3853
3854 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3855 for (; it != rtcp_report_blocks.end(); ++it) {
3856 ReportBlock report_block;
3857 report_block.sender_SSRC = it->remoteSSRC;
3858 report_block.source_SSRC = it->sourceSSRC;
3859 report_block.fraction_lost = it->fractionLost;
3860 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3861 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3862 report_block.interarrival_jitter = it->jitter;
3863 report_block.last_SR_timestamp = it->lastSR;
3864 report_block.delay_since_last_SR = it->delaySinceLastSR;
3865 report_blocks->push_back(report_block);
3866 }
3867 return 0;
3868}
3869
niklase@google.com470e71d2011-07-07 08:21:25 +00003870int
3871Channel::GetRTPStatistics(CallStatistics& stats)
3872{
niklase@google.com470e71d2011-07-07 08:21:25 +00003873 // --- Part one of the final structure (four values)
3874
3875 // The jitter statistics is updated for each received RTP packet and is
3876 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003877 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003878 StreamStatistician* statistician =
3879 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3880 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003881 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3882 _engineStatisticsPtr->SetLastError(
3883 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3884 "GetRTPStatistics() failed to read RTP statistics from the "
3885 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003886 }
3887
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003888 stats.fractionLost = statistics.fraction_lost;
3889 stats.cumulativeLost = statistics.cumulative_lost;
3890 stats.extendedMax = statistics.extended_max_sequence_number;
3891 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003892
3893 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3894 VoEId(_instanceId, _channelId),
3895 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003896 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003897 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3898 stats.jitterSamples);
3899
3900 // --- Part two of the final structure (one value)
3901
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003902 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003903 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003904 if (method == kRtcpOff)
3905 {
3906 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3907 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003908 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003909 "measurements cannot be retrieved");
3910 } else
3911 {
3912 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003913 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 if (remoteSSRC > 0)
3915 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003916 uint16_t avgRTT(0);
3917 uint16_t maxRTT(0);
3918 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003919
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003920 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003921 != 0)
3922 {
3923 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3924 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003925 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003926 "the RTP/RTCP module");
3927 }
3928 } else
3929 {
3930 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3931 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003932 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003933 "RTP packets have been received yet");
3934 }
3935 }
3936
3937 stats.rttMs = static_cast<int> (RTT);
3938
3939 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3940 VoEId(_instanceId, _channelId),
3941 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3942
3943 // --- Part three of the final structure (four values)
3944
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003945 uint32_t bytesSent(0);
3946 uint32_t packetsSent(0);
3947 uint32_t bytesReceived(0);
3948 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003949
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003950 if (statistician) {
3951 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3952 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003953
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003954 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003955 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003956 {
3957 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3958 VoEId(_instanceId, _channelId),
3959 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003960 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003961 }
3962
3963 stats.bytesSent = bytesSent;
3964 stats.packetsSent = packetsSent;
3965 stats.bytesReceived = bytesReceived;
3966 stats.packetsReceived = packetsReceived;
3967
3968 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3969 VoEId(_instanceId, _channelId),
3970 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003971 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003972 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3973 stats.packetsReceived);
3974
3975 return 0;
3976}
3977
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003978int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3979 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3980 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003981
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003982 if (enable) {
3983 if (redPayloadtype < 0 || redPayloadtype > 127) {
3984 _engineStatisticsPtr->SetLastError(
3985 VE_PLTYPE_ERROR, kTraceError,
3986 "SetFECStatus() invalid RED payload type");
3987 return -1;
3988 }
3989
3990 if (SetRedPayloadType(redPayloadtype) < 0) {
3991 _engineStatisticsPtr->SetLastError(
3992 VE_CODEC_ERROR, kTraceError,
3993 "SetSecondarySendCodec() Failed to register RED ACM");
3994 return -1;
3995 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003996 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003997
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003998 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003999 _engineStatisticsPtr->SetLastError(
4000 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4001 "SetFECStatus() failed to set FEC state in the ACM");
4002 return -1;
4003 }
4004 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004005}
4006
4007int
4008Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4009{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004010 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004011 if (enabled)
4012 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004013 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004014 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004015 {
4016 _engineStatisticsPtr->SetLastError(
4017 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4018 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4019 "module");
4020 return -1;
4021 }
4022 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4023 VoEId(_instanceId, _channelId),
4024 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4025 enabled, redPayloadtype);
4026 return 0;
4027 }
4028 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4029 VoEId(_instanceId, _channelId),
4030 "GetFECStatus() => enabled=%d", enabled);
4031 return 0;
4032}
4033
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004034void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4035 // None of these functions can fail.
4036 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004037 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4038 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004039 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004040 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004041 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004042 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004043}
4044
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004045// Called when we are missing one or more packets.
4046int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004047 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4048}
4049
niklase@google.com470e71d2011-07-07 08:21:25 +00004050int
niklase@google.com470e71d2011-07-07 08:21:25 +00004051Channel::StartRTPDump(const char fileNameUTF8[1024],
4052 RTPDirections direction)
4053{
4054 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4055 "Channel::StartRTPDump()");
4056 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4057 {
4058 _engineStatisticsPtr->SetLastError(
4059 VE_INVALID_ARGUMENT, kTraceError,
4060 "StartRTPDump() invalid RTP direction");
4061 return -1;
4062 }
4063 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4064 &_rtpDumpIn : &_rtpDumpOut;
4065 if (rtpDumpPtr == NULL)
4066 {
4067 assert(false);
4068 return -1;
4069 }
4070 if (rtpDumpPtr->IsActive())
4071 {
4072 rtpDumpPtr->Stop();
4073 }
4074 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4075 {
4076 _engineStatisticsPtr->SetLastError(
4077 VE_BAD_FILE, kTraceError,
4078 "StartRTPDump() failed to create file");
4079 return -1;
4080 }
4081 return 0;
4082}
4083
4084int
4085Channel::StopRTPDump(RTPDirections direction)
4086{
4087 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4088 "Channel::StopRTPDump()");
4089 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4090 {
4091 _engineStatisticsPtr->SetLastError(
4092 VE_INVALID_ARGUMENT, kTraceError,
4093 "StopRTPDump() invalid RTP direction");
4094 return -1;
4095 }
4096 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4097 &_rtpDumpIn : &_rtpDumpOut;
4098 if (rtpDumpPtr == NULL)
4099 {
4100 assert(false);
4101 return -1;
4102 }
4103 if (!rtpDumpPtr->IsActive())
4104 {
4105 return 0;
4106 }
4107 return rtpDumpPtr->Stop();
4108}
4109
4110bool
4111Channel::RTPDumpIsActive(RTPDirections direction)
4112{
4113 if ((direction != kRtpIncoming) &&
4114 (direction != kRtpOutgoing))
4115 {
4116 _engineStatisticsPtr->SetLastError(
4117 VE_INVALID_ARGUMENT, kTraceError,
4118 "RTPDumpIsActive() invalid RTP direction");
4119 return false;
4120 }
4121 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4122 &_rtpDumpIn : &_rtpDumpOut;
4123 return rtpDumpPtr->IsActive();
4124}
4125
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00004126void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
4127 int video_channel) {
4128 CriticalSectionScoped cs(&_callbackCritSect);
4129 if (vie_network_) {
4130 vie_network_->Release();
4131 vie_network_ = NULL;
4132 }
4133 video_channel_ = -1;
4134
4135 if (vie_network != NULL && video_channel != -1) {
4136 vie_network_ = vie_network;
4137 video_channel_ = video_channel;
4138 }
4139}
4140
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004141uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004142Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004143{
4144 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004145 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004146 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004147 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004148 return 0;
4149}
4150
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004151void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004152 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004153 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004154 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004155 CodecInst codec;
4156 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004157
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004158 if (!mono_recording_audio_.get()) {
4159 // Temporary space for DownConvertToCodecFormat.
4160 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004161 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004162 DownConvertToCodecFormat(audio_data,
4163 number_of_frames,
4164 number_of_channels,
4165 sample_rate,
4166 codec.channels,
4167 codec.plfreq,
4168 mono_recording_audio_.get(),
4169 &input_resampler_,
4170 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004171}
4172
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004173uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004174Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004175{
4176 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4177 "Channel::PrepareEncodeAndSend()");
4178
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004179 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004180 {
4181 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4182 "Channel::PrepareEncodeAndSend() invalid audio frame");
4183 return -1;
4184 }
4185
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004186 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00004187 {
4188 MixOrReplaceAudioWithFile(mixingFrequency);
4189 }
4190
wu@webrtc.org63420662013-10-17 18:28:55 +00004191 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004192 {
4193 AudioFrameOperations::Mute(_audioFrame);
4194 }
4195
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004196 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00004197 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004198 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004199 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004200 if (_inputExternalMediaCallbackPtr)
4201 {
4202 _inputExternalMediaCallbackPtr->Process(
4203 _channelId,
4204 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004205 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004206 _audioFrame.samples_per_channel_,
4207 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004208 isStereo);
4209 }
4210 }
4211
4212 InsertInbandDtmfTone();
4213
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004214 if (_includeAudioLevelIndication) {
4215 // Performs level analysis only; does not affect the signal.
4216 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4217 if (err) {
4218 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4219 assert(false);
4220 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004221 }
4222
niklase@google.com470e71d2011-07-07 08:21:25 +00004223 return 0;
4224}
4225
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004226uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004227Channel::EncodeAndSend()
4228{
4229 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4230 "Channel::EncodeAndSend()");
4231
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004232 assert(_audioFrame.num_channels_ <= 2);
4233 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004234 {
4235 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4236 "Channel::EncodeAndSend() invalid audio frame");
4237 return -1;
4238 }
4239
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004240 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004241
4242 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4243
4244 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004245 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004246 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004247 {
4248 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4249 "Channel::EncodeAndSend() ACM encoding failed");
4250 return -1;
4251 }
4252
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004253 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004254
4255 // --- Encode if complete frame is ready
4256
4257 // This call will trigger AudioPacketizationCallback::SendData if encoding
4258 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004259 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004260}
4261
4262int Channel::RegisterExternalMediaProcessing(
4263 ProcessingTypes type,
4264 VoEMediaProcess& processObject)
4265{
4266 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4267 "Channel::RegisterExternalMediaProcessing()");
4268
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004269 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004270
4271 if (kPlaybackPerChannel == type)
4272 {
4273 if (_outputExternalMediaCallbackPtr)
4274 {
4275 _engineStatisticsPtr->SetLastError(
4276 VE_INVALID_OPERATION, kTraceError,
4277 "Channel::RegisterExternalMediaProcessing() "
4278 "output external media already enabled");
4279 return -1;
4280 }
4281 _outputExternalMediaCallbackPtr = &processObject;
4282 _outputExternalMedia = true;
4283 }
4284 else if (kRecordingPerChannel == type)
4285 {
4286 if (_inputExternalMediaCallbackPtr)
4287 {
4288 _engineStatisticsPtr->SetLastError(
4289 VE_INVALID_OPERATION, kTraceError,
4290 "Channel::RegisterExternalMediaProcessing() "
4291 "output external media already enabled");
4292 return -1;
4293 }
4294 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004295 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00004296 }
4297 return 0;
4298}
4299
4300int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4301{
4302 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4303 "Channel::DeRegisterExternalMediaProcessing()");
4304
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004305 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004306
4307 if (kPlaybackPerChannel == type)
4308 {
4309 if (!_outputExternalMediaCallbackPtr)
4310 {
4311 _engineStatisticsPtr->SetLastError(
4312 VE_INVALID_OPERATION, kTraceWarning,
4313 "Channel::DeRegisterExternalMediaProcessing() "
4314 "output external media already disabled");
4315 return 0;
4316 }
4317 _outputExternalMedia = false;
4318 _outputExternalMediaCallbackPtr = NULL;
4319 }
4320 else if (kRecordingPerChannel == type)
4321 {
4322 if (!_inputExternalMediaCallbackPtr)
4323 {
4324 _engineStatisticsPtr->SetLastError(
4325 VE_INVALID_OPERATION, kTraceWarning,
4326 "Channel::DeRegisterExternalMediaProcessing() "
4327 "input external media already disabled");
4328 return 0;
4329 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004330 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00004331 _inputExternalMediaCallbackPtr = NULL;
4332 }
4333
4334 return 0;
4335}
4336
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004337int Channel::SetExternalMixing(bool enabled) {
4338 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4339 "Channel::SetExternalMixing(enabled=%d)", enabled);
4340
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004341 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004342 {
4343 _engineStatisticsPtr->SetLastError(
4344 VE_INVALID_OPERATION, kTraceError,
4345 "Channel::SetExternalMixing() "
4346 "external mixing cannot be changed while playing.");
4347 return -1;
4348 }
4349
4350 _externalMixing = enabled;
4351
4352 return 0;
4353}
4354
niklase@google.com470e71d2011-07-07 08:21:25 +00004355int
niklase@google.com470e71d2011-07-07 08:21:25 +00004356Channel::GetNetworkStatistics(NetworkStatistics& stats)
4357{
4358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4359 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004360 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004361 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004362 if (return_value >= 0) {
4363 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4364 }
4365 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004366}
4367
wu@webrtc.org24301a62013-12-13 19:17:43 +00004368void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4369 audio_coding_->GetDecodingCallStatistics(stats);
4370}
4371
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004372bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4373 int* playout_buffer_delay_ms) const {
4374 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004376 "Channel::GetDelayEstimate() no valid estimate.");
4377 return false;
4378 }
4379 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4380 _recPacketDelayMs;
4381 *playout_buffer_delay_ms = playout_delay_ms_;
4382 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4383 "Channel::GetDelayEstimate()");
4384 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004385}
4386
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004387int Channel::SetInitialPlayoutDelay(int delay_ms)
4388{
4389 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4390 "Channel::SetInitialPlayoutDelay()");
4391 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4392 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4393 {
4394 _engineStatisticsPtr->SetLastError(
4395 VE_INVALID_ARGUMENT, kTraceError,
4396 "SetInitialPlayoutDelay() invalid min delay");
4397 return -1;
4398 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004399 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004400 {
4401 _engineStatisticsPtr->SetLastError(
4402 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4403 "SetInitialPlayoutDelay() failed to set min playout delay");
4404 return -1;
4405 }
4406 return 0;
4407}
4408
4409
niklase@google.com470e71d2011-07-07 08:21:25 +00004410int
4411Channel::SetMinimumPlayoutDelay(int delayMs)
4412{
4413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4414 "Channel::SetMinimumPlayoutDelay()");
4415 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4416 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4417 {
4418 _engineStatisticsPtr->SetLastError(
4419 VE_INVALID_ARGUMENT, kTraceError,
4420 "SetMinimumPlayoutDelay() invalid min delay");
4421 return -1;
4422 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004423 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004424 {
4425 _engineStatisticsPtr->SetLastError(
4426 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4427 "SetMinimumPlayoutDelay() failed to set min playout delay");
4428 return -1;
4429 }
4430 return 0;
4431}
4432
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004433void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4434 uint32_t playout_timestamp = 0;
4435
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004436 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004437 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4438 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4439 " timestamp from the ACM");
4440 _engineStatisticsPtr->SetLastError(
4441 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4442 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4443 return;
4444 }
4445
4446 uint16_t delay_ms = 0;
4447 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4448 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4449 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4450 " delay from the ADM");
4451 _engineStatisticsPtr->SetLastError(
4452 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4453 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4454 return;
4455 }
4456
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004457 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004458 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004459 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004460 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4461 playout_frequency = 8000;
4462 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4463 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004464 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004465 }
4466
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004467 jitter_buffer_playout_timestamp_ = playout_timestamp;
4468
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004469 // Remove the playout delay.
4470 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4471
4472 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4473 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4474 playout_timestamp);
4475
4476 if (rtcp) {
4477 playout_timestamp_rtcp_ = playout_timestamp;
4478 } else {
4479 playout_timestamp_rtp_ = playout_timestamp;
4480 }
4481 playout_delay_ms_ = delay_ms;
4482}
4483
4484int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4485 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4486 "Channel::GetPlayoutTimestamp()");
4487 if (playout_timestamp_rtp_ == 0) {
4488 _engineStatisticsPtr->SetLastError(
4489 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4490 "GetPlayoutTimestamp() failed to retrieve timestamp");
4491 return -1;
4492 }
4493 timestamp = playout_timestamp_rtp_;
4494 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4495 VoEId(_instanceId,_channelId),
4496 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4497 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004498}
4499
4500int
4501Channel::SetInitTimestamp(unsigned int timestamp)
4502{
4503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4504 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004505 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004506 {
4507 _engineStatisticsPtr->SetLastError(
4508 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4509 return -1;
4510 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004511 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004512 {
4513 _engineStatisticsPtr->SetLastError(
4514 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4515 "SetInitTimestamp() failed to set timestamp");
4516 return -1;
4517 }
4518 return 0;
4519}
4520
4521int
4522Channel::SetInitSequenceNumber(short sequenceNumber)
4523{
4524 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4525 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004526 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004527 {
4528 _engineStatisticsPtr->SetLastError(
4529 VE_SENDING, kTraceError,
4530 "SetInitSequenceNumber() already sending");
4531 return -1;
4532 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004533 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004534 {
4535 _engineStatisticsPtr->SetLastError(
4536 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4537 "SetInitSequenceNumber() failed to set sequence number");
4538 return -1;
4539 }
4540 return 0;
4541}
4542
4543int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004544Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004545{
4546 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4547 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004548 *rtpRtcpModule = _rtpRtcpModule.get();
4549 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004550 return 0;
4551}
4552
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004553// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4554// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004555int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004556Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004557{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004558 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004559 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004560
4561 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004562 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004563
4564 if (_inputFilePlayerPtr == NULL)
4565 {
4566 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4567 VoEId(_instanceId, _channelId),
4568 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4569 " doesnt exist");
4570 return -1;
4571 }
4572
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004573 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004574 fileSamples,
4575 mixingFrequency) == -1)
4576 {
4577 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4578 VoEId(_instanceId, _channelId),
4579 "Channel::MixOrReplaceAudioWithFile() file mixing "
4580 "failed");
4581 return -1;
4582 }
4583 if (fileSamples == 0)
4584 {
4585 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4586 VoEId(_instanceId, _channelId),
4587 "Channel::MixOrReplaceAudioWithFile() file is ended");
4588 return 0;
4589 }
4590 }
4591
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004592 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004593
4594 if (_mixFileWithMicrophone)
4595 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004596 // Currently file stream is always mono.
4597 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004598 MixWithSat(_audioFrame.data_,
4599 _audioFrame.num_channels_,
4600 fileBuffer.get(),
4601 1,
4602 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004603 }
4604 else
4605 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004606 // Replace ACM audio with file.
4607 // Currently file stream is always mono.
4608 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004609 _audioFrame.UpdateFrame(_channelId,
4610 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004611 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004612 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004613 mixingFrequency,
4614 AudioFrame::kNormalSpeech,
4615 AudioFrame::kVadUnknown,
4616 1);
4617
4618 }
4619 return 0;
4620}
4621
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004622int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004623Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004624 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004625{
4626 assert(mixingFrequency <= 32000);
4627
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004628 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004629 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004630
4631 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004632 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004633
4634 if (_outputFilePlayerPtr == NULL)
4635 {
4636 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4637 VoEId(_instanceId, _channelId),
4638 "Channel::MixAudioWithFile() file mixing failed");
4639 return -1;
4640 }
4641
4642 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004643 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004644 fileSamples,
4645 mixingFrequency) == -1)
4646 {
4647 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4648 VoEId(_instanceId, _channelId),
4649 "Channel::MixAudioWithFile() file mixing failed");
4650 return -1;
4651 }
4652 }
4653
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004654 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004655 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004656 // Currently file stream is always mono.
4657 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004658 MixWithSat(audioFrame.data_,
4659 audioFrame.num_channels_,
4660 fileBuffer.get(),
4661 1,
4662 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004663 }
4664 else
4665 {
4666 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004667 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004668 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004669 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004670 return -1;
4671 }
4672
4673 return 0;
4674}
4675
4676int
4677Channel::InsertInbandDtmfTone()
4678{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004679 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004680 if (_inbandDtmfQueue.PendingDtmf() &&
4681 !_inbandDtmfGenerator.IsAddingTone() &&
4682 _inbandDtmfGenerator.DelaySinceLastTone() >
4683 kMinTelephoneEventSeparationMs)
4684 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004685 int8_t eventCode(0);
4686 uint16_t lengthMs(0);
4687 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004688
4689 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4690 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4691 if (_playInbandDtmfEvent)
4692 {
4693 // Add tone to output mixer using a reduced length to minimize
4694 // risk of echo.
4695 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4696 attenuationDb);
4697 }
4698 }
4699
4700 if (_inbandDtmfGenerator.IsAddingTone())
4701 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004702 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004703 _inbandDtmfGenerator.GetSampleRate(frequency);
4704
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004705 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004706 {
4707 // Update sample rate of Dtmf tone since the mixing frequency
4708 // has changed.
4709 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004710 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004711 // Reset the tone to be added taking the new sample rate into
4712 // account.
4713 _inbandDtmfGenerator.ResetTone();
4714 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004715
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004716 int16_t toneBuffer[320];
4717 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004718 // Get 10ms tone segment and set time since last tone to zero
4719 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4720 {
4721 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4722 VoEId(_instanceId, _channelId),
4723 "Channel::EncodeAndSend() inserting Dtmf failed");
4724 return -1;
4725 }
4726
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004727 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004728 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004729 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004730 sample++)
4731 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004732 for (int channel = 0;
4733 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004734 channel++)
4735 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004736 const int index = sample * _audioFrame.num_channels_ + channel;
4737 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004738 }
4739 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004740
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004741 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004742 } else
4743 {
4744 // Add 10ms to "delay-since-last-tone" counter
4745 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4746 }
4747 return 0;
4748}
4749
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004750int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004751Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4752{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004753 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004754 if (_transportPtr == NULL)
4755 {
4756 return -1;
4757 }
4758 if (!RTCP)
4759 {
4760 return _transportPtr->SendPacket(_channelId, data, len);
4761 }
4762 else
4763 {
4764 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4765 }
4766}
4767
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004768// Called for incoming RTP packets after successful RTP header parsing.
4769void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4770 uint16_t sequence_number) {
4771 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4772 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4773 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004774
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004775 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004776 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004777
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004778 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004779 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004780 return;
4781 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004782
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004783 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004784 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004785
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004786 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4787 // Even though the actual sampling rate for G.722 audio is
4788 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4789 // 8,000 Hz because that value was erroneously assigned in
4790 // RFC 1890 and must remain unchanged for backward compatibility.
4791 rtp_receive_frequency = 8000;
4792 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4793 // We are resampling Opus internally to 32,000 Hz until all our
4794 // DSP routines can operate at 48,000 Hz, but the RTP clock
4795 // rate for the Opus payload format is standardized to 48,000 Hz,
4796 // because that is the maximum supported decoding sampling rate.
4797 rtp_receive_frequency = 48000;
4798 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004799
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004800 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4801 // every incoming packet.
4802 uint32_t timestamp_diff_ms = (rtp_timestamp -
4803 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004804 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4805 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4806 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4807 // timestamp, the resulting difference is negative, but is set to zero.
4808 // This can happen when a network glitch causes a packet to arrive late,
4809 // and during long comfort noise periods with clock drift.
4810 timestamp_diff_ms = 0;
4811 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004812
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004813 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4814 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004815
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004816 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004817
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004818 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004819
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004820 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4821 _recPacketDelayMs = packet_delay_ms;
4822 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004823
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004824 if (_average_jitter_buffer_delay_us == 0) {
4825 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4826 return;
4827 }
4828
4829 // Filter average delay value using exponential filter (alpha is
4830 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4831 // risk of rounding error) and compensate for it in GetDelayEstimate()
4832 // later.
4833 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4834 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004835}
4836
4837void
4838Channel::RegisterReceiveCodecsToRTPModule()
4839{
4840 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4841 "Channel::RegisterReceiveCodecsToRTPModule()");
4842
4843
4844 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004845 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004846
4847 for (int idx = 0; idx < nSupportedCodecs; idx++)
4848 {
4849 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004850 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004851 (rtp_receiver_->RegisterReceivePayload(
4852 codec.plname,
4853 codec.pltype,
4854 codec.plfreq,
4855 codec.channels,
4856 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004857 {
4858 WEBRTC_TRACE(
4859 kTraceWarning,
4860 kTraceVoice,
4861 VoEId(_instanceId, _channelId),
4862 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4863 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4864 codec.plname, codec.pltype, codec.plfreq,
4865 codec.channels, codec.rate);
4866 }
4867 else
4868 {
4869 WEBRTC_TRACE(
4870 kTraceInfo,
4871 kTraceVoice,
4872 VoEId(_instanceId, _channelId),
4873 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004874 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004875 "receiver",
4876 codec.plname, codec.pltype, codec.plfreq,
4877 codec.channels, codec.rate);
4878 }
4879 }
4880}
4881
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004882int Channel::SetSecondarySendCodec(const CodecInst& codec,
4883 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004884 // Sanity check for payload type.
4885 if (red_payload_type < 0 || red_payload_type > 127) {
4886 _engineStatisticsPtr->SetLastError(
4887 VE_PLTYPE_ERROR, kTraceError,
4888 "SetRedPayloadType() invalid RED payload type");
4889 return -1;
4890 }
4891
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004892 if (SetRedPayloadType(red_payload_type) < 0) {
4893 _engineStatisticsPtr->SetLastError(
4894 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4895 "SetSecondarySendCodec() Failed to register RED ACM");
4896 return -1;
4897 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004898 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004899 _engineStatisticsPtr->SetLastError(
4900 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4901 "SetSecondarySendCodec() Failed to register secondary send codec in "
4902 "ACM");
4903 return -1;
4904 }
4905
4906 return 0;
4907}
4908
4909void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004910 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004911}
4912
4913int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004914 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004915 _engineStatisticsPtr->SetLastError(
4916 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4917 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4918 return -1;
4919 }
4920 return 0;
4921}
4922
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004923// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004924int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004925 CodecInst codec;
4926 bool found_red = false;
4927
4928 // Get default RED settings from the ACM database
4929 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4930 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004931 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004932 if (!STR_CASE_CMP(codec.plname, "RED")) {
4933 found_red = true;
4934 break;
4935 }
4936 }
4937
4938 if (!found_red) {
4939 _engineStatisticsPtr->SetLastError(
4940 VE_CODEC_ERROR, kTraceError,
4941 "SetRedPayloadType() RED is not supported");
4942 return -1;
4943 }
4944
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004945 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004946 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004947 _engineStatisticsPtr->SetLastError(
4948 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4949 "SetRedPayloadType() RED registration in ACM module failed");
4950 return -1;
4951 }
4952
4953 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4954 _engineStatisticsPtr->SetLastError(
4955 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4956 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4957 return -1;
4958 }
4959 return 0;
4960}
4961
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004962int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4963 unsigned char id) {
4964 int error = 0;
4965 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4966 if (enable) {
4967 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4968 }
4969 return error;
4970}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004971} // namespace voe
4972} // namespace webrtc