blob: 576331ad534cdc5ce60df8c4278f177cc5e75cb7 [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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.orgead8a5b2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
minyue@webrtc.org4489c512013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.orgead8a5b2013-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.orga5db8e32014-03-20 12:04:09 +000016#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org7fc75bb2013-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.orgead8a5b2013-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.orgfec6b6e2014-03-24 10:38:25 +000027#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.orgead8a5b2013-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"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000035
36#if defined(_WIN32)
37#include <Qos.h>
38#endif
39
andrew@webrtc.orgd898c012012-11-14 19:07:54 +000040namespace webrtc {
41namespace voe {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000042
sprang@webrtc.org4f1f5fa2013-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.org54f03bc2013-04-09 10:09:10 +000091int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000092Channel::SendData(FrameType frameType,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +000093 uint8_t payloadType,
94 uint32_t timeStamp,
95 const uint8_t* payloadData,
96 uint16_t payloadSize,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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 {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000106 // 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.org80142aa2013-09-18 22:37:32 +0000109 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.
115 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
116 payloadType,
117 timeStamp,
118 // Leaving the time when this frame was
119 // received from the capture device as
120 // undefined for voice for now.
121 -1,
122 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.org54f03bc2013-04-09 10:09:10 +0000138int32_t
139Channel::InFrameType(int16_t frameType)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000140{
141 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
142 "Channel::InFrameType(frameType=%d)", frameType);
143
144 CriticalSectionScoped cs(&_callbackCritSect);
145 // 1 indicates speech
146 _sendFrameType = (frameType == 1) ? 1 : 0;
147 return 0;
148}
149
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000150int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000151Channel::OnRxVadDetected(int vadDecision)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000152{
153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
154 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
155
156 CriticalSectionScoped cs(&_callbackCritSect);
157 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.orgb27e6702013-10-18 21:10:51 +0000174 CriticalSectionScoped cs(&_callbackCritSect);
175
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org54f03bc2013-04-09 10:09:10 +0000184 uint8_t* bufferToSendPtr = (uint8_t*)data;
185 int32_t bufferLength = len;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000186
187 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000188 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000189 {
190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
191 VoEId(_instanceId,_channelId),
192 "Channel::SendPacket() RTP dump to output file failed");
193 }
194
wu@webrtc.orgb27e6702013-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;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000205 }
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000206 return n;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.orgb27e6702013-10-18 21:10:51 +0000218 CriticalSectionScoped cs(&_callbackCritSect);
219 if (_transportPtr == NULL)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000220 {
wu@webrtc.orgb27e6702013-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;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000226 }
227
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000228 uint8_t* bufferToSendPtr = (uint8_t*)data;
229 int32_t bufferLength = len;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000230
231 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000232 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000233 {
234 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
235 VoEId(_instanceId,_channelId),
236 "Channel::SendPacket() RTCP dump to output file failed");
237 }
238
wu@webrtc.orgb27e6702013-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;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000250 }
wu@webrtc.orgb27e6702013-10-18 21:10:51 +0000251 return n;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000252}
253
254void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000255Channel::OnPlayTelephoneEvent(int32_t id,
256 uint8_t event,
257 uint16_t lengthMs,
258 uint8_t volume)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000259{
260 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
261 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
262 " volume=%u)", id, event, lengthMs, volume);
263
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.orga20e2d42013-08-21 20:58:21 +0000279Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000280{
281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
282 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000283 id, ssrc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000284
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000285 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000286 assert(channel == _channelId);
287
dwkang@webrtc.orgc766a742013-08-29 07:34:12 +0000288 // Update ssrc so that NTP for AV sync can be updated.
289 _rtpRtcpModule->SetRemoteSSRC(ssrc);
290
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000291 if (_rtpObserver)
292 {
293 CriticalSectionScoped cs(&_callbackCritSect);
294
295 if (_rtpObserverPtr)
296 {
297 // Send new SSRC to registered observer using callback
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000298 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000299 }
300 }
301}
302
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000303void Channel::OnIncomingCSRCChanged(int32_t id,
304 uint32_t CSRC,
305 bool added)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org54f03bc2013-04-09 10:09:10 +0000311 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000312 assert(channel == _channelId);
313
314 if (_rtpObserver)
315 {
316 CriticalSectionScoped cs(&_callbackCritSect);
317
318 if (_rtpObserverPtr)
319 {
320 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
321 }
322 }
323}
324
stefan@webrtc.orga20e2d42013-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.org4f1f5fa2013-12-19 13:26:02 +0000331 statistics_proxy_->ResetStatistics();
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000332}
333
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000334void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000335Channel::OnApplicationDataReceived(int32_t id,
336 uint8_t subType,
337 uint32_t name,
338 uint16_t length,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000339 const uint8_t* data)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org54f03bc2013-04-09 10:09:10 +0000346 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000347 assert(channel == _channelId);
348
349 if (_rtcpObserver)
350 {
351 CriticalSectionScoped cs(&_callbackCritSect);
352
353 if (_rtcpObserverPtr)
354 {
355 _rtcpObserverPtr->OnApplicationDataReceived(channel,
356 subType,
357 name,
358 data,
359 length);
360 }
361 }
362}
363
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000364int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000365Channel::OnInitializeDecoder(
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000366 int32_t id,
367 int8_t payloadType,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000368 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000369 int frequency,
370 uint8_t channels,
371 uint32_t rate)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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
378 assert(VoEChannelId(id) == _channelId);
379
380 CodecInst receiveCodec = {0};
381 CodecInst dummyCodec = {0};
382
383 receiveCodec.pltype = payloadType;
384 receiveCodec.plfreq = frequency;
385 receiveCodec.channels = channels;
386 receiveCodec.rate = rate;
387 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgd4682362013-01-22 04:44:30 +0000388
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000389 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000390 receiveCodec.pacsize = dummyCodec.pacsize;
391
392 // Register the new codec to the ACM
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000393 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000394 {
395 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
396 VoEId(_instanceId, _channelId),
397 "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.orgca7a9a22013-05-14 08:31:39 +0000407Channel::OnPacketTimeout(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000408{
409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
410 "Channel::OnPacketTimeout(id=%d)", id);
411
412 CriticalSectionScoped cs(_callbackCritSectPtr);
413 if (_voiceEngineObserverPtr)
414 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000415 if (channel_state_.Get().receiving || _externalTransport)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000416 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000417 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.orgca7a9a22013-05-14 08:31:39 +0000434Channel::OnReceivedPacket(int32_t id,
435 RtpRtcpPacketType packetType)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000436{
437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
438 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
439 id, packetType);
440
441 assert(VoEChannelId(id) == _channelId);
442
443 // Notify only for the case when we have restarted an RTP session.
444 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
445 {
446 CriticalSectionScoped cs(_callbackCritSectPtr);
447 if (_voiceEngineObserverPtr)
448 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000449 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.orgca7a9a22013-05-14 08:31:39 +0000466Channel::OnPeriodicDeadOrAlive(int32_t id,
467 RTPAliveType alive)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000468{
469 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
470 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
471
henrika@webrtc.org1d25eac2013-04-05 14:34:57 +0000472 {
473 CriticalSectionScoped cs(&_callbackCritSect);
474 if (!_connectionObserver)
475 return;
476 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000477
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000478 int32_t channel = VoEChannelId(id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.orgdf08c5d2014-03-18 10:32:33 +0000493 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000505 // Send callback to the registered observer
506 if (_connectionObserver)
507 {
508 CriticalSectionScoped cs(&_callbackCritSect);
509 if (_connectionObserverPtr)
510 {
511 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
512 }
513 }
514}
515
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000516int32_t
517Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000518 uint16_t payloadSize,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.comca771492012-12-12 21:31:41 +0000528 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
529
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000530 if (!channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org510ee1b2013-09-23 23:02:24 +0000543 if (audio_coding_->IncomingPacket(payloadData,
544 payloadSize,
545 *rtpHeader) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org4aa9f1a2013-06-06 21:09:01 +0000553 // Update the packet delay.
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000554 UpdatePacketDelay(rtpHeader->header.timestamp,
555 rtpHeader->header.sequenceNumber);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +0000556
wu@webrtc.org7fc75bb2013-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.org4aa9f1a2013-06-06 21:09:01 +0000560
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000561 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org7fc75bb2013-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.org4aa9f1a2013-06-06 21:09:01 +0000567 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000568 return 0;
569}
570
stefan@webrtc.orgdb74c612013-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.orgca7a9a22013-05-14 08:31:39 +0000586int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +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.org510ee1b2013-09-23 23:02:24 +0000592 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
593 &audioFrame) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000594 {
595 WEBRTC_TRACE(kTraceError, kTraceVoice,
596 VoEId(_instanceId,_channelId),
597 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
598 // 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;
603 }
604
605 if (_RxVadDetection)
606 {
607 UpdateRxVadDetection(audioFrame);
608 }
609
610 // Convert module ID to internal VoE channel ID
611 audioFrame.id_ = VoEChannelId(audioFrame.id_);
612 // Store speech type for dead-or-alive detection
613 _outputSpeechType = audioFrame.speech_type_;
614
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000615 ChannelState::State state = channel_state_.Get();
616
617 if (state.rx_apm_is_enabled) {
andrew@webrtc.orge95dc252014-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 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000623 }
624
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000625 float output_gain = 1.0f;
626 float left_pan = 1.0f;
627 float right_pan = 1.0f;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000628 {
wu@webrtc.orgf7651ef2013-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);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000639 }
640
641 // Scale left and/or right channel(s) if stereo and master balance is
642 // active
643
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000644 if (left_pan != 1.0f || right_pan != 1.0f)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000645 {
646 if (audioFrame.num_channels_ == 1)
647 {
648 // Emulate stereo mode since panning is active.
649 // The mono signal is copied to both left and right channels here.
650 AudioFrameOperations::MonoToStereo(&audioFrame);
651 }
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.orgf7651ef2013-10-17 18:28:55 +0000657 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000658 }
659
660 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000661 if (state.output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000662 {
663 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
664 }
665
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000666 // External media
667 if (_outputExternalMedia)
668 {
669 CriticalSectionScoped cs(&_callbackCritSect);
670 const bool isStereo = (audioFrame.num_channels_ == 2);
671 if (_outputExternalMediaCallbackPtr)
672 {
673 _outputExternalMediaCallbackPtr->Process(
674 _channelId,
675 kPlaybackPerChannel,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000676 (int16_t*)audioFrame.data_,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000677 audioFrame.samples_per_channel_,
678 audioFrame.sample_rate_hz_,
679 isStereo);
680 }
681 }
682
683 // Record playout if enabled
684 {
685 CriticalSectionScoped cs(&_fileCritSect);
686
687 if (_outputFileRecording && _outputFileRecorderPtr)
688 {
689 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
690 }
691 }
692
693 // Measure audio level (0-9)
694 _outputAudioLevel.ComputeLevel(audioFrame);
695
696 return 0;
697}
698
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000699int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000700Channel::NeededFrequency(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000701{
702 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
703 "Channel::NeededFrequency(id=%d)", id);
704
705 int highestNeeded = 0;
706
707 // Determine highest needed receive frequency
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000708 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000709
710 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000711 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000712 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000713 highestNeeded = audio_coding_->PlayoutFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000714 }
715 else
716 {
717 highestNeeded = receiveFrequency;
718 }
719
720 // Special case, if we're playing a file on the playout side
721 // we take that frequency into consideration as well
722 // This is not needed on sending side, since the codec will
723 // limit the spectrum anyway.
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000724 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000725 {
726 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000727 if (_outputFilePlayerPtr)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000728 {
729 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
730 {
731 highestNeeded=_outputFilePlayerPtr->Frequency();
732 }
733 }
734 }
735
736 return(highestNeeded);
737}
738
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +0000739int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000740Channel::CreateChannel(Channel*& channel,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000741 int32_t channelId,
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000742 uint32_t instanceId,
743 const Config& config)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000744{
745 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
746 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
747 channelId, instanceId);
748
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000749 channel = new Channel(channelId, instanceId, config);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000750 if (channel == NULL)
751 {
752 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
753 VoEId(instanceId,channelId),
754 "Channel::CreateChannel() unable to allocate memory for"
755 " channel");
756 return -1;
757 }
758 return 0;
759}
760
761void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000762Channel::PlayNotification(int32_t id, uint32_t durationMs)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000763{
764 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
765 "Channel::PlayNotification(id=%d, durationMs=%d)",
766 id, durationMs);
767
768 // Not implement yet
769}
770
771void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000772Channel::RecordNotification(int32_t id, uint32_t durationMs)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000773{
774 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
775 "Channel::RecordNotification(id=%d, durationMs=%d)",
776 id, durationMs);
777
778 // Not implement yet
779}
780
781void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000782Channel::PlayFileEnded(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000783{
784 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
785 "Channel::PlayFileEnded(id=%d)", id);
786
787 if (id == _inputFilePlayerId)
788 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000789 channel_state_.SetInputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000790 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
791 VoEId(_instanceId,_channelId),
792 "Channel::PlayFileEnded() => input file player module is"
793 " shutdown");
794 }
795 else if (id == _outputFilePlayerId)
796 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000797 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000798 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
799 VoEId(_instanceId,_channelId),
800 "Channel::PlayFileEnded() => output file player module is"
801 " shutdown");
802 }
803}
804
805void
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000806Channel::RecordFileEnded(int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000807{
808 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
809 "Channel::RecordFileEnded(id=%d)", id);
810
811 assert(id == _outputFileRecorderId);
812
813 CriticalSectionScoped cs(&_fileCritSect);
814
815 _outputFileRecording = false;
816 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
817 VoEId(_instanceId,_channelId),
818 "Channel::RecordFileEnded() => output file recorder module is"
819 " shutdown");
820}
821
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +0000822Channel::Channel(int32_t channelId,
minyue@webrtc.org4489c512013-09-12 17:03:00 +0000823 uint32_t instanceId,
824 const Config& config) :
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000825 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
826 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +0000827 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000828 _instanceId(instanceId),
829 _channelId(channelId),
stefan@webrtc.org6696fba2013-05-29 12:12:51 +0000830 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000831 rtp_payload_registry_(
andresp@webrtc.org99681312014-04-08 11:06:12 +0000832 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000833 rtp_receive_statistics_(ReceiveStatistics::Create(
834 Clock::GetRealTimeClock())),
835 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
836 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
837 this, this, rtp_payload_registry_.get())),
838 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000839 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000840 VoEModuleId(instanceId, channelId))),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000841 _rtpDumpIn(*RtpDump::CreateRtpDump()),
842 _rtpDumpOut(*RtpDump::CreateRtpDump()),
843 _outputAudioLevel(),
844 _externalTransport(false),
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000845 _audioLevel_dBov(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000846 _inputFilePlayerPtr(NULL),
847 _outputFilePlayerPtr(NULL),
848 _outputFileRecorderPtr(NULL),
849 // Avoid conflict with other channels by adding 1024 - 1026,
850 // won't use as much as 1024 channels.
851 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
852 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
853 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000854 _outputFileRecording(false),
855 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
856 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000857 _outputExternalMedia(false),
858 _inputExternalMediaCallbackPtr(NULL),
859 _outputExternalMediaCallbackPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000860 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
861 _sendTelephoneEventPayloadType(106),
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +0000862 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +0000863 playout_timestamp_rtp_(0),
864 playout_timestamp_rtcp_(0),
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000865 playout_delay_ms_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000866 _numberOfDiscardedPackets(0),
xians@webrtc.org5ce87232013-07-31 16:30:19 +0000867 send_sequence_number_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000868 _engineStatisticsPtr(NULL),
869 _outputMixerPtr(NULL),
870 _transmitMixerPtr(NULL),
871 _moduleProcessThreadPtr(NULL),
872 _audioDeviceModulePtr(NULL),
873 _voiceEngineObserverPtr(NULL),
874 _callbackCritSectPtr(NULL),
875 _transportPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000876 _rxVadObserverPtr(NULL),
877 _oldVadDecision(-1),
878 _sendFrameType(0),
879 _rtpObserverPtr(NULL),
880 _rtcpObserverPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000881 _externalPlayout(false),
roosa@google.comb9e3afc2012-12-12 23:00:29 +0000882 _externalMixing(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000883 _mixFileWithMicrophone(false),
884 _rtpObserver(false),
885 _rtcpObserver(false),
886 _mute(false),
887 _panLeft(1.0f),
888 _panRight(1.0f),
889 _outputGain(1.0f),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000890 _playOutbandDtmfEvent(false),
891 _playInbandDtmfEvent(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000892 _lastLocalTimeStamp(0),
roosa@google.comca771492012-12-12 21:31:41 +0000893 _lastRemoteTimeStamp(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000894 _lastPayloadType(0),
895 _includeAudioLevelIndication(false),
896 _rtpPacketTimedOut(false),
897 _rtpPacketTimeOutIsEnabled(false),
898 _rtpTimeOutSeconds(0),
899 _connectionObserver(false),
900 _connectionObserverPtr(NULL),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000901 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +0000902 vie_network_(NULL),
903 video_channel_(-1),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +0000904 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orgd5577342013-05-22 20:39:43 +0000905 least_required_delay_ms_(0),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000906 _previousTimestamp(0),
907 _recPacketDelayMs(20),
908 _RxVadDetection(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000909 _rxAgcIsEnabled(false),
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +0000910 _rxNsIsEnabled(false),
911 restored_packet_in_use_(false)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000912{
913 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
914 "Channel::Channel() - ctor");
915 _inbandDtmfQueue.ResetDtmf();
916 _inbandDtmfGenerator.Init();
917 _outputAudioLevel.Clear();
918
919 RtpRtcp::Configuration configuration;
920 configuration.id = VoEModuleId(instanceId, channelId);
921 configuration.audio = true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000922 configuration.outgoing_transport = this;
923 configuration.rtcp_feedback = this;
924 configuration.audio_messages = this;
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000925 configuration.receive_statistics = rtp_receive_statistics_.get();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000926
927 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000928
929 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
930 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
931 statistics_proxy_.get());
aluebs@webrtc.org1a07e422014-04-16 11:58:18 +0000932
933 Config audioproc_config;
934 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
935 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000936}
937
938Channel::~Channel()
939{
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +0000940 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000941 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
942 "Channel::~Channel() - dtor");
943
944 if (_outputExternalMedia)
945 {
946 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
947 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +0000948 if (channel_state_.Get().input_external_media)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000949 {
950 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
951 }
952 StopSend();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000953 StopPlayout();
954
955 {
956 CriticalSectionScoped cs(&_fileCritSect);
957 if (_inputFilePlayerPtr)
958 {
959 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
960 _inputFilePlayerPtr->StopPlayingFile();
961 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
962 _inputFilePlayerPtr = NULL;
963 }
964 if (_outputFilePlayerPtr)
965 {
966 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
967 _outputFilePlayerPtr->StopPlayingFile();
968 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
969 _outputFilePlayerPtr = NULL;
970 }
971 if (_outputFileRecorderPtr)
972 {
973 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
974 _outputFileRecorderPtr->StopRecording();
975 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
976 _outputFileRecorderPtr = NULL;
977 }
978 }
979
980 // The order to safely shutdown modules in a channel is:
981 // 1. De-register callbacks in modules
982 // 2. De-register modules in process thread
983 // 3. Destroy modules
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000984 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000985 {
986 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
987 VoEId(_instanceId,_channelId),
988 "~Channel() failed to de-register transport callback"
989 " (Audio coding module)");
990 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +0000991 if (audio_coding_->RegisterVADCallback(NULL) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000992 {
993 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
994 VoEId(_instanceId,_channelId),
995 "~Channel() failed to de-register VAD callback"
996 " (Audio coding module)");
997 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000998 // De-register modules in process thread
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000999 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
1000 {
1001 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1002 VoEId(_instanceId,_channelId),
1003 "~Channel() failed to deregister RTP/RTCP module");
1004 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001005 // End of modules shutdown
1006
1007 // Delete other objects
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001008 if (vie_network_) {
1009 vie_network_->Release();
1010 vie_network_ = NULL;
1011 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001012 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1013 RtpDump::DestroyRtpDump(&_rtpDumpOut);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001014 delete &_callbackCritSect;
1015 delete &_fileCritSect;
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00001016 delete &volume_settings_critsect_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001017}
1018
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001019int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001020Channel::Init()
1021{
1022 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1023 "Channel::Init()");
1024
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001025 channel_state_.Reset();
1026
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001027 // --- Initial sanity
1028
1029 if ((_engineStatisticsPtr == NULL) ||
1030 (_moduleProcessThreadPtr == NULL))
1031 {
1032 WEBRTC_TRACE(kTraceError, kTraceVoice,
1033 VoEId(_instanceId,_channelId),
1034 "Channel::Init() must call SetEngineInformation() first");
1035 return -1;
1036 }
1037
1038 // --- Add modules to process thread (for periodic schedulation)
1039
1040 const bool processThreadFail =
1041 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001042 false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001043 if (processThreadFail)
1044 {
1045 _engineStatisticsPtr->SetLastError(
1046 VE_CANNOT_INIT_CHANNEL, kTraceError,
1047 "Channel::Init() modules not registered");
1048 return -1;
1049 }
1050 // --- ACM initialization
1051
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001052 if ((audio_coding_->InitializeReceiver() == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001053#ifdef WEBRTC_CODEC_AVT
1054 // out-of-band Dtmf tones are played out by default
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001055 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001056#endif
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001057 (audio_coding_->InitializeSender() == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001058 {
1059 _engineStatisticsPtr->SetLastError(
1060 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1061 "Channel::Init() unable to initialize the ACM - 1");
1062 return -1;
1063 }
1064
1065 // --- RTP/RTCP module initialization
1066
1067 // Ensure that RTCP is enabled by default for the created channel.
1068 // Note that, the module will keep generating RTCP until it is explicitly
1069 // disabled by the user.
1070 // After StopListen (when no sockets exists), RTCP packets will no longer
1071 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001072 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1073 // RTCP is enabled by default.
1074 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001075 {
1076 _engineStatisticsPtr->SetLastError(
1077 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1078 "Channel::Init() RTP/RTCP module not initialized");
1079 return -1;
1080 }
1081
1082 // --- Register all permanent callbacks
1083 const bool fail =
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001084 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1085 (audio_coding_->RegisterVADCallback(this) == -1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001086
1087 if (fail)
1088 {
1089 _engineStatisticsPtr->SetLastError(
1090 VE_CANNOT_INIT_CHANNEL, kTraceError,
1091 "Channel::Init() callbacks not registered");
1092 return -1;
1093 }
1094
1095 // --- Register all supported codecs to the receiving side of the
1096 // RTP/RTCP module
1097
1098 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001099 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001100
1101 for (int idx = 0; idx < nSupportedCodecs; idx++)
1102 {
1103 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001104 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001105 (rtp_receiver_->RegisterReceivePayload(
1106 codec.plname,
1107 codec.pltype,
1108 codec.plfreq,
1109 codec.channels,
1110 (codec.rate < 0) ? 0 : codec.rate) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001111 {
1112 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1113 VoEId(_instanceId,_channelId),
1114 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1115 "to RTP/RTCP receiver",
1116 codec.plname, codec.pltype, codec.plfreq,
1117 codec.channels, codec.rate);
1118 }
1119 else
1120 {
1121 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1122 VoEId(_instanceId,_channelId),
1123 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1124 "the RTP/RTCP receiver",
1125 codec.plname, codec.pltype, codec.plfreq,
1126 codec.channels, codec.rate);
1127 }
1128
1129 // Ensure that PCMU is used as default codec on the sending side
1130 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
1131 {
1132 SetSendCodec(codec);
1133 }
1134
1135 // Register default PT for outband 'telephone-event'
1136 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1137 {
1138 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001139 (audio_coding_->RegisterReceiveCodec(codec) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001140 {
1141 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1142 VoEId(_instanceId,_channelId),
1143 "Channel::Init() failed to register outband "
1144 "'telephone-event' (%d/%d) correctly",
1145 codec.pltype, codec.plfreq);
1146 }
1147 }
1148
1149 if (!STR_CASE_CMP(codec.plname, "CN"))
1150 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001151 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1152 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001153 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
1154 {
1155 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1156 VoEId(_instanceId,_channelId),
1157 "Channel::Init() failed to register CN (%d/%d) "
1158 "correctly - 1",
1159 codec.pltype, codec.plfreq);
1160 }
1161 }
1162#ifdef WEBRTC_CODEC_RED
1163 // Register RED to the receiving side of the ACM.
1164 // We will not receive an OnInitializeDecoder() callback for RED.
1165 if (!STR_CASE_CMP(codec.plname, "RED"))
1166 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001167 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001168 {
1169 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1170 VoEId(_instanceId,_channelId),
1171 "Channel::Init() failed to register RED (%d/%d) "
1172 "correctly",
1173 codec.pltype, codec.plfreq);
1174 }
1175 }
1176#endif
1177 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001178
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00001179 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1180 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1181 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001182 }
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00001183 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1184 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1185 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001186 }
1187
1188 return 0;
1189}
1190
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001191int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001192Channel::SetEngineInformation(Statistics& engineStatistics,
1193 OutputMixer& outputMixer,
1194 voe::TransmitMixer& transmitMixer,
1195 ProcessThread& moduleProcessThread,
1196 AudioDeviceModule& audioDeviceModule,
1197 VoiceEngineObserver* voiceEngineObserver,
1198 CriticalSectionWrapper* callbackCritSect)
1199{
1200 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1201 "Channel::SetEngineInformation()");
1202 _engineStatisticsPtr = &engineStatistics;
1203 _outputMixerPtr = &outputMixer;
1204 _transmitMixerPtr = &transmitMixer,
1205 _moduleProcessThreadPtr = &moduleProcessThread;
1206 _audioDeviceModulePtr = &audioDeviceModule;
1207 _voiceEngineObserverPtr = voiceEngineObserver;
1208 _callbackCritSectPtr = callbackCritSect;
1209 return 0;
1210}
1211
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001212int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001213Channel::UpdateLocalTimeStamp()
1214{
1215
1216 _timeStamp += _audioFrame.samples_per_channel_;
1217 return 0;
1218}
1219
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001220int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001221Channel::StartPlayout()
1222{
1223 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1224 "Channel::StartPlayout()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001225 if (channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001226 {
1227 return 0;
1228 }
roosa@google.comb9e3afc2012-12-12 23:00:29 +00001229
1230 if (!_externalMixing) {
1231 // Add participant as candidates for mixing.
1232 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1233 {
1234 _engineStatisticsPtr->SetLastError(
1235 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1236 "StartPlayout() failed to add participant to mixer");
1237 return -1;
1238 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001239 }
1240
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001241 channel_state_.SetPlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001242 if (RegisterFilePlayingToMixer() != 0)
1243 return -1;
1244
1245 return 0;
1246}
1247
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001248int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001249Channel::StopPlayout()
1250{
1251 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1252 "Channel::StopPlayout()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001253 if (!channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001254 {
1255 return 0;
1256 }
roosa@google.comb9e3afc2012-12-12 23:00:29 +00001257
1258 if (!_externalMixing) {
1259 // Remove participant as candidates for mixing
1260 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1261 {
1262 _engineStatisticsPtr->SetLastError(
1263 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1264 "StopPlayout() failed to remove participant from mixer");
1265 return -1;
1266 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001267 }
1268
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001269 channel_state_.SetPlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001270 _outputAudioLevel.Clear();
1271
1272 return 0;
1273}
1274
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001275int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001276Channel::StartSend()
1277{
1278 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1279 "Channel::StartSend()");
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001280 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001281 // This needs to be done before |sending| is set to true.
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001282 if (send_sequence_number_)
1283 SetInitSequenceNumber(send_sequence_number_);
1284
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001285 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001286 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001287 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001288 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001289 channel_state_.SetSending(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001290
1291 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
1292 {
1293 _engineStatisticsPtr->SetLastError(
1294 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1295 "StartSend() RTP/RTCP failed to start sending");
1296 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001297 channel_state_.SetSending(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001298 return -1;
1299 }
1300
1301 return 0;
1302}
1303
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001304int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001305Channel::StopSend()
1306{
1307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1308 "Channel::StopSend()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001309 if (!channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001310 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001311 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001312 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001313 channel_state_.SetSending(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001314
xians@webrtc.org5ce87232013-07-31 16:30:19 +00001315 // Store the sequence number to be able to pick up the same sequence for
1316 // the next StartSend(). This is needed for restarting device, otherwise
1317 // it might cause libSRTP to complain about packets being replayed.
1318 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1319 // CL is landed. See issue
1320 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1321 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1322
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001323 // Reset sending SSRC and sequence number and triggers direct transmission
1324 // of RTCP BYE
1325 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1326 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
1327 {
1328 _engineStatisticsPtr->SetLastError(
1329 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1330 "StartSend() RTP/RTCP failed to stop sending");
1331 }
1332
1333 return 0;
1334}
1335
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001336int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001337Channel::StartReceiving()
1338{
1339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1340 "Channel::StartReceiving()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001341 if (channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001342 {
1343 return 0;
1344 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001345 channel_state_.SetReceiving(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001346 _numberOfDiscardedPackets = 0;
1347 return 0;
1348}
1349
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001350int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001351Channel::StopReceiving()
1352{
1353 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1354 "Channel::StopReceiving()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001355 if (!channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001356 {
1357 return 0;
1358 }
pwestin@webrtc.org912b7f72013-03-13 23:20:57 +00001359
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001360 channel_state_.SetReceiving(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001361 return 0;
1362}
1363
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001364int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001365Channel::SetNetEQPlayoutMode(NetEqModes mode)
1366{
1367 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1368 "Channel::SetNetEQPlayoutMode()");
1369 AudioPlayoutMode playoutMode(voice);
1370 switch (mode)
1371 {
1372 case kNetEqDefault:
1373 playoutMode = voice;
1374 break;
1375 case kNetEqStreaming:
1376 playoutMode = streaming;
1377 break;
1378 case kNetEqFax:
1379 playoutMode = fax;
1380 break;
roosa@google.com90d333e2012-12-12 21:59:14 +00001381 case kNetEqOff:
1382 playoutMode = off;
1383 break;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001384 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001385 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001386 {
1387 _engineStatisticsPtr->SetLastError(
1388 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1389 "SetNetEQPlayoutMode() failed to set playout mode");
1390 return -1;
1391 }
1392 return 0;
1393}
1394
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001395int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001396Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1397{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001398 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001399 switch (playoutMode)
1400 {
1401 case voice:
1402 mode = kNetEqDefault;
1403 break;
1404 case streaming:
1405 mode = kNetEqStreaming;
1406 break;
1407 case fax:
1408 mode = kNetEqFax;
1409 break;
roosa@google.com90d333e2012-12-12 21:59:14 +00001410 case off:
1411 mode = kNetEqOff;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001412 }
1413 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1414 VoEId(_instanceId,_channelId),
1415 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1416 return 0;
1417}
1418
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001419int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001420Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1421{
1422 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1423 "Channel::RegisterVoiceEngineObserver()");
1424 CriticalSectionScoped cs(&_callbackCritSect);
1425
1426 if (_voiceEngineObserverPtr)
1427 {
1428 _engineStatisticsPtr->SetLastError(
1429 VE_INVALID_OPERATION, kTraceError,
1430 "RegisterVoiceEngineObserver() observer already enabled");
1431 return -1;
1432 }
1433 _voiceEngineObserverPtr = &observer;
1434 return 0;
1435}
1436
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001437int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001438Channel::DeRegisterVoiceEngineObserver()
1439{
1440 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1441 "Channel::DeRegisterVoiceEngineObserver()");
1442 CriticalSectionScoped cs(&_callbackCritSect);
1443
1444 if (!_voiceEngineObserverPtr)
1445 {
1446 _engineStatisticsPtr->SetLastError(
1447 VE_INVALID_OPERATION, kTraceWarning,
1448 "DeRegisterVoiceEngineObserver() observer already disabled");
1449 return 0;
1450 }
1451 _voiceEngineObserverPtr = NULL;
1452 return 0;
1453}
1454
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001455int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001456Channel::GetSendCodec(CodecInst& codec)
1457{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001458 return (audio_coding_->SendCodec(&codec));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001459}
1460
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001461int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001462Channel::GetRecCodec(CodecInst& codec)
1463{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001464 return (audio_coding_->ReceiveCodec(&codec));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001465}
1466
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001467int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001468Channel::SetSendCodec(const CodecInst& codec)
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::SetSendCodec()");
1472
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001473 if (audio_coding_->RegisterSendCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001474 {
1475 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1476 "SetSendCodec() failed to register codec to ACM");
1477 return -1;
1478 }
1479
1480 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1481 {
1482 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1483 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1484 {
1485 WEBRTC_TRACE(
1486 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1487 "SetSendCodec() failed to register codec to"
1488 " RTP/RTCP module");
1489 return -1;
1490 }
1491 }
1492
1493 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
1494 {
1495 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1496 "SetSendCodec() failed to set audio packet size");
1497 return -1;
1498 }
1499
1500 return 0;
1501}
1502
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001503int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001504Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1505{
1506 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1507 "Channel::SetVADStatus(mode=%d)", mode);
1508 // To disable VAD, DTX must be disabled too
1509 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001510 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001511 {
1512 _engineStatisticsPtr->SetLastError(
1513 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1514 "SetVADStatus() failed to set VAD");
1515 return -1;
1516 }
1517 return 0;
1518}
1519
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001520int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001521Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1522{
1523 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1524 "Channel::GetVADStatus");
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001525 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001526 {
1527 _engineStatisticsPtr->SetLastError(
1528 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1529 "GetVADStatus() failed to get VAD status");
1530 return -1;
1531 }
1532 disabledDTX = !disabledDTX;
1533 return 0;
1534}
1535
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001536int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001537Channel::SetRecPayloadType(const CodecInst& codec)
1538{
1539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1540 "Channel::SetRecPayloadType()");
1541
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001542 if (channel_state_.Get().playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001543 {
1544 _engineStatisticsPtr->SetLastError(
1545 VE_ALREADY_PLAYING, kTraceError,
1546 "SetRecPayloadType() unable to set PT while playing");
1547 return -1;
1548 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001549 if (channel_state_.Get().receiving)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001550 {
1551 _engineStatisticsPtr->SetLastError(
1552 VE_ALREADY_LISTENING, kTraceError,
1553 "SetRecPayloadType() unable to set PT while listening");
1554 return -1;
1555 }
1556
1557 if (codec.pltype == -1)
1558 {
1559 // De-register the selected codec (RTP/RTCP module and ACM)
1560
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001561 int8_t pltype(-1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001562 CodecInst rxCodec = codec;
1563
1564 // Get payload type for the given codec
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001565 rtp_payload_registry_->ReceivePayloadType(
1566 rxCodec.plname,
1567 rxCodec.plfreq,
1568 rxCodec.channels,
1569 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1570 &pltype);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001571 rxCodec.pltype = pltype;
1572
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001573 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001574 {
1575 _engineStatisticsPtr->SetLastError(
1576 VE_RTP_RTCP_MODULE_ERROR,
1577 kTraceError,
1578 "SetRecPayloadType() RTP/RTCP-module deregistration "
1579 "failed");
1580 return -1;
1581 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001582 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001583 {
1584 _engineStatisticsPtr->SetLastError(
1585 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1586 "SetRecPayloadType() ACM deregistration failed - 1");
1587 return -1;
1588 }
1589 return 0;
1590 }
1591
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001592 if (rtp_receiver_->RegisterReceivePayload(
1593 codec.plname,
1594 codec.pltype,
1595 codec.plfreq,
1596 codec.channels,
1597 (codec.rate < 0) ? 0 : codec.rate) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001598 {
1599 // First attempt to register failed => de-register and try again
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001600 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1601 if (rtp_receiver_->RegisterReceivePayload(
1602 codec.plname,
1603 codec.pltype,
1604 codec.plfreq,
1605 codec.channels,
1606 (codec.rate < 0) ? 0 : codec.rate) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001607 {
1608 _engineStatisticsPtr->SetLastError(
1609 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1610 "SetRecPayloadType() RTP/RTCP-module registration failed");
1611 return -1;
1612 }
1613 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001614 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001615 {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001616 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1617 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001618 {
1619 _engineStatisticsPtr->SetLastError(
1620 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1621 "SetRecPayloadType() ACM registration failed - 1");
1622 return -1;
1623 }
1624 }
1625 return 0;
1626}
1627
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001628int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001629Channel::GetRecPayloadType(CodecInst& codec)
1630{
1631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1632 "Channel::GetRecPayloadType()");
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001633 int8_t payloadType(-1);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001634 if (rtp_payload_registry_->ReceivePayloadType(
1635 codec.plname,
1636 codec.plfreq,
1637 codec.channels,
1638 (codec.rate < 0) ? 0 : codec.rate,
1639 &payloadType) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001640 {
1641 _engineStatisticsPtr->SetLastError(
1642 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1643 "GetRecPayloadType() failed to retrieve RX payload type");
1644 return -1;
1645 }
1646 codec.pltype = payloadType;
1647 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1648 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1649 return 0;
1650}
1651
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001652int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001653Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1654{
1655 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1656 "Channel::SetSendCNPayloadType()");
1657
1658 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001659 int32_t samplingFreqHz(-1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001660 const int kMono = 1;
1661 if (frequency == kFreq32000Hz)
1662 samplingFreqHz = 32000;
1663 else if (frequency == kFreq16000Hz)
1664 samplingFreqHz = 16000;
1665
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001666 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001667 {
1668 _engineStatisticsPtr->SetLastError(
1669 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1670 "SetSendCNPayloadType() failed to retrieve default CN codec "
1671 "settings");
1672 return -1;
1673 }
1674
1675 // Modify the payload type (must be set to dynamic range)
1676 codec.pltype = type;
1677
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00001678 if (audio_coding_->RegisterSendCodec(codec) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001679 {
1680 _engineStatisticsPtr->SetLastError(
1681 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1682 "SetSendCNPayloadType() failed to register CN to ACM");
1683 return -1;
1684 }
1685
1686 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1687 {
1688 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1689 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
1690 {
1691 _engineStatisticsPtr->SetLastError(
1692 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1693 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1694 "module");
1695 return -1;
1696 }
1697 }
1698 return 0;
1699}
1700
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001701int32_t Channel::RegisterExternalTransport(Transport& transport)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001702{
1703 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1704 "Channel::RegisterExternalTransport()");
1705
1706 CriticalSectionScoped cs(&_callbackCritSect);
1707
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001708 if (_externalTransport)
1709 {
1710 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1711 kTraceError,
1712 "RegisterExternalTransport() external transport already enabled");
1713 return -1;
1714 }
1715 _externalTransport = true;
1716 _transportPtr = &transport;
1717 return 0;
1718}
1719
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001720int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001721Channel::DeRegisterExternalTransport()
1722{
1723 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1724 "Channel::DeRegisterExternalTransport()");
1725
1726 CriticalSectionScoped cs(&_callbackCritSect);
1727
1728 if (!_transportPtr)
1729 {
1730 _engineStatisticsPtr->SetLastError(
1731 VE_INVALID_OPERATION, kTraceWarning,
1732 "DeRegisterExternalTransport() external transport already "
1733 "disabled");
1734 return 0;
1735 }
1736 _externalTransport = false;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001737 _transportPtr = NULL;
1738 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1739 "DeRegisterExternalTransport() all transport is disabled");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001740 return 0;
1741}
1742
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001743int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1744 const PacketTime& packet_time) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001745 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1746 "Channel::ReceivedRTPPacket()");
1747
1748 // Store playout timestamp for the received RTP packet
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00001749 UpdatePlayoutTimestamp(false);
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001750
1751 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001752 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1753 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001754 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1755 VoEId(_instanceId,_channelId),
1756 "Channel::SendPacket() RTP dump to input file failed");
1757 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001758 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001759 RTPHeader header;
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001760 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1761 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1762 "Incoming packet: invalid RTP header");
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001763 return -1;
1764 }
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001765 header.payload_type_frequency =
1766 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001767 if (header.payload_type_frequency < 0)
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001768 return -1;
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001769 bool in_order = IsPacketInOrder(header);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001770 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001771 IsPacketRetransmitted(header, in_order));
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001772 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00001773
1774 // Forward any packets to ViE bandwidth estimator, if enabled.
1775 {
1776 CriticalSectionScoped cs(&_callbackCritSect);
1777 if (vie_network_) {
1778 int64_t arrival_time_ms;
1779 if (packet_time.timestamp != -1) {
1780 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1781 } else {
1782 arrival_time_ms = TickTime::MillisecondTimestamp();
1783 }
1784 int payload_length = length - header.headerLength;
1785 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1786 payload_length, header);
1787 }
1788 }
1789
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001790 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001791}
1792
1793bool Channel::ReceivePacket(const uint8_t* packet,
1794 int packet_length,
1795 const RTPHeader& header,
1796 bool in_order) {
1797 if (rtp_payload_registry_->IsEncapsulated(header)) {
1798 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001799 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001800 const uint8_t* payload = packet + header.headerLength;
1801 int payload_length = packet_length - header.headerLength;
1802 assert(payload_length >= 0);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001803 PayloadUnion payload_specific;
1804 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001805 &payload_specific)) {
1806 return false;
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001807 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001808 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1809 payload_specific, in_order);
1810}
1811
1812bool Channel::HandleEncapsulation(const uint8_t* packet,
1813 int packet_length,
1814 const RTPHeader& header) {
1815 if (!rtp_payload_registry_->IsRtx(header))
1816 return false;
1817
1818 // Remove the RTX header and parse the original RTP header.
1819 if (packet_length < header.headerLength)
1820 return false;
1821 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1822 return false;
1823 if (restored_packet_in_use_) {
1824 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1825 "Multiple RTX headers detected, dropping packet");
1826 return false;
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001827 }
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001828 uint8_t* restored_packet_ptr = restored_packet_;
1829 if (!rtp_payload_registry_->RestoreOriginalPacket(
1830 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1831 header)) {
1832 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1833 "Incoming RTX packet: invalid RTP header");
1834 return false;
1835 }
1836 restored_packet_in_use_ = true;
1837 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1838 restored_packet_in_use_ = false;
1839 return ret;
1840}
1841
1842bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1843 StreamStatistician* statistician =
1844 rtp_receive_statistics_->GetStatistician(header.ssrc);
1845 if (!statistician)
1846 return false;
1847 return statistician->IsPacketInOrder(header.sequenceNumber);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001848}
1849
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001850bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1851 bool in_order) const {
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001852 // Retransmissions are handled separately if RTX is enabled.
1853 if (rtp_payload_registry_->RtxEnabled())
1854 return false;
1855 StreamStatistician* statistician =
1856 rtp_receive_statistics_->GetStatistician(header.ssrc);
1857 if (!statistician)
1858 return false;
1859 // Check if this is a retransmission.
1860 uint16_t min_rtt = 0;
1861 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org7e97e4c2013-11-08 15:18:52 +00001862 return !in_order &&
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00001863 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00001864}
1865
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001866int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001867 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1868 "Channel::ReceivedRTCPPacket()");
1869 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00001870 UpdatePlayoutTimestamp(true);
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001871
1872 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001873 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1874 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001875 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1876 VoEId(_instanceId,_channelId),
1877 "Channel::SendPacket() RTCP dump to input file failed");
1878 }
1879
1880 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.org6696fba2013-05-29 12:12:51 +00001881 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1882 (uint16_t)length) == -1) {
pwestin@webrtc.orge4932182013-04-03 15:43:57 +00001883 _engineStatisticsPtr->SetLastError(
1884 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1885 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1886 }
1887 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001888}
1889
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001890int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00001891 bool loop,
1892 FileFormats format,
1893 int startPosition,
1894 float volumeScaling,
1895 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001896 const CodecInst* codecInst)
1897{
1898 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1899 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1900 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1901 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1902 startPosition, stopPosition);
1903
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001904 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_ALREADY_PLAYING, kTraceError,
1908 "StartPlayingFileLocally() is already playing");
1909 return -1;
1910 }
1911
1912 {
1913 CriticalSectionScoped cs(&_fileCritSect);
1914
1915 if (_outputFilePlayerPtr)
1916 {
1917 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1918 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1919 _outputFilePlayerPtr = NULL;
1920 }
1921
1922 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1923 _outputFilePlayerId, (const FileFormats)format);
1924
1925 if (_outputFilePlayerPtr == NULL)
1926 {
1927 _engineStatisticsPtr->SetLastError(
1928 VE_INVALID_ARGUMENT, kTraceError,
1929 "StartPlayingFileLocally() filePlayer format is not correct");
1930 return -1;
1931 }
1932
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00001933 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001934
1935 if (_outputFilePlayerPtr->StartPlayingFile(
1936 fileName,
1937 loop,
1938 startPosition,
1939 volumeScaling,
1940 notificationTime,
1941 stopPosition,
1942 (const CodecInst*)codecInst) != 0)
1943 {
1944 _engineStatisticsPtr->SetLastError(
1945 VE_BAD_FILE, kTraceError,
1946 "StartPlayingFile() failed to start file playout");
1947 _outputFilePlayerPtr->StopPlayingFile();
1948 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1949 _outputFilePlayerPtr = NULL;
1950 return -1;
1951 }
1952 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001953 channel_state_.SetOutputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001954 }
1955
1956 if (RegisterFilePlayingToMixer() != 0)
1957 return -1;
1958
1959 return 0;
1960}
1961
1962int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00001963 FileFormats format,
1964 int startPosition,
1965 float volumeScaling,
1966 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001967 const CodecInst* codecInst)
1968{
1969 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1970 "Channel::StartPlayingFileLocally(format=%d,"
1971 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1972 format, volumeScaling, startPosition, stopPosition);
1973
1974 if(stream == NULL)
1975 {
1976 _engineStatisticsPtr->SetLastError(
1977 VE_BAD_FILE, kTraceError,
1978 "StartPlayingFileLocally() NULL as input stream");
1979 return -1;
1980 }
1981
1982
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00001983 if (channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001984 {
1985 _engineStatisticsPtr->SetLastError(
1986 VE_ALREADY_PLAYING, kTraceError,
1987 "StartPlayingFileLocally() is already playing");
1988 return -1;
1989 }
1990
1991 {
1992 CriticalSectionScoped cs(&_fileCritSect);
1993
1994 // Destroy the old instance
1995 if (_outputFilePlayerPtr)
1996 {
1997 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1998 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1999 _outputFilePlayerPtr = NULL;
2000 }
2001
2002 // Create the instance
2003 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2004 _outputFilePlayerId,
2005 (const FileFormats)format);
2006
2007 if (_outputFilePlayerPtr == NULL)
2008 {
2009 _engineStatisticsPtr->SetLastError(
2010 VE_INVALID_ARGUMENT, kTraceError,
2011 "StartPlayingFileLocally() filePlayer format isnot correct");
2012 return -1;
2013 }
2014
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002015 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002016
2017 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2018 volumeScaling,
2019 notificationTime,
2020 stopPosition, codecInst) != 0)
2021 {
2022 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2023 "StartPlayingFile() failed to "
2024 "start file playout");
2025 _outputFilePlayerPtr->StopPlayingFile();
2026 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2027 _outputFilePlayerPtr = NULL;
2028 return -1;
2029 }
2030 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002031 channel_state_.SetOutputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002032 }
2033
2034 if (RegisterFilePlayingToMixer() != 0)
2035 return -1;
2036
2037 return 0;
2038}
2039
2040int Channel::StopPlayingFileLocally()
2041{
2042 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2043 "Channel::StopPlayingFileLocally()");
2044
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002045 if (!channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002046 {
2047 _engineStatisticsPtr->SetLastError(
2048 VE_INVALID_OPERATION, kTraceWarning,
2049 "StopPlayingFileLocally() isnot playing");
2050 return 0;
2051 }
2052
2053 {
2054 CriticalSectionScoped cs(&_fileCritSect);
2055
2056 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2057 {
2058 _engineStatisticsPtr->SetLastError(
2059 VE_STOP_RECORDING_FAILED, kTraceError,
2060 "StopPlayingFile() could not stop playing");
2061 return -1;
2062 }
2063 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2064 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2065 _outputFilePlayerPtr = NULL;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002066 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002067 }
2068 // _fileCritSect cannot be taken while calling
2069 // SetAnonymousMixibilityStatus. Refer to comments in
2070 // StartPlayingFileLocally(const char* ...) for more details.
2071 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2072 {
2073 _engineStatisticsPtr->SetLastError(
2074 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2075 "StopPlayingFile() failed to stop participant from playing as"
2076 "file in the mixer");
2077 return -1;
2078 }
2079
2080 return 0;
2081}
2082
2083int Channel::IsPlayingFileLocally() const
2084{
2085 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2086 "Channel::IsPlayingFileLocally()");
2087
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002088 return channel_state_.Get().output_file_playing;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002089}
2090
2091int Channel::RegisterFilePlayingToMixer()
2092{
2093 // Return success for not registering for file playing to mixer if:
2094 // 1. playing file before playout is started on that channel.
2095 // 2. starting playout without file playing on that channel.
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002096 if (!channel_state_.Get().playing ||
2097 !channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002098 {
2099 return 0;
2100 }
2101
2102 // |_fileCritSect| cannot be taken while calling
2103 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2104 // frames can be pulled by the mixer. Since the frames are generated from
2105 // the file, _fileCritSect will be taken. This would result in a deadlock.
2106 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2107 {
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002108 channel_state_.SetOutputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002109 CriticalSectionScoped cs(&_fileCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002110 _engineStatisticsPtr->SetLastError(
2111 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2112 "StartPlayingFile() failed to add participant as file to mixer");
2113 _outputFilePlayerPtr->StopPlayingFile();
2114 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2115 _outputFilePlayerPtr = NULL;
2116 return -1;
2117 }
2118
2119 return 0;
2120}
2121
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002122int Channel::ScaleLocalFilePlayout(float scale)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002123{
2124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2125 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2126
2127 CriticalSectionScoped cs(&_fileCritSect);
2128
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002129 if (!channel_state_.Get().output_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002130 {
2131 _engineStatisticsPtr->SetLastError(
2132 VE_INVALID_OPERATION, kTraceError,
2133 "ScaleLocalFilePlayout() isnot playing");
2134 return -1;
2135 }
2136 if ((_outputFilePlayerPtr == NULL) ||
2137 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2138 {
2139 _engineStatisticsPtr->SetLastError(
2140 VE_BAD_ARGUMENT, kTraceError,
2141 "SetAudioScaling() failed to scale the playout");
2142 return -1;
2143 }
2144
2145 return 0;
2146}
2147
2148int Channel::GetLocalPlayoutPosition(int& positionMs)
2149{
2150 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2151 "Channel::GetLocalPlayoutPosition(position=?)");
2152
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002153 uint32_t position;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002154
2155 CriticalSectionScoped cs(&_fileCritSect);
2156
2157 if (_outputFilePlayerPtr == NULL)
2158 {
2159 _engineStatisticsPtr->SetLastError(
2160 VE_INVALID_OPERATION, kTraceError,
2161 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2162 return -1;
2163 }
2164
2165 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2166 {
2167 _engineStatisticsPtr->SetLastError(
2168 VE_BAD_FILE, kTraceError,
2169 "GetLocalPlayoutPosition() failed");
2170 return -1;
2171 }
2172 positionMs = position;
2173
2174 return 0;
2175}
2176
2177int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002178 bool loop,
2179 FileFormats format,
2180 int startPosition,
2181 float volumeScaling,
2182 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002183 const CodecInst* codecInst)
2184{
2185 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2186 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2187 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2188 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2189 startPosition, stopPosition);
2190
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002191 CriticalSectionScoped cs(&_fileCritSect);
2192
2193 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002194 {
2195 _engineStatisticsPtr->SetLastError(
2196 VE_ALREADY_PLAYING, kTraceWarning,
2197 "StartPlayingFileAsMicrophone() filePlayer is playing");
2198 return 0;
2199 }
2200
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002201 // Destroy the old instance
2202 if (_inputFilePlayerPtr)
2203 {
2204 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2205 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2206 _inputFilePlayerPtr = NULL;
2207 }
2208
2209 // Create the instance
2210 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2211 _inputFilePlayerId, (const FileFormats)format);
2212
2213 if (_inputFilePlayerPtr == NULL)
2214 {
2215 _engineStatisticsPtr->SetLastError(
2216 VE_INVALID_ARGUMENT, kTraceError,
2217 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2218 return -1;
2219 }
2220
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002221 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002222
2223 if (_inputFilePlayerPtr->StartPlayingFile(
2224 fileName,
2225 loop,
2226 startPosition,
2227 volumeScaling,
2228 notificationTime,
2229 stopPosition,
2230 (const CodecInst*)codecInst) != 0)
2231 {
2232 _engineStatisticsPtr->SetLastError(
2233 VE_BAD_FILE, kTraceError,
2234 "StartPlayingFile() failed to start file playout");
2235 _inputFilePlayerPtr->StopPlayingFile();
2236 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2237 _inputFilePlayerPtr = NULL;
2238 return -1;
2239 }
2240 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002241 channel_state_.SetInputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002242
2243 return 0;
2244}
2245
2246int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002247 FileFormats format,
2248 int startPosition,
2249 float volumeScaling,
2250 int stopPosition,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002251 const CodecInst* codecInst)
2252{
2253 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2254 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2255 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2256 format, volumeScaling, startPosition, stopPosition);
2257
2258 if(stream == NULL)
2259 {
2260 _engineStatisticsPtr->SetLastError(
2261 VE_BAD_FILE, kTraceError,
2262 "StartPlayingFileAsMicrophone NULL as input stream");
2263 return -1;
2264 }
2265
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002266 CriticalSectionScoped cs(&_fileCritSect);
2267
2268 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002269 {
2270 _engineStatisticsPtr->SetLastError(
2271 VE_ALREADY_PLAYING, kTraceWarning,
2272 "StartPlayingFileAsMicrophone() is playing");
2273 return 0;
2274 }
2275
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002276 // Destroy the old instance
2277 if (_inputFilePlayerPtr)
2278 {
2279 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2280 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2281 _inputFilePlayerPtr = NULL;
2282 }
2283
2284 // Create the instance
2285 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2286 _inputFilePlayerId, (const FileFormats)format);
2287
2288 if (_inputFilePlayerPtr == NULL)
2289 {
2290 _engineStatisticsPtr->SetLastError(
2291 VE_INVALID_ARGUMENT, kTraceError,
2292 "StartPlayingInputFile() filePlayer format isnot correct");
2293 return -1;
2294 }
2295
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002296 const uint32_t notificationTime(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002297
2298 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2299 volumeScaling, notificationTime,
2300 stopPosition, codecInst) != 0)
2301 {
2302 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2303 "StartPlayingFile() failed to start "
2304 "file playout");
2305 _inputFilePlayerPtr->StopPlayingFile();
2306 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2307 _inputFilePlayerPtr = NULL;
2308 return -1;
2309 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00002310
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002311 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002312 channel_state_.SetInputFilePlaying(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002313
2314 return 0;
2315}
2316
2317int Channel::StopPlayingFileAsMicrophone()
2318{
2319 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2320 "Channel::StopPlayingFileAsMicrophone()");
2321
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002322 CriticalSectionScoped cs(&_fileCritSect);
2323
2324 if (!channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002325 {
2326 _engineStatisticsPtr->SetLastError(
2327 VE_INVALID_OPERATION, kTraceWarning,
2328 "StopPlayingFileAsMicrophone() isnot playing");
2329 return 0;
2330 }
2331
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002332 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2333 {
2334 _engineStatisticsPtr->SetLastError(
2335 VE_STOP_RECORDING_FAILED, kTraceError,
2336 "StopPlayingFile() could not stop playing");
2337 return -1;
2338 }
2339 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2340 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2341 _inputFilePlayerPtr = NULL;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002342 channel_state_.SetInputFilePlaying(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002343
2344 return 0;
2345}
2346
2347int Channel::IsPlayingFileAsMicrophone() const
2348{
2349 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2350 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002351 return channel_state_.Get().input_file_playing;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002352}
2353
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002354int Channel::ScaleFileAsMicrophonePlayout(float scale)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002355{
2356 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2357 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2358
2359 CriticalSectionScoped cs(&_fileCritSect);
2360
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002361 if (!channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002362 {
2363 _engineStatisticsPtr->SetLastError(
2364 VE_INVALID_OPERATION, kTraceError,
2365 "ScaleFileAsMicrophonePlayout() isnot playing");
2366 return -1;
2367 }
2368
2369 if ((_inputFilePlayerPtr == NULL) ||
2370 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2371 {
2372 _engineStatisticsPtr->SetLastError(
2373 VE_BAD_ARGUMENT, kTraceError,
2374 "SetAudioScaling() failed to scale playout");
2375 return -1;
2376 }
2377
2378 return 0;
2379}
2380
2381int Channel::StartRecordingPlayout(const char* fileName,
2382 const CodecInst* codecInst)
2383{
2384 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2385 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2386
2387 if (_outputFileRecording)
2388 {
2389 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2390 "StartRecordingPlayout() is already recording");
2391 return 0;
2392 }
2393
2394 FileFormats format;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002395 const uint32_t notificationTime(0); // Not supported in VoE
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002396 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2397
2398 if ((codecInst != NULL) &&
2399 ((codecInst->channels < 1) || (codecInst->channels > 2)))
2400 {
2401 _engineStatisticsPtr->SetLastError(
2402 VE_BAD_ARGUMENT, kTraceError,
2403 "StartRecordingPlayout() invalid compression");
2404 return(-1);
2405 }
2406 if(codecInst == NULL)
2407 {
2408 format = kFileFormatPcm16kHzFile;
2409 codecInst=&dummyCodec;
2410 }
2411 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2412 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2413 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2414 {
2415 format = kFileFormatWavFile;
2416 }
2417 else
2418 {
2419 format = kFileFormatCompressedFile;
2420 }
2421
2422 CriticalSectionScoped cs(&_fileCritSect);
2423
2424 // Destroy the old instance
2425 if (_outputFileRecorderPtr)
2426 {
2427 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2428 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2429 _outputFileRecorderPtr = NULL;
2430 }
2431
2432 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2433 _outputFileRecorderId, (const FileFormats)format);
2434 if (_outputFileRecorderPtr == NULL)
2435 {
2436 _engineStatisticsPtr->SetLastError(
2437 VE_INVALID_ARGUMENT, kTraceError,
2438 "StartRecordingPlayout() fileRecorder format isnot correct");
2439 return -1;
2440 }
2441
2442 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2443 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2444 {
2445 _engineStatisticsPtr->SetLastError(
2446 VE_BAD_FILE, kTraceError,
2447 "StartRecordingAudioFile() failed to start file recording");
2448 _outputFileRecorderPtr->StopRecording();
2449 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2450 _outputFileRecorderPtr = NULL;
2451 return -1;
2452 }
2453 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2454 _outputFileRecording = true;
2455
2456 return 0;
2457}
2458
2459int Channel::StartRecordingPlayout(OutStream* stream,
2460 const CodecInst* codecInst)
2461{
2462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2463 "Channel::StartRecordingPlayout()");
2464
2465 if (_outputFileRecording)
2466 {
2467 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2468 "StartRecordingPlayout() is already recording");
2469 return 0;
2470 }
2471
2472 FileFormats format;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002473 const uint32_t notificationTime(0); // Not supported in VoE
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002474 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2475
2476 if (codecInst != NULL && codecInst->channels != 1)
2477 {
2478 _engineStatisticsPtr->SetLastError(
2479 VE_BAD_ARGUMENT, kTraceError,
2480 "StartRecordingPlayout() invalid compression");
2481 return(-1);
2482 }
2483 if(codecInst == NULL)
2484 {
2485 format = kFileFormatPcm16kHzFile;
2486 codecInst=&dummyCodec;
2487 }
2488 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2489 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2490 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2491 {
2492 format = kFileFormatWavFile;
2493 }
2494 else
2495 {
2496 format = kFileFormatCompressedFile;
2497 }
2498
2499 CriticalSectionScoped cs(&_fileCritSect);
2500
2501 // Destroy the old instance
2502 if (_outputFileRecorderPtr)
2503 {
2504 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2505 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2506 _outputFileRecorderPtr = NULL;
2507 }
2508
2509 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2510 _outputFileRecorderId, (const FileFormats)format);
2511 if (_outputFileRecorderPtr == NULL)
2512 {
2513 _engineStatisticsPtr->SetLastError(
2514 VE_INVALID_ARGUMENT, kTraceError,
2515 "StartRecordingPlayout() fileRecorder format isnot correct");
2516 return -1;
2517 }
2518
2519 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2520 notificationTime) != 0)
2521 {
2522 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2523 "StartRecordingPlayout() failed to "
2524 "start file recording");
2525 _outputFileRecorderPtr->StopRecording();
2526 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2527 _outputFileRecorderPtr = NULL;
2528 return -1;
2529 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00002530
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002531 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2532 _outputFileRecording = true;
2533
2534 return 0;
2535}
2536
2537int Channel::StopRecordingPlayout()
2538{
2539 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2540 "Channel::StopRecordingPlayout()");
2541
2542 if (!_outputFileRecording)
2543 {
2544 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2545 "StopRecordingPlayout() isnot recording");
2546 return -1;
2547 }
2548
2549
2550 CriticalSectionScoped cs(&_fileCritSect);
2551
2552 if (_outputFileRecorderPtr->StopRecording() != 0)
2553 {
2554 _engineStatisticsPtr->SetLastError(
2555 VE_STOP_RECORDING_FAILED, kTraceError,
2556 "StopRecording() could not stop recording");
2557 return(-1);
2558 }
2559 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2560 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2561 _outputFileRecorderPtr = NULL;
2562 _outputFileRecording = false;
2563
2564 return 0;
2565}
2566
2567void
2568Channel::SetMixWithMicStatus(bool mix)
2569{
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002570 CriticalSectionScoped cs(&_fileCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002571 _mixFileWithMicrophone=mix;
2572}
2573
2574int
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002575Channel::GetSpeechOutputLevel(uint32_t& level) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002576{
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002577 int8_t currentLevel = _outputAudioLevel.Level();
2578 level = static_cast<int32_t> (currentLevel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002579 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2580 VoEId(_instanceId,_channelId),
2581 "GetSpeechOutputLevel() => level=%u", level);
2582 return 0;
2583}
2584
2585int
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002586Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002587{
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00002588 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2589 level = static_cast<int32_t> (currentLevel);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002590 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2591 VoEId(_instanceId,_channelId),
2592 "GetSpeechOutputLevelFullRange() => level=%u", level);
2593 return 0;
2594}
2595
2596int
2597Channel::SetMute(bool enable)
2598{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002599 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002600 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2601 "Channel::SetMute(enable=%d)", enable);
2602 _mute = enable;
2603 return 0;
2604}
2605
2606bool
2607Channel::Mute() const
2608{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002609 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002610 return _mute;
2611}
2612
2613int
2614Channel::SetOutputVolumePan(float left, float right)
2615{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002616 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002617 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2618 "Channel::SetOutputVolumePan()");
2619 _panLeft = left;
2620 _panRight = right;
2621 return 0;
2622}
2623
2624int
2625Channel::GetOutputVolumePan(float& left, float& right) const
2626{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002627 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002628 left = _panLeft;
2629 right = _panRight;
2630 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2631 VoEId(_instanceId,_channelId),
2632 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2633 return 0;
2634}
2635
2636int
2637Channel::SetChannelOutputVolumeScaling(float scaling)
2638{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002639 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002640 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2641 "Channel::SetChannelOutputVolumeScaling()");
2642 _outputGain = scaling;
2643 return 0;
2644}
2645
2646int
2647Channel::GetChannelOutputVolumeScaling(float& scaling) const
2648{
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00002649 CriticalSectionScoped cs(&volume_settings_critsect_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002650 scaling = _outputGain;
2651 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2652 VoEId(_instanceId,_channelId),
2653 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2654 return 0;
2655}
2656
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002657int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00002658 int lengthMs, int attenuationDb,
2659 bool playDtmfEvent)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002660{
2661 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2662 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2663 playDtmfEvent);
2664
2665 _playOutbandDtmfEvent = playDtmfEvent;
2666
2667 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
2668 attenuationDb) != 0)
2669 {
2670 _engineStatisticsPtr->SetLastError(
2671 VE_SEND_DTMF_FAILED,
2672 kTraceWarning,
2673 "SendTelephoneEventOutband() failed to send event");
2674 return -1;
2675 }
2676 return 0;
2677}
2678
2679int Channel::SendTelephoneEventInband(unsigned char eventCode,
2680 int lengthMs,
2681 int attenuationDb,
2682 bool playDtmfEvent)
2683{
2684 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2685 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2686 playDtmfEvent);
2687
2688 _playInbandDtmfEvent = playDtmfEvent;
2689 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2690
2691 return 0;
2692}
2693
2694int
2695Channel::SetDtmfPlayoutStatus(bool enable)
2696{
2697 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2698 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00002699 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002700 {
2701 _engineStatisticsPtr->SetLastError(
2702 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2703 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2704 return -1;
2705 }
2706 return 0;
2707}
2708
2709bool
2710Channel::DtmfPlayoutStatus() const
2711{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00002712 return audio_coding_->DtmfPlayoutStatus();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002713}
2714
2715int
2716Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2717{
2718 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2719 "Channel::SetSendTelephoneEventPayloadType()");
2720 if (type > 127)
2721 {
2722 _engineStatisticsPtr->SetLastError(
2723 VE_INVALID_ARGUMENT, kTraceError,
2724 "SetSendTelephoneEventPayloadType() invalid type");
2725 return -1;
2726 }
pbos@webrtc.org6a4acb92013-07-11 15:50:07 +00002727 CodecInst codec = {};
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002728 codec.plfreq = 8000;
2729 codec.pltype = type;
2730 memcpy(codec.plname, "telephone-event", 16);
2731 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
2732 {
henrika@webrtc.org570c4a52013-04-17 07:34:25 +00002733 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2734 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2735 _engineStatisticsPtr->SetLastError(
2736 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2737 "SetSendTelephoneEventPayloadType() failed to register send"
2738 "payload type");
2739 return -1;
2740 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002741 }
2742 _sendTelephoneEventPayloadType = type;
2743 return 0;
2744}
2745
2746int
2747Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2748{
2749 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2750 "Channel::GetSendTelephoneEventPayloadType()");
2751 type = _sendTelephoneEventPayloadType;
2752 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2753 VoEId(_instanceId,_channelId),
2754 "GetSendTelephoneEventPayloadType() => type=%u", type);
2755 return 0;
2756}
2757
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002758int
2759Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2760{
2761 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2762 "Channel::UpdateRxVadDetection()");
2763
2764 int vadDecision = 1;
2765
2766 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
2767
2768 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2769 {
2770 OnRxVadDetected(vadDecision);
2771 _oldVadDecision = vadDecision;
2772 }
2773
2774 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2775 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2776 vadDecision);
2777 return 0;
2778}
2779
2780int
2781Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2782{
2783 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2784 "Channel::RegisterRxVadObserver()");
2785 CriticalSectionScoped cs(&_callbackCritSect);
2786
2787 if (_rxVadObserverPtr)
2788 {
2789 _engineStatisticsPtr->SetLastError(
2790 VE_INVALID_OPERATION, kTraceError,
2791 "RegisterRxVadObserver() observer already enabled");
2792 return -1;
2793 }
2794 _rxVadObserverPtr = &observer;
2795 _RxVadDetection = true;
2796 return 0;
2797}
2798
2799int
2800Channel::DeRegisterRxVadObserver()
2801{
2802 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2803 "Channel::DeRegisterRxVadObserver()");
2804 CriticalSectionScoped cs(&_callbackCritSect);
2805
2806 if (!_rxVadObserverPtr)
2807 {
2808 _engineStatisticsPtr->SetLastError(
2809 VE_INVALID_OPERATION, kTraceWarning,
2810 "DeRegisterRxVadObserver() observer already disabled");
2811 return 0;
2812 }
2813 _rxVadObserverPtr = NULL;
2814 _RxVadDetection = false;
2815 return 0;
2816}
2817
2818int
2819Channel::VoiceActivityIndicator(int &activity)
2820{
2821 activity = _sendFrameType;
2822
2823 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002824 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002825 return 0;
2826}
2827
2828#ifdef WEBRTC_VOICE_ENGINE_AGC
2829
2830int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002831Channel::SetRxAgcStatus(bool enable, AgcModes mode)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002832{
2833 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2834 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2835 (int)enable, (int)mode);
2836
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002837 GainControl::Mode agcMode = kDefaultRxAgcMode;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002838 switch (mode)
2839 {
2840 case kAgcDefault:
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002841 break;
2842 case kAgcUnchanged:
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002843 agcMode = rx_audioproc_->gain_control()->mode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002844 break;
2845 case kAgcFixedDigital:
2846 agcMode = GainControl::kFixedDigital;
2847 break;
2848 case kAgcAdaptiveDigital:
2849 agcMode =GainControl::kAdaptiveDigital;
2850 break;
2851 default:
2852 _engineStatisticsPtr->SetLastError(
2853 VE_INVALID_ARGUMENT, kTraceError,
2854 "SetRxAgcStatus() invalid Agc mode");
2855 return -1;
2856 }
2857
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002858 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002859 {
2860 _engineStatisticsPtr->SetLastError(
2861 VE_APM_ERROR, kTraceError,
2862 "SetRxAgcStatus() failed to set Agc mode");
2863 return -1;
2864 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002865 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002866 {
2867 _engineStatisticsPtr->SetLastError(
2868 VE_APM_ERROR, kTraceError,
2869 "SetRxAgcStatus() failed to set Agc state");
2870 return -1;
2871 }
2872
2873 _rxAgcIsEnabled = enable;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00002874 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002875
2876 return 0;
2877}
2878
2879int
2880Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2881{
2882 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2883 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2884
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002885 bool enable = rx_audioproc_->gain_control()->is_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002886 GainControl::Mode agcMode =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002887 rx_audioproc_->gain_control()->mode();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002888
2889 enabled = enable;
2890
2891 switch (agcMode)
2892 {
2893 case GainControl::kFixedDigital:
2894 mode = kAgcFixedDigital;
2895 break;
2896 case GainControl::kAdaptiveDigital:
2897 mode = kAgcAdaptiveDigital;
2898 break;
2899 default:
2900 _engineStatisticsPtr->SetLastError(
2901 VE_APM_ERROR, kTraceError,
2902 "GetRxAgcStatus() invalid Agc mode");
2903 return -1;
2904 }
2905
2906 return 0;
2907}
2908
2909int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002910Channel::SetRxAgcConfig(AgcConfig config)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002911{
2912 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2913 "Channel::SetRxAgcConfig()");
2914
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002915 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002916 config.targetLeveldBOv) != 0)
2917 {
2918 _engineStatisticsPtr->SetLastError(
2919 VE_APM_ERROR, kTraceError,
2920 "SetRxAgcConfig() failed to set target peak |level|"
2921 "(or envelope) of the Agc");
2922 return -1;
2923 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002924 if (rx_audioproc_->gain_control()->set_compression_gain_db(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002925 config.digitalCompressionGaindB) != 0)
2926 {
2927 _engineStatisticsPtr->SetLastError(
2928 VE_APM_ERROR, kTraceError,
2929 "SetRxAgcConfig() failed to set the range in |gain| the"
2930 " digital compression stage may apply");
2931 return -1;
2932 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002933 if (rx_audioproc_->gain_control()->enable_limiter(
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002934 config.limiterEnable) != 0)
2935 {
2936 _engineStatisticsPtr->SetLastError(
2937 VE_APM_ERROR, kTraceError,
2938 "SetRxAgcConfig() failed to set hard limiter to the signal");
2939 return -1;
2940 }
2941
2942 return 0;
2943}
2944
2945int
2946Channel::GetRxAgcConfig(AgcConfig& config)
2947{
2948 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2949 "Channel::GetRxAgcConfig(config=%?)");
2950
2951 config.targetLeveldBOv =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002952 rx_audioproc_->gain_control()->target_level_dbfs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002953 config.digitalCompressionGaindB =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002954 rx_audioproc_->gain_control()->compression_gain_db();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002955 config.limiterEnable =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002956 rx_audioproc_->gain_control()->is_limiter_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002957
2958 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2959 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2960 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2961 " limiterEnable=%d",
2962 config.targetLeveldBOv,
2963 config.digitalCompressionGaindB,
2964 config.limiterEnable);
2965
2966 return 0;
2967}
2968
2969#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2970
2971#ifdef WEBRTC_VOICE_ENGINE_NR
2972
2973int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00002974Channel::SetRxNsStatus(bool enable, NsModes mode)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002975{
2976 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2977 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2978 (int)enable, (int)mode);
2979
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00002980 NoiseSuppression::Level nsLevel = kDefaultNsMode;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002981 switch (mode)
2982 {
2983
2984 case kNsDefault:
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002985 break;
2986 case kNsUnchanged:
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00002987 nsLevel = rx_audioproc_->noise_suppression()->level();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002988 break;
2989 case kNsConference:
2990 nsLevel = NoiseSuppression::kHigh;
2991 break;
2992 case kNsLowSuppression:
2993 nsLevel = NoiseSuppression::kLow;
2994 break;
2995 case kNsModerateSuppression:
2996 nsLevel = NoiseSuppression::kModerate;
2997 break;
2998 case kNsHighSuppression:
2999 nsLevel = NoiseSuppression::kHigh;
3000 break;
3001 case kNsVeryHighSuppression:
3002 nsLevel = NoiseSuppression::kVeryHigh;
3003 break;
3004 }
3005
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003006 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003007 != 0)
3008 {
3009 _engineStatisticsPtr->SetLastError(
3010 VE_APM_ERROR, kTraceError,
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00003011 "SetRxNsStatus() failed to set NS level");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003012 return -1;
3013 }
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003014 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003015 {
3016 _engineStatisticsPtr->SetLastError(
3017 VE_APM_ERROR, kTraceError,
andrew@webrtc.orge06943f2013-10-04 17:54:09 +00003018 "SetRxNsStatus() failed to set NS state");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003019 return -1;
3020 }
3021
3022 _rxNsIsEnabled = enable;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003023 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003024
3025 return 0;
3026}
3027
3028int
3029Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3030{
3031 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3032 "Channel::GetRxNsStatus(enable=?, mode=?)");
3033
3034 bool enable =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003035 rx_audioproc_->noise_suppression()->is_enabled();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003036 NoiseSuppression::Level ncLevel =
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003037 rx_audioproc_->noise_suppression()->level();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003038
3039 enabled = enable;
3040
3041 switch (ncLevel)
3042 {
3043 case NoiseSuppression::kLow:
3044 mode = kNsLowSuppression;
3045 break;
3046 case NoiseSuppression::kModerate:
3047 mode = kNsModerateSuppression;
3048 break;
3049 case NoiseSuppression::kHigh:
3050 mode = kNsHighSuppression;
3051 break;
3052 case NoiseSuppression::kVeryHigh:
3053 mode = kNsVeryHighSuppression;
3054 break;
3055 }
3056
3057 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3058 VoEId(_instanceId,_channelId),
3059 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3060 return 0;
3061}
3062
3063#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3064
3065int
3066Channel::RegisterRTPObserver(VoERTPObserver& observer)
3067{
3068 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3069 "Channel::RegisterRTPObserver()");
3070 CriticalSectionScoped cs(&_callbackCritSect);
3071
3072 if (_rtpObserverPtr)
3073 {
3074 _engineStatisticsPtr->SetLastError(
3075 VE_INVALID_OPERATION, kTraceError,
3076 "RegisterRTPObserver() observer already enabled");
3077 return -1;
3078 }
3079
3080 _rtpObserverPtr = &observer;
3081 _rtpObserver = true;
3082
3083 return 0;
3084}
3085
3086int
3087Channel::DeRegisterRTPObserver()
3088{
3089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3090 "Channel::DeRegisterRTPObserver()");
3091 CriticalSectionScoped cs(&_callbackCritSect);
3092
3093 if (!_rtpObserverPtr)
3094 {
3095 _engineStatisticsPtr->SetLastError(
3096 VE_INVALID_OPERATION, kTraceWarning,
3097 "DeRegisterRTPObserver() observer already disabled");
3098 return 0;
3099 }
3100
3101 _rtpObserver = false;
3102 _rtpObserverPtr = NULL;
3103
3104 return 0;
3105}
3106
3107int
3108Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3109{
3110 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3111 "Channel::RegisterRTCPObserver()");
3112 CriticalSectionScoped cs(&_callbackCritSect);
3113
3114 if (_rtcpObserverPtr)
3115 {
3116 _engineStatisticsPtr->SetLastError(
3117 VE_INVALID_OPERATION, kTraceError,
3118 "RegisterRTCPObserver() observer already enabled");
3119 return -1;
3120 }
3121
3122 _rtcpObserverPtr = &observer;
3123 _rtcpObserver = true;
3124
3125 return 0;
3126}
3127
3128int
3129Channel::DeRegisterRTCPObserver()
3130{
3131 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3132 "Channel::DeRegisterRTCPObserver()");
3133 CriticalSectionScoped cs(&_callbackCritSect);
3134
3135 if (!_rtcpObserverPtr)
3136 {
3137 _engineStatisticsPtr->SetLastError(
3138 VE_INVALID_OPERATION, kTraceWarning,
3139 "DeRegisterRTCPObserver() observer already disabled");
3140 return 0;
3141 }
3142
3143 _rtcpObserver = false;
3144 _rtcpObserverPtr = NULL;
3145
3146 return 0;
3147}
3148
3149int
3150Channel::SetLocalSSRC(unsigned int ssrc)
3151{
3152 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3153 "Channel::SetLocalSSRC()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003154 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003155 {
3156 _engineStatisticsPtr->SetLastError(
3157 VE_ALREADY_SENDING, kTraceError,
3158 "SetLocalSSRC() already sending");
3159 return -1;
3160 }
3161 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
3162 {
3163 _engineStatisticsPtr->SetLastError(
3164 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3165 "SetLocalSSRC() failed to set SSRC");
3166 return -1;
3167 }
3168 return 0;
3169}
3170
3171int
3172Channel::GetLocalSSRC(unsigned int& ssrc)
3173{
3174 ssrc = _rtpRtcpModule->SSRC();
3175 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3176 VoEId(_instanceId,_channelId),
3177 "GetLocalSSRC() => ssrc=%lu", ssrc);
3178 return 0;
3179}
3180
3181int
3182Channel::GetRemoteSSRC(unsigned int& ssrc)
3183{
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003184 ssrc = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003185 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3186 VoEId(_instanceId,_channelId),
3187 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3188 return 0;
3189}
3190
3191int
3192Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3193{
3194 if (arrCSRC == NULL)
3195 {
3196 _engineStatisticsPtr->SetLastError(
3197 VE_INVALID_ARGUMENT, kTraceError,
3198 "GetRemoteCSRCs() invalid array argument");
3199 return -1;
3200 }
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003201 uint32_t arrOfCSRC[kRtpCsrcSize];
3202 int32_t CSRCs(0);
braveyao@webrtc.org3f7753c2014-03-11 16:19:56 +00003203 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003204 if (CSRCs > 0)
3205 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003206 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003207 for (int i = 0; i < (int) CSRCs; i++)
3208 {
3209 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3210 VoEId(_instanceId, _channelId),
3211 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3212 }
3213 } else
3214 {
3215 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3216 VoEId(_instanceId, _channelId),
3217 "GetRemoteCSRCs() => list is empty!");
3218 }
3219 return CSRCs;
3220}
3221
wu@webrtc.org9a823222014-03-06 23:49:08 +00003222int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003223 if (rtp_audioproc_.get() == NULL) {
3224 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3225 _channelId)));
3226 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003227
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003228 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3229 AudioProcessing::kNoError) {
3230 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3231 "Failed to enable AudioProcessing::level_estimator()");
3232 return -1;
3233 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003234
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003235 _includeAudioLevelIndication = enable;
wu@webrtc.org9a823222014-03-06 23:49:08 +00003236
3237 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003238}
andrew@webrtc.org80142aa2013-09-18 22:37:32 +00003239
wu@webrtc.org9a823222014-03-06 23:49:08 +00003240int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3241 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3242}
3243
3244int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3245 rtp_header_parser_->DeregisterRtpHeaderExtension(
3246 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00003247 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3248 kRtpExtensionAbsoluteSendTime, id)) {
3249 return -1;
wu@webrtc.org9a823222014-03-06 23:49:08 +00003250 }
3251 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003252}
3253
3254int
3255Channel::SetRTCPStatus(bool enable)
3256{
3257 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3258 "Channel::SetRTCPStatus()");
3259 if (_rtpRtcpModule->SetRTCPStatus(enable ?
3260 kRtcpCompound : kRtcpOff) != 0)
3261 {
3262 _engineStatisticsPtr->SetLastError(
3263 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3264 "SetRTCPStatus() failed to set RTCP status");
3265 return -1;
3266 }
3267 return 0;
3268}
3269
3270int
3271Channel::GetRTCPStatus(bool& enabled)
3272{
3273 RTCPMethod method = _rtpRtcpModule->RTCP();
3274 enabled = (method != kRtcpOff);
3275 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3276 VoEId(_instanceId,_channelId),
3277 "GetRTCPStatus() => enabled=%d", enabled);
3278 return 0;
3279}
3280
3281int
3282Channel::SetRTCP_CNAME(const char cName[256])
3283{
3284 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3285 "Channel::SetRTCP_CNAME()");
3286 if (_rtpRtcpModule->SetCNAME(cName) != 0)
3287 {
3288 _engineStatisticsPtr->SetLastError(
3289 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3290 "SetRTCP_CNAME() failed to set RTCP CNAME");
3291 return -1;
3292 }
3293 return 0;
3294}
3295
3296int
3297Channel::GetRTCP_CNAME(char cName[256])
3298{
3299 if (_rtpRtcpModule->CNAME(cName) != 0)
3300 {
3301 _engineStatisticsPtr->SetLastError(
3302 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3303 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3304 return -1;
3305 }
3306 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3307 VoEId(_instanceId, _channelId),
3308 "GetRTCP_CNAME() => cName=%s", cName);
3309 return 0;
3310}
3311
3312int
3313Channel::GetRemoteRTCP_CNAME(char cName[256])
3314{
3315 if (cName == NULL)
3316 {
3317 _engineStatisticsPtr->SetLastError(
3318 VE_INVALID_ARGUMENT, kTraceError,
3319 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3320 return -1;
3321 }
3322 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003323 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003324 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
3325 {
3326 _engineStatisticsPtr->SetLastError(
3327 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3328 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3329 return -1;
3330 }
3331 strcpy(cName, cname);
3332 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3333 VoEId(_instanceId, _channelId),
3334 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3335 return 0;
3336}
3337
3338int
3339Channel::GetRemoteRTCPData(
3340 unsigned int& NTPHigh,
3341 unsigned int& NTPLow,
3342 unsigned int& timestamp,
3343 unsigned int& playoutTimestamp,
3344 unsigned int* jitter,
3345 unsigned short* fractionLost)
3346{
3347 // --- Information from sender info in received Sender Reports
3348
3349 RTCPSenderInfo senderInfo;
3350 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
3351 {
3352 _engineStatisticsPtr->SetLastError(
3353 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3354 "GetRemoteRTCPData() failed to retrieve sender info for remote "
3355 "side");
3356 return -1;
3357 }
3358
3359 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3360 // and octet count)
3361 NTPHigh = senderInfo.NTPseconds;
3362 NTPLow = senderInfo.NTPfraction;
3363 timestamp = senderInfo.RTPtimeStamp;
3364
3365 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3366 VoEId(_instanceId, _channelId),
3367 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3368 "timestamp=%lu",
3369 NTPHigh, NTPLow, timestamp);
3370
3371 // --- Locally derived information
3372
3373 // This value is updated on each incoming RTCP packet (0 when no packet
3374 // has been received)
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003375 playoutTimestamp = playout_timestamp_rtcp_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003376
3377 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3378 VoEId(_instanceId, _channelId),
3379 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00003380 playout_timestamp_rtcp_);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003381
3382 if (NULL != jitter || NULL != fractionLost)
3383 {
3384 // Get all RTCP receiver report blocks that have been received on this
3385 // channel. If we receive RTP packets from a remote source we know the
3386 // remote SSRC and use the report block from him.
3387 // Otherwise use the first report block.
3388 std::vector<RTCPReportBlock> remote_stats;
3389 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
3390 remote_stats.empty()) {
3391 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3392 VoEId(_instanceId, _channelId),
3393 "GetRemoteRTCPData() failed to measure statistics due"
3394 " to lack of received RTP and/or RTCP packets");
3395 return -1;
3396 }
3397
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003398 uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003399 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3400 for (; it != remote_stats.end(); ++it) {
3401 if (it->remoteSSRC == remoteSSRC)
3402 break;
3403 }
3404
3405 if (it == remote_stats.end()) {
3406 // If we have not received any RTCP packets from this SSRC it probably
3407 // means that we have not received any RTP packets.
3408 // Use the first received report block instead.
3409 it = remote_stats.begin();
3410 remoteSSRC = it->remoteSSRC;
3411 }
3412
3413 if (jitter) {
3414 *jitter = it->jitter;
3415 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3416 VoEId(_instanceId, _channelId),
3417 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3418 }
3419
3420 if (fractionLost) {
3421 *fractionLost = it->fractionLost;
3422 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3423 VoEId(_instanceId, _channelId),
3424 "GetRemoteRTCPData() => fractionLost = %lu",
3425 *fractionLost);
3426 }
3427 }
3428 return 0;
3429}
3430
3431int
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00003432Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003433 unsigned int name,
3434 const char* data,
3435 unsigned short dataLengthInBytes)
3436{
3437 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3438 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003439 if (!channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003440 {
3441 _engineStatisticsPtr->SetLastError(
3442 VE_NOT_SENDING, kTraceError,
3443 "SendApplicationDefinedRTCPPacket() not sending");
3444 return -1;
3445 }
3446 if (NULL == data)
3447 {
3448 _engineStatisticsPtr->SetLastError(
3449 VE_INVALID_ARGUMENT, kTraceError,
3450 "SendApplicationDefinedRTCPPacket() invalid data value");
3451 return -1;
3452 }
3453 if (dataLengthInBytes % 4 != 0)
3454 {
3455 _engineStatisticsPtr->SetLastError(
3456 VE_INVALID_ARGUMENT, kTraceError,
3457 "SendApplicationDefinedRTCPPacket() invalid length value");
3458 return -1;
3459 }
3460 RTCPMethod status = _rtpRtcpModule->RTCP();
3461 if (status == kRtcpOff)
3462 {
3463 _engineStatisticsPtr->SetLastError(
3464 VE_RTCP_ERROR, kTraceError,
3465 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3466 return -1;
3467 }
3468
3469 // Create and schedule the RTCP APP packet for transmission
3470 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
3471 subType,
3472 name,
3473 (const unsigned char*) data,
3474 dataLengthInBytes) != 0)
3475 {
3476 _engineStatisticsPtr->SetLastError(
3477 VE_SEND_ERROR, kTraceError,
3478 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3479 return -1;
3480 }
3481 return 0;
3482}
3483
3484int
3485Channel::GetRTPStatistics(
3486 unsigned int& averageJitterMs,
3487 unsigned int& maxJitterMs,
3488 unsigned int& discardedPackets)
3489{
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003490 // The jitter statistics is updated for each received RTP packet and is
3491 // based on received packets.
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003492 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3493 // If RTCP is off, there is no timed thread in the RTCP module regularly
3494 // generating new stats, trigger the update manually here instead.
3495 StreamStatistician* statistician =
3496 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3497 if (statistician) {
3498 // Don't use returned statistics, use data from proxy instead so that
3499 // max jitter can be fetched atomically.
3500 RtcpStatistics s;
3501 statistician->GetStatistics(&s, true);
3502 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003503 }
3504
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003505 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003506 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003507 if (playoutFrequency > 0) {
3508 // Scale RTP statistics given the current playout frequency
3509 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3510 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003511 }
3512
3513 discardedPackets = _numberOfDiscardedPackets;
3514
3515 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3516 VoEId(_instanceId, _channelId),
3517 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
3518 " discardedPackets = %lu)",
3519 averageJitterMs, maxJitterMs, discardedPackets);
3520 return 0;
3521}
3522
3523int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3524 if (sender_info == NULL) {
3525 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3526 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3527 return -1;
3528 }
3529
3530 // Get the sender info from the latest received RTCP Sender Report.
3531 RTCPSenderInfo rtcp_sender_info;
3532 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3533 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3534 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3535 return -1;
3536 }
3537
3538 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3539 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3540 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3541 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3542 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3543 return 0;
3544}
3545
3546int Channel::GetRemoteRTCPReportBlocks(
3547 std::vector<ReportBlock>* report_blocks) {
3548 if (report_blocks == NULL) {
3549 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3550 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3551 return -1;
3552 }
3553
3554 // Get the report blocks from the latest received RTCP Sender or Receiver
3555 // Report. Each element in the vector contains the sender's SSRC and a
3556 // report block according to RFC 3550.
3557 std::vector<RTCPReportBlock> rtcp_report_blocks;
3558 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3559 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3560 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3561 return -1;
3562 }
3563
3564 if (rtcp_report_blocks.empty())
3565 return 0;
3566
3567 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3568 for (; it != rtcp_report_blocks.end(); ++it) {
3569 ReportBlock report_block;
3570 report_block.sender_SSRC = it->remoteSSRC;
3571 report_block.source_SSRC = it->sourceSSRC;
3572 report_block.fraction_lost = it->fractionLost;
3573 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3574 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3575 report_block.interarrival_jitter = it->jitter;
3576 report_block.last_SR_timestamp = it->lastSR;
3577 report_block.delay_since_last_SR = it->delaySinceLastSR;
3578 report_blocks->push_back(report_block);
3579 }
3580 return 0;
3581}
3582
3583int
3584Channel::GetRTPStatistics(CallStatistics& stats)
3585{
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003586 // --- Part one of the final structure (four values)
3587
3588 // The jitter statistics is updated for each received RTP packet and is
3589 // based on received packets.
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00003590 RtcpStatistics statistics;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00003591 StreamStatistician* statistician =
3592 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3593 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003594 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3595 _engineStatisticsPtr->SetLastError(
3596 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3597 "GetRTPStatistics() failed to read RTP statistics from the "
3598 "RTP/RTCP module");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003599 }
3600
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003601 stats.fractionLost = statistics.fraction_lost;
3602 stats.cumulativeLost = statistics.cumulative_lost;
3603 stats.extendedMax = statistics.extended_max_sequence_number;
3604 stats.jitterSamples = statistics.jitter;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003605
3606 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3607 VoEId(_instanceId, _channelId),
3608 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
3609 " extendedMax=%lu, jitterSamples=%li)",
3610 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3611 stats.jitterSamples);
3612
3613 // --- Part two of the final structure (one value)
3614
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003615 uint16_t RTT(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003616 RTCPMethod method = _rtpRtcpModule->RTCP();
3617 if (method == kRtcpOff)
3618 {
3619 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3620 VoEId(_instanceId, _channelId),
3621 "GetRTPStatistics() RTCP is disabled => valid RTT "
3622 "measurements cannot be retrieved");
3623 } else
3624 {
3625 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003626 uint32_t remoteSSRC = rtp_receiver_->SSRC();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003627 if (remoteSSRC > 0)
3628 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003629 uint16_t avgRTT(0);
3630 uint16_t maxRTT(0);
3631 uint16_t minRTT(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003632
3633 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
3634 != 0)
3635 {
3636 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3637 VoEId(_instanceId, _channelId),
3638 "GetRTPStatistics() failed to retrieve RTT from "
3639 "the RTP/RTCP module");
3640 }
3641 } else
3642 {
3643 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3644 VoEId(_instanceId, _channelId),
3645 "GetRTPStatistics() failed to measure RTT since no "
3646 "RTP packets have been received yet");
3647 }
3648 }
3649
3650 stats.rttMs = static_cast<int> (RTT);
3651
3652 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3653 VoEId(_instanceId, _channelId),
3654 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3655
3656 // --- Part three of the final structure (four values)
3657
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003658 uint32_t bytesSent(0);
3659 uint32_t packetsSent(0);
3660 uint32_t bytesReceived(0);
3661 uint32_t packetsReceived(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003662
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00003663 if (statistician) {
3664 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3665 }
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003666
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003667 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00003668 &packetsSent) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003669 {
3670 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3671 VoEId(_instanceId, _channelId),
3672 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
3673 " output will not be complete");
3674 }
3675
3676 stats.bytesSent = bytesSent;
3677 stats.packetsSent = packetsSent;
3678 stats.bytesReceived = bytesReceived;
3679 stats.packetsReceived = packetsReceived;
3680
3681 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3682 VoEId(_instanceId, _channelId),
3683 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
3684 " bytesReceived=%d, packetsReceived=%d)",
3685 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3686 stats.packetsReceived);
3687
3688 return 0;
3689}
3690
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003691int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3692 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3693 "Channel::SetFECStatus()");
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003694
turaj@webrtc.org040f8002013-01-31 18:20:17 +00003695 if (enable) {
3696 if (redPayloadtype < 0 || redPayloadtype > 127) {
3697 _engineStatisticsPtr->SetLastError(
3698 VE_PLTYPE_ERROR, kTraceError,
3699 "SetFECStatus() invalid RED payload type");
3700 return -1;
3701 }
3702
3703 if (SetRedPayloadType(redPayloadtype) < 0) {
3704 _engineStatisticsPtr->SetLastError(
3705 VE_CODEC_ERROR, kTraceError,
3706 "SetSecondarySendCodec() Failed to register RED ACM");
3707 return -1;
3708 }
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003709 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003710
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003711 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00003712 _engineStatisticsPtr->SetLastError(
3713 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3714 "SetFECStatus() failed to set FEC state in the ACM");
3715 return -1;
3716 }
3717 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003718}
3719
3720int
3721Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
3722{
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003723 enabled = audio_coding_->FECStatus();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003724 if (enabled)
3725 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003726 int8_t payloadType(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003727 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
3728 {
3729 _engineStatisticsPtr->SetLastError(
3730 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3731 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
3732 "module");
3733 return -1;
3734 }
3735 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3736 VoEId(_instanceId, _channelId),
3737 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
3738 enabled, redPayloadtype);
3739 return 0;
3740 }
3741 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3742 VoEId(_instanceId, _channelId),
3743 "GetFECStatus() => enabled=%d", enabled);
3744 return 0;
3745}
3746
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003747void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3748 // None of these functions can fail.
3749 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.orgdb74c612013-09-06 13:40:11 +00003750 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3751 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003752 if (enable)
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003753 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003754 else
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003755 audio_coding_->DisableNack();
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003756}
3757
pwestin@webrtc.org4aa9f1a2013-06-06 21:09:01 +00003758// Called when we are missing one or more packets.
3759int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgb8171ff2013-06-05 15:33:20 +00003760 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3761}
3762
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003763int
3764Channel::StartRTPDump(const char fileNameUTF8[1024],
3765 RTPDirections direction)
3766{
3767 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3768 "Channel::StartRTPDump()");
3769 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3770 {
3771 _engineStatisticsPtr->SetLastError(
3772 VE_INVALID_ARGUMENT, kTraceError,
3773 "StartRTPDump() invalid RTP direction");
3774 return -1;
3775 }
3776 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3777 &_rtpDumpIn : &_rtpDumpOut;
3778 if (rtpDumpPtr == NULL)
3779 {
3780 assert(false);
3781 return -1;
3782 }
3783 if (rtpDumpPtr->IsActive())
3784 {
3785 rtpDumpPtr->Stop();
3786 }
3787 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3788 {
3789 _engineStatisticsPtr->SetLastError(
3790 VE_BAD_FILE, kTraceError,
3791 "StartRTPDump() failed to create file");
3792 return -1;
3793 }
3794 return 0;
3795}
3796
3797int
3798Channel::StopRTPDump(RTPDirections direction)
3799{
3800 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3801 "Channel::StopRTPDump()");
3802 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3803 {
3804 _engineStatisticsPtr->SetLastError(
3805 VE_INVALID_ARGUMENT, kTraceError,
3806 "StopRTPDump() invalid RTP direction");
3807 return -1;
3808 }
3809 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3810 &_rtpDumpIn : &_rtpDumpOut;
3811 if (rtpDumpPtr == NULL)
3812 {
3813 assert(false);
3814 return -1;
3815 }
3816 if (!rtpDumpPtr->IsActive())
3817 {
3818 return 0;
3819 }
3820 return rtpDumpPtr->Stop();
3821}
3822
3823bool
3824Channel::RTPDumpIsActive(RTPDirections direction)
3825{
3826 if ((direction != kRtpIncoming) &&
3827 (direction != kRtpOutgoing))
3828 {
3829 _engineStatisticsPtr->SetLastError(
3830 VE_INVALID_ARGUMENT, kTraceError,
3831 "RTPDumpIsActive() invalid RTP direction");
3832 return false;
3833 }
3834 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3835 &_rtpDumpIn : &_rtpDumpOut;
3836 return rtpDumpPtr->IsActive();
3837}
3838
solenberg@webrtc.orgfec6b6e2014-03-24 10:38:25 +00003839void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3840 int video_channel) {
3841 CriticalSectionScoped cs(&_callbackCritSect);
3842 if (vie_network_) {
3843 vie_network_->Release();
3844 vie_network_ = NULL;
3845 }
3846 video_channel_ = -1;
3847
3848 if (vie_network != NULL && video_channel != -1) {
3849 vie_network_ = vie_network;
3850 video_channel_ = video_channel;
3851 }
3852}
3853
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003854uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003855Channel::Demultiplex(const AudioFrame& audioFrame)
3856{
3857 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3858 "Channel::Demultiplex()");
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00003859 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003860 _audioFrame.id_ = _channelId;
3861 return 0;
3862}
3863
xians@webrtc.org44f12392013-07-31 16:23:37 +00003864void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00003865 int sample_rate,
xians@webrtc.org44f12392013-07-31 16:23:37 +00003866 int number_of_frames,
xians@webrtc.org0e6fa8c2013-07-31 16:27:42 +00003867 int number_of_channels) {
xians@webrtc.org44f12392013-07-31 16:23:37 +00003868 CodecInst codec;
3869 GetSendCodec(codec);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003870
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00003871 if (!mono_recording_audio_.get()) {
3872 // Temporary space for DownConvertToCodecFormat.
3873 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003874 }
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00003875 DownConvertToCodecFormat(audio_data,
3876 number_of_frames,
3877 number_of_channels,
3878 sample_rate,
3879 codec.channels,
3880 codec.plfreq,
3881 mono_recording_audio_.get(),
3882 &input_resampler_,
3883 &_audioFrame);
xians@webrtc.org44f12392013-07-31 16:23:37 +00003884}
3885
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003886uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003887Channel::PrepareEncodeAndSend(int mixingFrequency)
3888{
3889 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3890 "Channel::PrepareEncodeAndSend()");
3891
3892 if (_audioFrame.samples_per_channel_ == 0)
3893 {
3894 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3895 "Channel::PrepareEncodeAndSend() invalid audio frame");
3896 return -1;
3897 }
3898
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003899 if (channel_state_.Get().input_file_playing)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003900 {
3901 MixOrReplaceAudioWithFile(mixingFrequency);
3902 }
3903
wu@webrtc.orgf7651ef2013-10-17 18:28:55 +00003904 if (Mute())
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003905 {
3906 AudioFrameOperations::Mute(_audioFrame);
3907 }
3908
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00003909 if (channel_state_.Get().input_external_media)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003910 {
3911 CriticalSectionScoped cs(&_callbackCritSect);
3912 const bool isStereo = (_audioFrame.num_channels_ == 2);
3913 if (_inputExternalMediaCallbackPtr)
3914 {
3915 _inputExternalMediaCallbackPtr->Process(
3916 _channelId,
3917 kRecordingPerChannel,
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003918 (int16_t*)_audioFrame.data_,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003919 _audioFrame.samples_per_channel_,
3920 _audioFrame.sample_rate_hz_,
3921 isStereo);
3922 }
3923 }
3924
3925 InsertInbandDtmfTone();
3926
andrew@webrtc.orge95dc252014-01-07 17:45:09 +00003927 if (_includeAudioLevelIndication) {
3928 // Performs level analysis only; does not affect the signal.
3929 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
3930 if (err) {
3931 LOG(LS_ERROR) << "ProcessStream() error: " << err;
3932 assert(false);
3933 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003934 }
3935
3936 return 0;
3937}
3938
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00003939uint32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003940Channel::EncodeAndSend()
3941{
3942 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3943 "Channel::EncodeAndSend()");
3944
3945 assert(_audioFrame.num_channels_ <= 2);
3946 if (_audioFrame.samples_per_channel_ == 0)
3947 {
3948 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3949 "Channel::EncodeAndSend() invalid audio frame");
3950 return -1;
3951 }
3952
3953 _audioFrame.id_ = _channelId;
3954
3955 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3956
3957 // The ACM resamples internally.
3958 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003959 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003960 {
3961 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3962 "Channel::EncodeAndSend() ACM encoding failed");
3963 return -1;
3964 }
3965
3966 _timeStamp += _audioFrame.samples_per_channel_;
3967
3968 // --- Encode if complete frame is ready
3969
3970 // This call will trigger AudioPacketizationCallback::SendData if encoding
3971 // is done and payload is ready for packetization and transmission.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00003972 return audio_coding_->Process();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00003973}
3974
3975int Channel::RegisterExternalMediaProcessing(
3976 ProcessingTypes type,
3977 VoEMediaProcess& processObject)
3978{
3979 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3980 "Channel::RegisterExternalMediaProcessing()");
3981
3982 CriticalSectionScoped cs(&_callbackCritSect);
3983
3984 if (kPlaybackPerChannel == type)
3985 {
3986 if (_outputExternalMediaCallbackPtr)
3987 {
3988 _engineStatisticsPtr->SetLastError(
3989 VE_INVALID_OPERATION, kTraceError,
3990 "Channel::RegisterExternalMediaProcessing() "
3991 "output external media already enabled");
3992 return -1;
3993 }
3994 _outputExternalMediaCallbackPtr = &processObject;
3995 _outputExternalMedia = true;
3996 }
3997 else if (kRecordingPerChannel == type)
3998 {
3999 if (_inputExternalMediaCallbackPtr)
4000 {
4001 _engineStatisticsPtr->SetLastError(
4002 VE_INVALID_OPERATION, kTraceError,
4003 "Channel::RegisterExternalMediaProcessing() "
4004 "output external media already enabled");
4005 return -1;
4006 }
4007 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004008 channel_state_.SetInputExternalMedia(true);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004009 }
4010 return 0;
4011}
4012
4013int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4014{
4015 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4016 "Channel::DeRegisterExternalMediaProcessing()");
4017
4018 CriticalSectionScoped cs(&_callbackCritSect);
4019
4020 if (kPlaybackPerChannel == type)
4021 {
4022 if (!_outputExternalMediaCallbackPtr)
4023 {
4024 _engineStatisticsPtr->SetLastError(
4025 VE_INVALID_OPERATION, kTraceWarning,
4026 "Channel::DeRegisterExternalMediaProcessing() "
4027 "output external media already disabled");
4028 return 0;
4029 }
4030 _outputExternalMedia = false;
4031 _outputExternalMediaCallbackPtr = NULL;
4032 }
4033 else if (kRecordingPerChannel == type)
4034 {
4035 if (!_inputExternalMediaCallbackPtr)
4036 {
4037 _engineStatisticsPtr->SetLastError(
4038 VE_INVALID_OPERATION, kTraceWarning,
4039 "Channel::DeRegisterExternalMediaProcessing() "
4040 "input external media already disabled");
4041 return 0;
4042 }
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004043 channel_state_.SetInputExternalMedia(false);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004044 _inputExternalMediaCallbackPtr = NULL;
4045 }
4046
4047 return 0;
4048}
4049
roosa@google.comb9e3afc2012-12-12 23:00:29 +00004050int Channel::SetExternalMixing(bool enabled) {
4051 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4052 "Channel::SetExternalMixing(enabled=%d)", enabled);
4053
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004054 if (channel_state_.Get().playing)
roosa@google.comb9e3afc2012-12-12 23:00:29 +00004055 {
4056 _engineStatisticsPtr->SetLastError(
4057 VE_INVALID_OPERATION, kTraceError,
4058 "Channel::SetExternalMixing() "
4059 "external mixing cannot be changed while playing.");
4060 return -1;
4061 }
4062
4063 _externalMixing = enabled;
4064
4065 return 0;
4066}
4067
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004068int
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004069Channel::GetNetworkStatistics(NetworkStatistics& stats)
4070{
4071 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4072 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.orge9bb4e52013-02-21 10:27:48 +00004073 ACMNetworkStatistics acm_stats;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004074 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.orge9bb4e52013-02-21 10:27:48 +00004075 if (return_value >= 0) {
4076 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4077 }
4078 return return_value;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004079}
4080
wu@webrtc.org79d6daf2013-12-13 19:17:43 +00004081void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4082 audio_coding_->GetDecodingCallStatistics(stats);
4083}
4084
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004085bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4086 int* playout_buffer_delay_ms) const {
4087 if (_average_jitter_buffer_delay_us == 0) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004089 "Channel::GetDelayEstimate() no valid estimate.");
4090 return false;
4091 }
4092 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4093 _recPacketDelayMs;
4094 *playout_buffer_delay_ms = playout_delay_ms_;
4095 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4096 "Channel::GetDelayEstimate()");
4097 return true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004098}
4099
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +00004100int Channel::SetInitialPlayoutDelay(int delay_ms)
4101{
4102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4103 "Channel::SetInitialPlayoutDelay()");
4104 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4105 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4106 {
4107 _engineStatisticsPtr->SetLastError(
4108 VE_INVALID_ARGUMENT, kTraceError,
4109 "SetInitialPlayoutDelay() invalid min delay");
4110 return -1;
4111 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004112 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.orgead8a5b2013-02-12 21:42:18 +00004113 {
4114 _engineStatisticsPtr->SetLastError(
4115 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4116 "SetInitialPlayoutDelay() failed to set min playout delay");
4117 return -1;
4118 }
4119 return 0;
4120}
4121
4122
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004123int
4124Channel::SetMinimumPlayoutDelay(int delayMs)
4125{
4126 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4127 "Channel::SetMinimumPlayoutDelay()");
4128 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4129 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4130 {
4131 _engineStatisticsPtr->SetLastError(
4132 VE_INVALID_ARGUMENT, kTraceError,
4133 "SetMinimumPlayoutDelay() invalid min delay");
4134 return -1;
4135 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004136 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004137 {
4138 _engineStatisticsPtr->SetLastError(
4139 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4140 "SetMinimumPlayoutDelay() failed to set min playout delay");
4141 return -1;
4142 }
4143 return 0;
4144}
4145
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004146void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4147 uint32_t playout_timestamp = 0;
4148
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004149 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004150 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4151 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4152 " timestamp from the ACM");
4153 _engineStatisticsPtr->SetLastError(
4154 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4155 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4156 return;
4157 }
4158
4159 uint16_t delay_ms = 0;
4160 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4161 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4162 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4163 " delay from the ADM");
4164 _engineStatisticsPtr->SetLastError(
4165 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4166 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4167 return;
4168 }
4169
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004170 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004171 CodecInst current_recive_codec;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004172 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004173 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4174 playout_frequency = 8000;
4175 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4176 playout_frequency = 48000;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004177 }
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004178 }
4179
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +00004180 jitter_buffer_playout_timestamp_ = playout_timestamp;
4181
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004182 // Remove the playout delay.
4183 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4184
4185 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4186 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4187 playout_timestamp);
4188
4189 if (rtcp) {
4190 playout_timestamp_rtcp_ = playout_timestamp;
4191 } else {
4192 playout_timestamp_rtp_ = playout_timestamp;
4193 }
4194 playout_delay_ms_ = delay_ms;
4195}
4196
4197int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4198 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4199 "Channel::GetPlayoutTimestamp()");
4200 if (playout_timestamp_rtp_ == 0) {
4201 _engineStatisticsPtr->SetLastError(
4202 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4203 "GetPlayoutTimestamp() failed to retrieve timestamp");
4204 return -1;
4205 }
4206 timestamp = playout_timestamp_rtp_;
4207 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4208 VoEId(_instanceId,_channelId),
4209 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4210 return 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004211}
4212
4213int
4214Channel::SetInitTimestamp(unsigned int timestamp)
4215{
4216 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4217 "Channel::SetInitTimestamp()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004218 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004219 {
4220 _engineStatisticsPtr->SetLastError(
4221 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4222 return -1;
4223 }
4224 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
4225 {
4226 _engineStatisticsPtr->SetLastError(
4227 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4228 "SetInitTimestamp() failed to set timestamp");
4229 return -1;
4230 }
4231 return 0;
4232}
4233
4234int
4235Channel::SetInitSequenceNumber(short sequenceNumber)
4236{
4237 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4238 "Channel::SetInitSequenceNumber()");
henrika@webrtc.orgdf08c5d2014-03-18 10:32:33 +00004239 if (channel_state_.Get().sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004240 {
4241 _engineStatisticsPtr->SetLastError(
4242 VE_SENDING, kTraceError,
4243 "SetInitSequenceNumber() already sending");
4244 return -1;
4245 }
4246 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
4247 {
4248 _engineStatisticsPtr->SetLastError(
4249 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4250 "SetInitSequenceNumber() failed to set sequence number");
4251 return -1;
4252 }
4253 return 0;
4254}
4255
4256int
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004257Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004258{
4259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4260 "Channel::GetRtpRtcp()");
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004261 *rtpRtcpModule = _rtpRtcpModule.get();
4262 *rtp_receiver = rtp_receiver_.get();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004263 return 0;
4264}
4265
4266// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4267// a shared helper.
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004268int32_t
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00004269Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004270{
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004271 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004272 int fileSamples(0);
4273
4274 {
4275 CriticalSectionScoped cs(&_fileCritSect);
4276
4277 if (_inputFilePlayerPtr == NULL)
4278 {
4279 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4280 VoEId(_instanceId, _channelId),
4281 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4282 " doesnt exist");
4283 return -1;
4284 }
4285
4286 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4287 fileSamples,
4288 mixingFrequency) == -1)
4289 {
4290 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4291 VoEId(_instanceId, _channelId),
4292 "Channel::MixOrReplaceAudioWithFile() file mixing "
4293 "failed");
4294 return -1;
4295 }
4296 if (fileSamples == 0)
4297 {
4298 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4299 VoEId(_instanceId, _channelId),
4300 "Channel::MixOrReplaceAudioWithFile() file is ended");
4301 return 0;
4302 }
4303 }
4304
4305 assert(_audioFrame.samples_per_channel_ == fileSamples);
4306
4307 if (_mixFileWithMicrophone)
4308 {
4309 // Currently file stream is always mono.
4310 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00004311 MixWithSat(_audioFrame.data_,
4312 _audioFrame.num_channels_,
4313 fileBuffer.get(),
4314 1,
4315 fileSamples);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004316 }
4317 else
4318 {
4319 // Replace ACM audio with file.
4320 // Currently file stream is always mono.
4321 // TODO(xians): Change the code when FilePlayer supports real stereo.
4322 _audioFrame.UpdateFrame(_channelId,
4323 -1,
4324 fileBuffer.get(),
4325 fileSamples,
4326 mixingFrequency,
4327 AudioFrame::kNormalSpeech,
4328 AudioFrame::kVadUnknown,
4329 1);
4330
4331 }
4332 return 0;
4333}
4334
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004335int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004336Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.orgca7a9a22013-05-14 08:31:39 +00004337 int mixingFrequency)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004338{
4339 assert(mixingFrequency <= 32000);
4340
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004341 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004342 int fileSamples(0);
4343
4344 {
4345 CriticalSectionScoped cs(&_fileCritSect);
4346
4347 if (_outputFilePlayerPtr == NULL)
4348 {
4349 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4350 VoEId(_instanceId, _channelId),
4351 "Channel::MixAudioWithFile() file mixing failed");
4352 return -1;
4353 }
4354
4355 // We should get the frequency we ask for.
4356 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
4357 fileSamples,
4358 mixingFrequency) == -1)
4359 {
4360 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4361 VoEId(_instanceId, _channelId),
4362 "Channel::MixAudioWithFile() file mixing failed");
4363 return -1;
4364 }
4365 }
4366
4367 if (audioFrame.samples_per_channel_ == fileSamples)
4368 {
4369 // Currently file stream is always mono.
4370 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.orgf7c73b52014-04-03 21:56:01 +00004371 MixWithSat(audioFrame.data_,
4372 audioFrame.num_channels_,
4373 fileBuffer.get(),
4374 1,
4375 fileSamples);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004376 }
4377 else
4378 {
4379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4380 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
4381 "fileSamples(%d)",
4382 audioFrame.samples_per_channel_, fileSamples);
4383 return -1;
4384 }
4385
4386 return 0;
4387}
4388
4389int
4390Channel::InsertInbandDtmfTone()
4391{
4392 // Check if we should start a new tone.
4393 if (_inbandDtmfQueue.PendingDtmf() &&
4394 !_inbandDtmfGenerator.IsAddingTone() &&
4395 _inbandDtmfGenerator.DelaySinceLastTone() >
4396 kMinTelephoneEventSeparationMs)
4397 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004398 int8_t eventCode(0);
4399 uint16_t lengthMs(0);
4400 uint8_t attenuationDb(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004401
4402 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4403 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4404 if (_playInbandDtmfEvent)
4405 {
4406 // Add tone to output mixer using a reduced length to minimize
4407 // risk of echo.
4408 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4409 attenuationDb);
4410 }
4411 }
4412
4413 if (_inbandDtmfGenerator.IsAddingTone())
4414 {
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004415 uint16_t frequency(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004416 _inbandDtmfGenerator.GetSampleRate(frequency);
4417
4418 if (frequency != _audioFrame.sample_rate_hz_)
4419 {
4420 // Update sample rate of Dtmf tone since the mixing frequency
4421 // has changed.
4422 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004423 (uint16_t) (_audioFrame.sample_rate_hz_));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004424 // Reset the tone to be added taking the new sample rate into
4425 // account.
4426 _inbandDtmfGenerator.ResetTone();
4427 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004428
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004429 int16_t toneBuffer[320];
4430 uint16_t toneSamples(0);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004431 // Get 10ms tone segment and set time since last tone to zero
4432 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4433 {
4434 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4435 VoEId(_instanceId, _channelId),
4436 "Channel::EncodeAndSend() inserting Dtmf failed");
4437 return -1;
4438 }
4439
4440 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004441 for (int sample = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004442 sample < _audioFrame.samples_per_channel_;
4443 sample++)
4444 {
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004445 for (int channel = 0;
4446 channel < _audioFrame.num_channels_;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004447 channel++)
4448 {
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004449 const int index = sample * _audioFrame.num_channels_ + channel;
4450 _audioFrame.data_[index] = toneBuffer[sample];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004451 }
4452 }
andrew@webrtc.orgd4682362013-01-22 04:44:30 +00004453
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004454 assert(_audioFrame.samples_per_channel_ == toneSamples);
4455 } else
4456 {
4457 // Add 10ms to "delay-since-last-tone" counter
4458 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4459 }
4460 return 0;
4461}
4462
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004463int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004464Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4465{
wu@webrtc.orgb27e6702013-10-18 21:10:51 +00004466 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004467 if (_transportPtr == NULL)
4468 {
4469 return -1;
4470 }
4471 if (!RTCP)
4472 {
4473 return _transportPtr->SendPacket(_channelId, data, len);
4474 }
4475 else
4476 {
4477 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4478 }
4479}
4480
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004481// Called for incoming RTP packets after successful RTP header parsing.
4482void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4483 uint16_t sequence_number) {
4484 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4485 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4486 rtp_timestamp, sequence_number);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004487
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004488 // Get frequency of last received payload
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004489 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004490
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004491 CodecInst current_receive_codec;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004492 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004493 return;
4494 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004495
turaj@webrtc.orgd5577342013-05-22 20:39:43 +00004496 // Update the least required delay.
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004497 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orgd5577342013-05-22 20:39:43 +00004498
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004499 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4500 // Even though the actual sampling rate for G.722 audio is
4501 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4502 // 8,000 Hz because that value was erroneously assigned in
4503 // RFC 1890 and must remain unchanged for backward compatibility.
4504 rtp_receive_frequency = 8000;
4505 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4506 // We are resampling Opus internally to 32,000 Hz until all our
4507 // DSP routines can operate at 48,000 Hz, but the RTP clock
4508 // rate for the Opus payload format is standardized to 48,000 Hz,
4509 // because that is the maximum supported decoding sampling rate.
4510 rtp_receive_frequency = 48000;
4511 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004512
turaj@webrtc.orgf1b92fd2013-12-13 21:05:07 +00004513 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4514 // every incoming packet.
4515 uint32_t timestamp_diff_ms = (rtp_timestamp -
4516 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orga5db8e32014-03-20 12:04:09 +00004517 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4518 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4519 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4520 // timestamp, the resulting difference is negative, but is set to zero.
4521 // This can happen when a network glitch causes a packet to arrive late,
4522 // and during long comfort noise periods with clock drift.
4523 timestamp_diff_ms = 0;
4524 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004525
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004526 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4527 (rtp_receive_frequency / 1000);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004528
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004529 _previousTimestamp = rtp_timestamp;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004530
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004531 if (timestamp_diff_ms == 0) return;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004532
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004533 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4534 _recPacketDelayMs = packet_delay_ms;
4535 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004536
pwestin@webrtc.orgf2724972013-04-11 20:23:35 +00004537 if (_average_jitter_buffer_delay_us == 0) {
4538 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4539 return;
4540 }
4541
4542 // Filter average delay value using exponential filter (alpha is
4543 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4544 // risk of rounding error) and compensate for it in GetDelayEstimate()
4545 // later.
4546 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4547 1000 * timestamp_diff_ms + 500) / 8;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004548}
4549
4550void
4551Channel::RegisterReceiveCodecsToRTPModule()
4552{
4553 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4554 "Channel::RegisterReceiveCodecsToRTPModule()");
4555
4556
4557 CodecInst codec;
pbos@webrtc.org54f03bc2013-04-09 10:09:10 +00004558 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004559
4560 for (int idx = 0; idx < nSupportedCodecs; idx++)
4561 {
4562 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004563 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +00004564 (rtp_receiver_->RegisterReceivePayload(
4565 codec.plname,
4566 codec.pltype,
4567 codec.plfreq,
4568 codec.channels,
4569 (codec.rate < 0) ? 0 : codec.rate) == -1))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00004570 {
4571 WEBRTC_TRACE(
4572 kTraceWarning,
4573 kTraceVoice,
4574 VoEId(_instanceId, _channelId),
4575 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4576 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4577 codec.plname, codec.pltype, codec.plfreq,
4578 codec.channels, codec.rate);
4579 }
4580 else
4581 {
4582 WEBRTC_TRACE(
4583 kTraceInfo,
4584 kTraceVoice,
4585 VoEId(_instanceId, _channelId),
4586 "Channel::RegisterReceiveCodecsToRTPModule() %s "
4587 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
4588 "receiver",
4589 codec.plname, codec.pltype, codec.plfreq,
4590 codec.channels, codec.rate);
4591 }
4592 }
4593}
4594
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004595int Channel::SetSecondarySendCodec(const CodecInst& codec,
4596 int red_payload_type) {
turaj@webrtc.org040f8002013-01-31 18:20:17 +00004597 // Sanity check for payload type.
4598 if (red_payload_type < 0 || red_payload_type > 127) {
4599 _engineStatisticsPtr->SetLastError(
4600 VE_PLTYPE_ERROR, kTraceError,
4601 "SetRedPayloadType() invalid RED payload type");
4602 return -1;
4603 }
4604
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004605 if (SetRedPayloadType(red_payload_type) < 0) {
4606 _engineStatisticsPtr->SetLastError(
4607 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4608 "SetSecondarySendCodec() Failed to register RED ACM");
4609 return -1;
4610 }
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004611 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004612 _engineStatisticsPtr->SetLastError(
4613 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4614 "SetSecondarySendCodec() Failed to register secondary send codec in "
4615 "ACM");
4616 return -1;
4617 }
4618
4619 return 0;
4620}
4621
4622void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004623 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004624}
4625
4626int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004627 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004628 _engineStatisticsPtr->SetLastError(
4629 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4630 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4631 return -1;
4632 }
4633 return 0;
4634}
4635
turaj@webrtc.org040f8002013-01-31 18:20:17 +00004636// Assuming this method is called with valid payload type.
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004637int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004638 CodecInst codec;
4639 bool found_red = false;
4640
4641 // Get default RED settings from the ACM database
4642 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4643 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004644 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004645 if (!STR_CASE_CMP(codec.plname, "RED")) {
4646 found_red = true;
4647 break;
4648 }
4649 }
4650
4651 if (!found_red) {
4652 _engineStatisticsPtr->SetLastError(
4653 VE_CODEC_ERROR, kTraceError,
4654 "SetRedPayloadType() RED is not supported");
4655 return -1;
4656 }
4657
turaj@webrtc.org2344ebe2013-01-31 18:34:19 +00004658 codec.pltype = red_payload_type;
andrew@webrtc.org510ee1b2013-09-23 23:02:24 +00004659 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org7db52902012-12-11 02:15:12 +00004660 _engineStatisticsPtr->SetLastError(
4661 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4662 "SetRedPayloadType() RED registration in ACM module failed");
4663 return -1;
4664 }
4665
4666 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4667 _engineStatisticsPtr->SetLastError(
4668 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4669 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4670 return -1;
4671 }
4672 return 0;
4673}
4674
wu@webrtc.org9a823222014-03-06 23:49:08 +00004675int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4676 unsigned char id) {
4677 int error = 0;
4678 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4679 if (enable) {
4680 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4681 }
4682 return error;
4683}
pbos@webrtc.org3b89e102013-07-03 15:12:26 +00004684} // namespace voe
4685} // namespace webrtc