blob: 480ff49475772b74a7bb3eff9c9742b4928db644 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000016#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/utility/interface/audio_frame_operations.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/utility/interface/rtp_dump.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/voice_engine/include/voe_base.h"
27#include "webrtc/voice_engine/include/voe_external_media.h"
28#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
29#include "webrtc/voice_engine/output_mixer.h"
30#include "webrtc/voice_engine/statistics.h"
31#include "webrtc/voice_engine/transmit_mixer.h"
32#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34#if defined(_WIN32)
35#include <Qos.h>
36#endif
37
andrew@webrtc.org50419b02012-11-14 19:07:54 +000038namespace webrtc {
39namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000040
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000041// Extend the default RTCP statistics struct with max_jitter, defined as the
42// maximum jitter value seen in an RTCP report block.
43struct ChannelStatistics : public RtcpStatistics {
44 ChannelStatistics() : rtcp(), max_jitter(0) {}
45
46 RtcpStatistics rtcp;
47 uint32_t max_jitter;
48};
49
50// Statistics callback, called at each generation of a new RTCP report block.
51class StatisticsProxy : public RtcpStatisticsCallback {
52 public:
53 StatisticsProxy(uint32_t ssrc)
54 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
55 ssrc_(ssrc) {}
56 virtual ~StatisticsProxy() {}
57
58 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
59 uint32_t ssrc) OVERRIDE {
60 if (ssrc != ssrc_)
61 return;
62
63 CriticalSectionScoped cs(stats_lock_.get());
64 stats_.rtcp = statistics;
65 if (statistics.jitter > stats_.max_jitter) {
66 stats_.max_jitter = statistics.jitter;
67 }
68 }
69
70 void ResetStatistics() {
71 CriticalSectionScoped cs(stats_lock_.get());
72 stats_ = ChannelStatistics();
73 }
74
75 ChannelStatistics GetStats() {
76 CriticalSectionScoped cs(stats_lock_.get());
77 return stats_;
78 }
79
80 private:
81 // StatisticsUpdated calls are triggered from threads in the RTP module,
82 // while GetStats calls can be triggered from the public voice engine API,
83 // hence synchronization is needed.
84 scoped_ptr<CriticalSectionWrapper> stats_lock_;
85 const uint32_t ssrc_;
86 ChannelStatistics stats_;
87};
88
pbos@webrtc.org6141e132013-04-09 10:09:10 +000089int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000090Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000091 uint8_t payloadType,
92 uint32_t timeStamp,
93 const uint8_t* payloadData,
94 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000095 const RTPFragmentationHeader* fragmentation)
96{
97 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
98 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
99 " payloadSize=%u, fragmentation=0x%x)",
100 frameType, payloadType, timeStamp, payloadSize, fragmentation);
101
102 if (_includeAudioLevelIndication)
103 {
104 // Store current audio level in the RTP/RTCP module.
105 // The level will be used in combination with voice-activity state
106 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000107 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 }
109
110 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
111 // packetization.
112 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000113 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 payloadType,
115 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000116 // Leaving the time when this frame was
117 // received from the capture device as
118 // undefined for voice for now.
119 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 payloadData,
121 payloadSize,
122 fragmentation) == -1)
123 {
124 _engineStatisticsPtr->SetLastError(
125 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
126 "Channel::SendData() failed to send data to RTP/RTCP module");
127 return -1;
128 }
129
130 _lastLocalTimeStamp = timeStamp;
131 _lastPayloadType = payloadType;
132
133 return 0;
134}
135
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136int32_t
137Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
140 "Channel::InFrameType(frameType=%d)", frameType);
141
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000142 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 // 1 indicates speech
144 _sendFrameType = (frameType == 1) ? 1 : 0;
145 return 0;
146}
147
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000148int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000149Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000150{
151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
152 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
153
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000154 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 if (_rxVadObserverPtr)
156 {
157 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
158 }
159
160 return 0;
161}
162
163int
164Channel::SendPacket(int channel, const void *data, int len)
165{
166 channel = VoEChannelId(channel);
167 assert(channel == _channelId);
168
169 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
170 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
171
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000172 CriticalSectionScoped cs(&_callbackCritSect);
173
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 if (_transportPtr == NULL)
175 {
176 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
177 "Channel::SendPacket() failed to send RTP packet due to"
178 " invalid transport object");
179 return -1;
180 }
181
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000182 uint8_t* bufferToSendPtr = (uint8_t*)data;
183 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
185 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000186 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 {
188 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
189 VoEId(_instanceId,_channelId),
190 "Channel::SendPacket() RTP dump to output file failed");
191 }
192
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000193 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
194 bufferLength);
195 if (n < 0) {
196 std::string transport_name =
197 _externalTransport ? "external transport" : "WebRtc sockets";
198 WEBRTC_TRACE(kTraceError, kTraceVoice,
199 VoEId(_instanceId,_channelId),
200 "Channel::SendPacket() RTP transmission using %s failed",
201 transport_name.c_str());
202 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000203 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000204 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
206
207int
208Channel::SendRTCPPacket(int channel, const void *data, int len)
209{
210 channel = VoEChannelId(channel);
211 assert(channel == _channelId);
212
213 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
214 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
215
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000216 CriticalSectionScoped cs(&_callbackCritSect);
217 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000219 WEBRTC_TRACE(kTraceError, kTraceVoice,
220 VoEId(_instanceId,_channelId),
221 "Channel::SendRTCPPacket() failed to send RTCP packet"
222 " due to invalid transport object");
223 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 }
225
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000226 uint8_t* bufferToSendPtr = (uint8_t*)data;
227 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228
229 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000230 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000231 {
232 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
233 VoEId(_instanceId,_channelId),
234 "Channel::SendPacket() RTCP dump to output file failed");
235 }
236
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000237 int n = _transportPtr->SendRTCPPacket(channel,
238 bufferToSendPtr,
239 bufferLength);
240 if (n < 0) {
241 std::string transport_name =
242 _externalTransport ? "external transport" : "WebRtc sockets";
243 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
244 VoEId(_instanceId,_channelId),
245 "Channel::SendRTCPPacket() transmission using %s failed",
246 transport_name.c_str());
247 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000249 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250}
251
252void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000253Channel::OnPlayTelephoneEvent(int32_t id,
254 uint8_t event,
255 uint16_t lengthMs,
256 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000257{
258 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
259 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000260 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000261
262 if (!_playOutbandDtmfEvent || (event > 15))
263 {
264 // Ignore callback since feedback is disabled or event is not a
265 // Dtmf tone event.
266 return;
267 }
268
269 assert(_outputMixerPtr != NULL);
270
271 // Start playing out the Dtmf tone (if playout is enabled).
272 // Reduce length of tone with 80ms to the reduce risk of echo.
273 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
274}
275
276void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000277Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000278{
279 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
280 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000281 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000283 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 assert(channel == _channelId);
285
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000286 // Update ssrc so that NTP for AV sync can be updated.
287 _rtpRtcpModule->SetRemoteSSRC(ssrc);
288
niklase@google.com470e71d2011-07-07 08:21:25 +0000289 if (_rtpObserver)
290 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000291 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000292
293 if (_rtpObserverPtr)
294 {
295 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000296 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 }
298 }
299}
300
pbos@webrtc.org92135212013-05-14 08:31:39 +0000301void Channel::OnIncomingCSRCChanged(int32_t id,
302 uint32_t CSRC,
303 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000304{
305 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
306 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
307 id, CSRC, added);
308
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000309 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000310 assert(channel == _channelId);
311
312 if (_rtpObserver)
313 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000314 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000315
316 if (_rtpObserverPtr)
317 {
318 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
319 }
320 }
321}
322
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000323void Channel::ResetStatistics(uint32_t ssrc) {
324 StreamStatistician* statistician =
325 rtp_receive_statistics_->GetStatistician(ssrc);
326 if (statistician) {
327 statistician->ResetStatistics();
328 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000329 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000330}
331
niklase@google.com470e71d2011-07-07 08:21:25 +0000332void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000333Channel::OnApplicationDataReceived(int32_t id,
334 uint8_t subType,
335 uint32_t name,
336 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000337 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000338{
339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
340 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
341 " name=%u, length=%u)",
342 id, subType, name, length);
343
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000344 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 assert(channel == _channelId);
346
347 if (_rtcpObserver)
348 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000349 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000350
351 if (_rtcpObserverPtr)
352 {
353 _rtcpObserverPtr->OnApplicationDataReceived(channel,
354 subType,
355 name,
356 data,
357 length);
358 }
359 }
360}
361
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000362int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000363Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000364 int32_t id,
365 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000366 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000367 int frequency,
368 uint8_t channels,
369 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000370{
371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
372 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
373 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
374 id, payloadType, payloadName, frequency, channels, rate);
375
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000376 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000377
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000378 CodecInst receiveCodec = {0};
379 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
381 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000382 receiveCodec.plfreq = frequency;
383 receiveCodec.channels = channels;
384 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000385 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000386
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000387 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000388 receiveCodec.pacsize = dummyCodec.pacsize;
389
390 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000391 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 {
393 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000394 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000395 "Channel::OnInitializeDecoder() invalid codec ("
396 "pt=%d, name=%s) received - 1", payloadType, payloadName);
397 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
398 return -1;
399 }
400
401 return 0;
402}
403
404void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000405Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000406{
407 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
408 "Channel::OnPacketTimeout(id=%d)", id);
409
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000410 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000411 if (_voiceEngineObserverPtr)
412 {
413 if (_receiving || _externalTransport)
414 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000415 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000416 assert(channel == _channelId);
417 // Ensure that next OnReceivedPacket() callback will trigger
418 // a VE_PACKET_RECEIPT_RESTARTED callback.
419 _rtpPacketTimedOut = true;
420 // Deliver callback to the observer
421 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
422 VoEId(_instanceId,_channelId),
423 "Channel::OnPacketTimeout() => "
424 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
425 _voiceEngineObserverPtr->CallbackOnError(channel,
426 VE_RECEIVE_PACKET_TIMEOUT);
427 }
428 }
429}
430
431void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000432Channel::OnReceivedPacket(int32_t id,
433 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000434{
435 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
436 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
437 id, packetType);
438
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000439 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000440
441 // Notify only for the case when we have restarted an RTP session.
442 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
443 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000444 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000445 if (_voiceEngineObserverPtr)
446 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000447 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000448 assert(channel == _channelId);
449 // Reset timeout mechanism
450 _rtpPacketTimedOut = false;
451 // Deliver callback to the observer
452 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
453 VoEId(_instanceId,_channelId),
454 "Channel::OnPacketTimeout() =>"
455 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
456 _voiceEngineObserverPtr->CallbackOnError(
457 channel,
458 VE_PACKET_RECEIPT_RESTARTED);
459 }
460 }
461}
462
463void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000464Channel::OnPeriodicDeadOrAlive(int32_t id,
465 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000466{
467 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
468 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
469
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000470 {
471 CriticalSectionScoped cs(&_callbackCritSect);
472 if (!_connectionObserver)
473 return;
474 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000476 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 assert(channel == _channelId);
478
479 // Use Alive as default to limit risk of false Dead detections
480 bool isAlive(true);
481
482 // Always mark the connection as Dead when the module reports kRtpDead
483 if (kRtpDead == alive)
484 {
485 isAlive = false;
486 }
487
488 // It is possible that the connection is alive even if no RTP packet has
489 // been received for a long time since the other side might use VAD/DTX
490 // and a low SID-packet update rate.
491 if ((kRtpNoRtp == alive) && _playing)
492 {
493 // Detect Alive for all NetEQ states except for the case when we are
494 // in PLC_CNG state.
495 // PLC_CNG <=> background noise only due to long expand or error.
496 // Note that, the case where the other side stops sending during CNG
497 // state will be detected as Alive. Dead is is not set until after
498 // missing RTCP packets for at least twelve seconds (handled
499 // internally by the RTP/RTCP module).
500 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
501 }
502
503 UpdateDeadOrAliveCounters(isAlive);
504
505 // Send callback to the registered observer
506 if (_connectionObserver)
507 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000508 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 if (_connectionObserverPtr)
510 {
511 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
512 }
513 }
514}
515
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000516int32_t
517Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000518 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000519 const WebRtcRTPHeader* rtpHeader)
520{
521 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
522 "Channel::OnReceivedPayloadData(payloadSize=%d,"
523 " payloadType=%u, audioChannel=%u)",
524 payloadSize,
525 rtpHeader->header.payloadType,
526 rtpHeader->type.Audio.channel);
527
roosa@google.com0870f022012-12-12 21:31:41 +0000528 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
529
niklase@google.com470e71d2011-07-07 08:21:25 +0000530 if (!_playing)
531 {
532 // Avoid inserting into NetEQ when we are not playing. Count the
533 // packet as discarded.
534 WEBRTC_TRACE(kTraceStream, kTraceVoice,
535 VoEId(_instanceId, _channelId),
536 "received packet is discarded since playing is not"
537 " activated");
538 _numberOfDiscardedPackets++;
539 return 0;
540 }
541
542 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000543 if (audio_coding_->IncomingPacket(payloadData,
544 payloadSize,
545 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 {
547 _engineStatisticsPtr->SetLastError(
548 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
549 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
550 return -1;
551 }
552
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000553 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 UpdatePacketDelay(rtpHeader->header.timestamp,
555 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000556
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000557 uint16_t round_trip_time = 0;
558 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
559 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000560
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000561 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000562 round_trip_time);
563 if (!nack_list.empty()) {
564 // Can't use nack_list.data() since it's not supported by all
565 // compilers.
566 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000567 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 return 0;
569}
570
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000571bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
572 int rtp_packet_length) {
573 RTPHeader header;
574 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
575 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
576 "IncomingPacket invalid RTP header");
577 return false;
578 }
579 header.payload_type_frequency =
580 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
581 if (header.payload_type_frequency < 0)
582 return false;
583 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
584}
585
pbos@webrtc.org92135212013-05-14 08:31:39 +0000586int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000587{
588 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
589 "Channel::GetAudioFrame(id=%d)", id);
590
591 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000592 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
593 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 {
595 WEBRTC_TRACE(kTraceError, kTraceVoice,
596 VoEId(_instanceId,_channelId),
597 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000598 // In all likelihood, the audio in this frame is garbage. We return an
599 // error so that the audio mixer module doesn't add it to the mix. As
600 // a result, it won't be played out and the actions skipped here are
601 // irrelevant.
602 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 }
604
605 if (_RxVadDetection)
606 {
607 UpdateRxVadDetection(audioFrame);
608 }
609
610 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000611 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000613 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000615 if (_rxApmIsEnabled) {
616 int err = rx_audioproc_->ProcessStream(&audioFrame);
617 if (err) {
618 LOG(LS_ERROR) << "ProcessStream() error: " << err;
619 assert(false);
620 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000621 }
622
wu@webrtc.org63420662013-10-17 18:28:55 +0000623 float output_gain = 1.0f;
624 float left_pan = 1.0f;
625 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000627 CriticalSectionScoped cs(&volume_settings_critsect_);
628 output_gain = _outputGain;
629 left_pan = _panLeft;
630 right_pan= _panRight;
631 }
632
633 // Output volume scaling
634 if (output_gain < 0.99f || output_gain > 1.01f)
635 {
636 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 }
638
639 // Scale left and/or right channel(s) if stereo and master balance is
640 // active
641
wu@webrtc.org63420662013-10-17 18:28:55 +0000642 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000644 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 {
646 // Emulate stereo mode since panning is active.
647 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000648 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000649 }
650 // For true stereo mode (when we are receiving a stereo signal), no
651 // action is needed.
652
653 // Do the panning operation (the audio frame contains stereo at this
654 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000655 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 }
657
658 // Mix decoded PCM output with file if file mixing is enabled
659 if (_outputFilePlaying)
660 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000661 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 }
663
664 // Place channel in on-hold state (~muted) if on-hold is activated
665 if (_outputIsOnHold)
666 {
667 AudioFrameOperations::Mute(audioFrame);
668 }
669
670 // External media
671 if (_outputExternalMedia)
672 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000673 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000674 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 if (_outputExternalMediaCallbackPtr)
676 {
677 _outputExternalMediaCallbackPtr->Process(
678 _channelId,
679 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000680 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000681 audioFrame.samples_per_channel_,
682 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000683 isStereo);
684 }
685 }
686
687 // Record playout if enabled
688 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000689 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000690
691 if (_outputFileRecording && _outputFileRecorderPtr)
692 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000693 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000694 }
695 }
696
697 // Measure audio level (0-9)
698 _outputAudioLevel.ComputeLevel(audioFrame);
699
700 return 0;
701}
702
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000703int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000704Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000705{
706 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
707 "Channel::NeededFrequency(id=%d)", id);
708
709 int highestNeeded = 0;
710
711 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000712 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000713
714 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000715 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000716 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000717 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 }
719 else
720 {
721 highestNeeded = receiveFrequency;
722 }
723
724 // Special case, if we're playing a file on the playout side
725 // we take that frequency into consideration as well
726 // This is not needed on sending side, since the codec will
727 // limit the spectrum anyway.
728 if (_outputFilePlaying)
729 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000730 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 if (_outputFilePlayerPtr && _outputFilePlaying)
732 {
733 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
734 {
735 highestNeeded=_outputFilePlayerPtr->Frequency();
736 }
737 }
738 }
739
740 return(highestNeeded);
741}
742
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000743int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000744Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000745 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000746 uint32_t instanceId,
747 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000748{
749 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
750 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
751 channelId, instanceId);
752
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000753 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000754 if (channel == NULL)
755 {
756 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
757 VoEId(instanceId,channelId),
758 "Channel::CreateChannel() unable to allocate memory for"
759 " channel");
760 return -1;
761 }
762 return 0;
763}
764
765void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000766Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000767{
768 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
769 "Channel::PlayNotification(id=%d, durationMs=%d)",
770 id, durationMs);
771
772 // Not implement yet
773}
774
775void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000776Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000777{
778 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
779 "Channel::RecordNotification(id=%d, durationMs=%d)",
780 id, durationMs);
781
782 // Not implement yet
783}
784
785void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000786Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000787{
788 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
789 "Channel::PlayFileEnded(id=%d)", id);
790
791 if (id == _inputFilePlayerId)
792 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000793 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
795 _inputFilePlaying = false;
796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
797 VoEId(_instanceId,_channelId),
798 "Channel::PlayFileEnded() => input file player module is"
799 " shutdown");
800 }
801 else if (id == _outputFilePlayerId)
802 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000803 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804
805 _outputFilePlaying = false;
806 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
807 VoEId(_instanceId,_channelId),
808 "Channel::PlayFileEnded() => output file player module is"
809 " shutdown");
810 }
811}
812
813void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000814Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000815{
816 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
817 "Channel::RecordFileEnded(id=%d)", id);
818
819 assert(id == _outputFileRecorderId);
820
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000821 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000822
823 _outputFileRecording = false;
824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
825 VoEId(_instanceId,_channelId),
826 "Channel::RecordFileEnded() => output file recorder module is"
827 " shutdown");
828}
829
pbos@webrtc.org92135212013-05-14 08:31:39 +0000830Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000831 uint32_t instanceId,
832 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
834 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000835 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000837 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000838 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000839 rtp_payload_registry_(
840 new RTPPayloadRegistry(channelId,
841 RTPPayloadStrategy::CreateStrategy(true))),
842 rtp_receive_statistics_(ReceiveStatistics::Create(
843 Clock::GetRealTimeClock())),
844 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
845 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
846 this, this, rtp_payload_registry_.get())),
847 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000848 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000849 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 _rtpDumpIn(*RtpDump::CreateRtpDump()),
851 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000854 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 _inputFilePlayerPtr(NULL),
856 _outputFilePlayerPtr(NULL),
857 _outputFileRecorderPtr(NULL),
858 // Avoid conflict with other channels by adding 1024 - 1026,
859 // won't use as much as 1024 channels.
860 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
861 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
862 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
863 _inputFilePlaying(false),
864 _outputFilePlaying(false),
865 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000866 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
867 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000868 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000869 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000870 _inputExternalMediaCallbackPtr(NULL),
871 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000872 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
873 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000874 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000875 playout_timestamp_rtp_(0),
876 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000877 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000878 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000879 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000880 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000881 _outputMixerPtr(NULL),
882 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000883 _moduleProcessThreadPtr(NULL),
884 _audioDeviceModulePtr(NULL),
885 _voiceEngineObserverPtr(NULL),
886 _callbackCritSectPtr(NULL),
887 _transportPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000888 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _rxVadObserverPtr(NULL),
890 _oldVadDecision(-1),
891 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 _rtpObserverPtr(NULL),
893 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000894 _outputIsOnHold(false),
895 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000896 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000897 _inputIsOnHold(false),
898 _playing(false),
899 _sending(false),
900 _receiving(false),
901 _mixFileWithMicrophone(false),
902 _rtpObserver(false),
903 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000904 _mute(false),
905 _panLeft(1.0f),
906 _panRight(1.0f),
907 _outputGain(1.0f),
908 _playOutbandDtmfEvent(false),
909 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000910 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000911 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000912 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000913 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 _rtpPacketTimedOut(false),
915 _rtpPacketTimeOutIsEnabled(false),
916 _rtpTimeOutSeconds(0),
917 _connectionObserver(false),
918 _connectionObserverPtr(NULL),
919 _countAliveDetections(0),
920 _countDeadDetections(0),
921 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000922 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000923 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000924 _previousTimestamp(0),
925 _recPacketDelayMs(20),
926 _RxVadDetection(false),
927 _rxApmIsEnabled(false),
928 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000929 _rxNsIsEnabled(false),
930 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000931{
932 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
933 "Channel::Channel() - ctor");
934 _inbandDtmfQueue.ResetDtmf();
935 _inbandDtmfGenerator.Init();
936 _outputAudioLevel.Clear();
937
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000938 RtpRtcp::Configuration configuration;
939 configuration.id = VoEModuleId(instanceId, channelId);
940 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000941 configuration.outgoing_transport = this;
942 configuration.rtcp_feedback = this;
943 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000944 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000945
946 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000947
948 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
949 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
950 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000951}
952
953Channel::~Channel()
954{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000955 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000956 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
957 "Channel::~Channel() - dtor");
958
959 if (_outputExternalMedia)
960 {
961 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
962 }
963 if (_inputExternalMedia)
964 {
965 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
966 }
967 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 StopPlayout();
969
970 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000971 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000972 if (_inputFilePlayerPtr)
973 {
974 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
975 _inputFilePlayerPtr->StopPlayingFile();
976 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
977 _inputFilePlayerPtr = NULL;
978 }
979 if (_outputFilePlayerPtr)
980 {
981 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
982 _outputFilePlayerPtr->StopPlayingFile();
983 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
984 _outputFilePlayerPtr = NULL;
985 }
986 if (_outputFileRecorderPtr)
987 {
988 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
989 _outputFileRecorderPtr->StopRecording();
990 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
991 _outputFileRecorderPtr = NULL;
992 }
993 }
994
995 // The order to safely shutdown modules in a channel is:
996 // 1. De-register callbacks in modules
997 // 2. De-register modules in process thread
998 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000999 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001000 {
1001 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1002 VoEId(_instanceId,_channelId),
1003 "~Channel() failed to de-register transport callback"
1004 " (Audio coding module)");
1005 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001006 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 {
1008 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1009 VoEId(_instanceId,_channelId),
1010 "~Channel() failed to de-register VAD callback"
1011 " (Audio coding module)");
1012 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001013 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001014 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 {
1016 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1017 VoEId(_instanceId,_channelId),
1018 "~Channel() failed to deregister RTP/RTCP module");
1019 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001020 // End of modules shutdown
1021
1022 // Delete other objects
1023 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1024 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001025 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001027 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001028}
1029
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001030int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001031Channel::Init()
1032{
1033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1034 "Channel::Init()");
1035
1036 // --- Initial sanity
1037
1038 if ((_engineStatisticsPtr == NULL) ||
1039 (_moduleProcessThreadPtr == NULL))
1040 {
1041 WEBRTC_TRACE(kTraceError, kTraceVoice,
1042 VoEId(_instanceId,_channelId),
1043 "Channel::Init() must call SetEngineInformation() first");
1044 return -1;
1045 }
1046
1047 // --- Add modules to process thread (for periodic schedulation)
1048
1049 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001050 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001052 if (processThreadFail)
1053 {
1054 _engineStatisticsPtr->SetLastError(
1055 VE_CANNOT_INIT_CHANNEL, kTraceError,
1056 "Channel::Init() modules not registered");
1057 return -1;
1058 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001059 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001060
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001061 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001062#ifdef WEBRTC_CODEC_AVT
1063 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001064 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001065#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001066 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 {
1068 _engineStatisticsPtr->SetLastError(
1069 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1070 "Channel::Init() unable to initialize the ACM - 1");
1071 return -1;
1072 }
1073
1074 // --- RTP/RTCP module initialization
1075
1076 // Ensure that RTCP is enabled by default for the created channel.
1077 // Note that, the module will keep generating RTCP until it is explicitly
1078 // disabled by the user.
1079 // After StopListen (when no sockets exists), RTCP packets will no longer
1080 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001081 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1082 // RTCP is enabled by default.
1083 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 {
1085 _engineStatisticsPtr->SetLastError(
1086 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1087 "Channel::Init() RTP/RTCP module not initialized");
1088 return -1;
1089 }
1090
1091 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001092 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001093 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1094 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001095
1096 if (fail)
1097 {
1098 _engineStatisticsPtr->SetLastError(
1099 VE_CANNOT_INIT_CHANNEL, kTraceError,
1100 "Channel::Init() callbacks not registered");
1101 return -1;
1102 }
1103
1104 // --- Register all supported codecs to the receiving side of the
1105 // RTP/RTCP module
1106
1107 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001108 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001109
1110 for (int idx = 0; idx < nSupportedCodecs; idx++)
1111 {
1112 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001113 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001114 (rtp_receiver_->RegisterReceivePayload(
1115 codec.plname,
1116 codec.pltype,
1117 codec.plfreq,
1118 codec.channels,
1119 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001120 {
1121 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1122 VoEId(_instanceId,_channelId),
1123 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1124 "to RTP/RTCP receiver",
1125 codec.plname, codec.pltype, codec.plfreq,
1126 codec.channels, codec.rate);
1127 }
1128 else
1129 {
1130 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1131 VoEId(_instanceId,_channelId),
1132 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1133 "the RTP/RTCP receiver",
1134 codec.plname, codec.pltype, codec.plfreq,
1135 codec.channels, codec.rate);
1136 }
1137
1138 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001139 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 {
1141 SetSendCodec(codec);
1142 }
1143
1144 // Register default PT for outband 'telephone-event'
1145 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1146 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001147 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001148 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 {
1150 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1151 VoEId(_instanceId,_channelId),
1152 "Channel::Init() failed to register outband "
1153 "'telephone-event' (%d/%d) correctly",
1154 codec.pltype, codec.plfreq);
1155 }
1156 }
1157
1158 if (!STR_CASE_CMP(codec.plname, "CN"))
1159 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001160 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1161 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001162 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001163 {
1164 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1165 VoEId(_instanceId,_channelId),
1166 "Channel::Init() failed to register CN (%d/%d) "
1167 "correctly - 1",
1168 codec.pltype, codec.plfreq);
1169 }
1170 }
1171#ifdef WEBRTC_CODEC_RED
1172 // Register RED to the receiving side of the ACM.
1173 // We will not receive an OnInitializeDecoder() callback for RED.
1174 if (!STR_CASE_CMP(codec.plname, "RED"))
1175 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001176 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001177 {
1178 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1179 VoEId(_instanceId,_channelId),
1180 "Channel::Init() failed to register RED (%d/%d) "
1181 "correctly",
1182 codec.pltype, codec.plfreq);
1183 }
1184 }
1185#endif
1186 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001187
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001188 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1189 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1190 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001192 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1193 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1194 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001195 }
1196
1197 return 0;
1198}
1199
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001200int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001201Channel::SetEngineInformation(Statistics& engineStatistics,
1202 OutputMixer& outputMixer,
1203 voe::TransmitMixer& transmitMixer,
1204 ProcessThread& moduleProcessThread,
1205 AudioDeviceModule& audioDeviceModule,
1206 VoiceEngineObserver* voiceEngineObserver,
1207 CriticalSectionWrapper* callbackCritSect)
1208{
1209 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1210 "Channel::SetEngineInformation()");
1211 _engineStatisticsPtr = &engineStatistics;
1212 _outputMixerPtr = &outputMixer;
1213 _transmitMixerPtr = &transmitMixer,
1214 _moduleProcessThreadPtr = &moduleProcessThread;
1215 _audioDeviceModulePtr = &audioDeviceModule;
1216 _voiceEngineObserverPtr = voiceEngineObserver;
1217 _callbackCritSectPtr = callbackCritSect;
1218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::UpdateLocalTimeStamp()
1223{
1224
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001225 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001226 return 0;
1227}
1228
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001229int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001230Channel::StartPlayout()
1231{
1232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1233 "Channel::StartPlayout()");
1234 if (_playing)
1235 {
1236 return 0;
1237 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001238
1239 if (!_externalMixing) {
1240 // Add participant as candidates for mixing.
1241 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1242 {
1243 _engineStatisticsPtr->SetLastError(
1244 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1245 "StartPlayout() failed to add participant to mixer");
1246 return -1;
1247 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001248 }
1249
1250 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001251
1252 if (RegisterFilePlayingToMixer() != 0)
1253 return -1;
1254
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 return 0;
1256}
1257
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001258int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001259Channel::StopPlayout()
1260{
1261 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1262 "Channel::StopPlayout()");
1263 if (!_playing)
1264 {
1265 return 0;
1266 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001267
1268 if (!_externalMixing) {
1269 // Remove participant as candidates for mixing
1270 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1271 {
1272 _engineStatisticsPtr->SetLastError(
1273 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1274 "StopPlayout() failed to remove participant from mixer");
1275 return -1;
1276 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 }
1278
1279 _playing = false;
1280 _outputAudioLevel.Clear();
1281
1282 return 0;
1283}
1284
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001285int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001286Channel::StartSend()
1287{
1288 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1289 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001290 // Resume the previous sequence number which was reset by StopSend().
1291 // This needs to be done before |_sending| is set to true.
1292 if (send_sequence_number_)
1293 SetInitSequenceNumber(send_sequence_number_);
1294
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001296 // A lock is needed because |_sending| can be accessed or modified by
1297 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001298 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001299
1300 if (_sending)
1301 {
1302 return 0;
1303 }
1304 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001305 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001306
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001307 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 {
1309 _engineStatisticsPtr->SetLastError(
1310 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1311 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001312 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001313 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 return -1;
1315 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001316
niklase@google.com470e71d2011-07-07 08:21:25 +00001317 return 0;
1318}
1319
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001320int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001321Channel::StopSend()
1322{
1323 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1324 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001326 // A lock is needed because |_sending| can be accessed or modified by
1327 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001328 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001329
1330 if (!_sending)
1331 {
1332 return 0;
1333 }
1334 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001335 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001336
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001337 // Store the sequence number to be able to pick up the same sequence for
1338 // the next StartSend(). This is needed for restarting device, otherwise
1339 // it might cause libSRTP to complain about packets being replayed.
1340 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1341 // CL is landed. See issue
1342 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1343 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1344
niklase@google.com470e71d2011-07-07 08:21:25 +00001345 // Reset sending SSRC and sequence number and triggers direct transmission
1346 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001347 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1348 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001349 {
1350 _engineStatisticsPtr->SetLastError(
1351 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1352 "StartSend() RTP/RTCP failed to stop sending");
1353 }
1354
niklase@google.com470e71d2011-07-07 08:21:25 +00001355 return 0;
1356}
1357
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001358int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001359Channel::StartReceiving()
1360{
1361 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1362 "Channel::StartReceiving()");
1363 if (_receiving)
1364 {
1365 return 0;
1366 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 _receiving = true;
1368 _numberOfDiscardedPackets = 0;
1369 return 0;
1370}
1371
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001372int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001373Channel::StopReceiving()
1374{
1375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1376 "Channel::StopReceiving()");
1377 if (!_receiving)
1378 {
1379 return 0;
1380 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001381
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001382 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001383 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001384 RegisterReceiveCodecsToRTPModule();
1385 _receiving = false;
1386 return 0;
1387}
1388
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001389int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001390Channel::SetNetEQPlayoutMode(NetEqModes mode)
1391{
1392 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1393 "Channel::SetNetEQPlayoutMode()");
1394 AudioPlayoutMode playoutMode(voice);
1395 switch (mode)
1396 {
1397 case kNetEqDefault:
1398 playoutMode = voice;
1399 break;
1400 case kNetEqStreaming:
1401 playoutMode = streaming;
1402 break;
1403 case kNetEqFax:
1404 playoutMode = fax;
1405 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001406 case kNetEqOff:
1407 playoutMode = off;
1408 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001410 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001411 {
1412 _engineStatisticsPtr->SetLastError(
1413 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1414 "SetNetEQPlayoutMode() failed to set playout mode");
1415 return -1;
1416 }
1417 return 0;
1418}
1419
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001420int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001421Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1422{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001423 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001424 switch (playoutMode)
1425 {
1426 case voice:
1427 mode = kNetEqDefault;
1428 break;
1429 case streaming:
1430 mode = kNetEqStreaming;
1431 break;
1432 case fax:
1433 mode = kNetEqFax;
1434 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001435 case off:
1436 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001437 }
1438 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1439 VoEId(_instanceId,_channelId),
1440 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1441 return 0;
1442}
1443
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001445Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1446{
1447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1448 "Channel::SetOnHoldStatus()");
1449 if (mode == kHoldSendAndPlay)
1450 {
1451 _outputIsOnHold = enable;
1452 _inputIsOnHold = enable;
1453 }
1454 else if (mode == kHoldPlayOnly)
1455 {
1456 _outputIsOnHold = enable;
1457 }
1458 if (mode == kHoldSendOnly)
1459 {
1460 _inputIsOnHold = enable;
1461 }
1462 return 0;
1463}
1464
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001465int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001466Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1467{
1468 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1469 "Channel::GetOnHoldStatus()");
1470 enabled = (_outputIsOnHold || _inputIsOnHold);
1471 if (_outputIsOnHold && _inputIsOnHold)
1472 {
1473 mode = kHoldSendAndPlay;
1474 }
1475 else if (_outputIsOnHold && !_inputIsOnHold)
1476 {
1477 mode = kHoldPlayOnly;
1478 }
1479 else if (!_outputIsOnHold && _inputIsOnHold)
1480 {
1481 mode = kHoldSendOnly;
1482 }
1483 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1484 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1485 enabled, mode);
1486 return 0;
1487}
1488
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001489int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001490Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1491{
1492 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1493 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001494 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001495
1496 if (_voiceEngineObserverPtr)
1497 {
1498 _engineStatisticsPtr->SetLastError(
1499 VE_INVALID_OPERATION, kTraceError,
1500 "RegisterVoiceEngineObserver() observer already enabled");
1501 return -1;
1502 }
1503 _voiceEngineObserverPtr = &observer;
1504 return 0;
1505}
1506
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001507int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001508Channel::DeRegisterVoiceEngineObserver()
1509{
1510 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1511 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001512 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001513
1514 if (!_voiceEngineObserverPtr)
1515 {
1516 _engineStatisticsPtr->SetLastError(
1517 VE_INVALID_OPERATION, kTraceWarning,
1518 "DeRegisterVoiceEngineObserver() observer already disabled");
1519 return 0;
1520 }
1521 _voiceEngineObserverPtr = NULL;
1522 return 0;
1523}
1524
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001525int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001526Channel::GetSendCodec(CodecInst& codec)
1527{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001528 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001529}
1530
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001531int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001532Channel::GetRecCodec(CodecInst& codec)
1533{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001534 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001535}
1536
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001537int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001538Channel::SetSendCodec(const CodecInst& codec)
1539{
1540 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1541 "Channel::SetSendCodec()");
1542
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001543 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001544 {
1545 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1546 "SetSendCodec() failed to register codec to ACM");
1547 return -1;
1548 }
1549
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001550 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001551 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001552 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1553 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001554 {
1555 WEBRTC_TRACE(
1556 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1557 "SetSendCodec() failed to register codec to"
1558 " RTP/RTCP module");
1559 return -1;
1560 }
1561 }
1562
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001563 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001564 {
1565 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1566 "SetSendCodec() failed to set audio packet size");
1567 return -1;
1568 }
1569
1570 return 0;
1571}
1572
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001573int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001574Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1575{
1576 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1577 "Channel::SetVADStatus(mode=%d)", mode);
1578 // To disable VAD, DTX must be disabled too
1579 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001580 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001581 {
1582 _engineStatisticsPtr->SetLastError(
1583 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1584 "SetVADStatus() failed to set VAD");
1585 return -1;
1586 }
1587 return 0;
1588}
1589
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001590int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001591Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1592{
1593 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1594 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001595 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001596 {
1597 _engineStatisticsPtr->SetLastError(
1598 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1599 "GetVADStatus() failed to get VAD status");
1600 return -1;
1601 }
1602 disabledDTX = !disabledDTX;
1603 return 0;
1604}
1605
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001606int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001607Channel::SetRecPayloadType(const CodecInst& codec)
1608{
1609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1610 "Channel::SetRecPayloadType()");
1611
1612 if (_playing)
1613 {
1614 _engineStatisticsPtr->SetLastError(
1615 VE_ALREADY_PLAYING, kTraceError,
1616 "SetRecPayloadType() unable to set PT while playing");
1617 return -1;
1618 }
1619 if (_receiving)
1620 {
1621 _engineStatisticsPtr->SetLastError(
1622 VE_ALREADY_LISTENING, kTraceError,
1623 "SetRecPayloadType() unable to set PT while listening");
1624 return -1;
1625 }
1626
1627 if (codec.pltype == -1)
1628 {
1629 // De-register the selected codec (RTP/RTCP module and ACM)
1630
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001631 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001632 CodecInst rxCodec = codec;
1633
1634 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001635 rtp_payload_registry_->ReceivePayloadType(
1636 rxCodec.plname,
1637 rxCodec.plfreq,
1638 rxCodec.channels,
1639 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1640 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001641 rxCodec.pltype = pltype;
1642
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001643 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001644 {
1645 _engineStatisticsPtr->SetLastError(
1646 VE_RTP_RTCP_MODULE_ERROR,
1647 kTraceError,
1648 "SetRecPayloadType() RTP/RTCP-module deregistration "
1649 "failed");
1650 return -1;
1651 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001652 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001653 {
1654 _engineStatisticsPtr->SetLastError(
1655 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1656 "SetRecPayloadType() ACM deregistration failed - 1");
1657 return -1;
1658 }
1659 return 0;
1660 }
1661
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001662 if (rtp_receiver_->RegisterReceivePayload(
1663 codec.plname,
1664 codec.pltype,
1665 codec.plfreq,
1666 codec.channels,
1667 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 {
1669 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001670 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1671 if (rtp_receiver_->RegisterReceivePayload(
1672 codec.plname,
1673 codec.pltype,
1674 codec.plfreq,
1675 codec.channels,
1676 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001677 {
1678 _engineStatisticsPtr->SetLastError(
1679 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1680 "SetRecPayloadType() RTP/RTCP-module registration failed");
1681 return -1;
1682 }
1683 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001684 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001685 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001686 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1687 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001688 {
1689 _engineStatisticsPtr->SetLastError(
1690 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1691 "SetRecPayloadType() ACM registration failed - 1");
1692 return -1;
1693 }
1694 }
1695 return 0;
1696}
1697
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001698int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001699Channel::GetRecPayloadType(CodecInst& codec)
1700{
1701 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1702 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001703 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001704 if (rtp_payload_registry_->ReceivePayloadType(
1705 codec.plname,
1706 codec.plfreq,
1707 codec.channels,
1708 (codec.rate < 0) ? 0 : codec.rate,
1709 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001710 {
1711 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001712 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001713 "GetRecPayloadType() failed to retrieve RX payload type");
1714 return -1;
1715 }
1716 codec.pltype = payloadType;
1717 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1718 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1719 return 0;
1720}
1721
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001722int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001723Channel::SetAMREncFormat(AmrMode mode)
1724{
1725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726 "Channel::SetAMREncFormat()");
1727
1728 // ACM doesn't support AMR
1729 return -1;
1730}
1731
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001732int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001733Channel::SetAMRDecFormat(AmrMode mode)
1734{
1735 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1736 "Channel::SetAMRDecFormat()");
1737
1738 // ACM doesn't support AMR
1739 return -1;
1740}
1741
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001742int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001743Channel::SetAMRWbEncFormat(AmrMode mode)
1744{
1745 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1746 "Channel::SetAMRWbEncFormat()");
1747
1748 // ACM doesn't support AMR
1749 return -1;
1750
1751}
1752
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001753int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001754Channel::SetAMRWbDecFormat(AmrMode mode)
1755{
1756 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1757 "Channel::SetAMRWbDecFormat()");
1758
1759 // ACM doesn't support AMR
1760 return -1;
1761}
1762
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001763int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001764Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1765{
1766 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1767 "Channel::SetSendCNPayloadType()");
1768
1769 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001770 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001771 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001772 if (frequency == kFreq32000Hz)
1773 samplingFreqHz = 32000;
1774 else if (frequency == kFreq16000Hz)
1775 samplingFreqHz = 16000;
1776
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001777 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001778 {
1779 _engineStatisticsPtr->SetLastError(
1780 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1781 "SetSendCNPayloadType() failed to retrieve default CN codec "
1782 "settings");
1783 return -1;
1784 }
1785
1786 // Modify the payload type (must be set to dynamic range)
1787 codec.pltype = type;
1788
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001789 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001790 {
1791 _engineStatisticsPtr->SetLastError(
1792 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1793 "SetSendCNPayloadType() failed to register CN to ACM");
1794 return -1;
1795 }
1796
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001797 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001798 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001799 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1800 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001801 {
1802 _engineStatisticsPtr->SetLastError(
1803 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1804 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1805 "module");
1806 return -1;
1807 }
1808 }
1809 return 0;
1810}
1811
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001812int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001813Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1814{
1815 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1816 "Channel::SetISACInitTargetRate()");
1817
1818 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001819 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001820 {
1821 _engineStatisticsPtr->SetLastError(
1822 VE_CODEC_ERROR, kTraceError,
1823 "SetISACInitTargetRate() failed to retrieve send codec");
1824 return -1;
1825 }
1826 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1827 {
1828 // This API is only valid if iSAC is setup to run in channel-adaptive
1829 // mode.
1830 // We do not validate the adaptive mode here. It is done later in the
1831 // ConfigISACBandwidthEstimator() API.
1832 _engineStatisticsPtr->SetLastError(
1833 VE_CODEC_ERROR, kTraceError,
1834 "SetISACInitTargetRate() send codec is not iSAC");
1835 return -1;
1836 }
1837
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001838 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001839 if (16000 == sendCodec.plfreq)
1840 {
1841 // Note that 0 is a valid and corresponds to "use default
1842 if ((rateBps != 0 &&
1843 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1844 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1845 {
1846 _engineStatisticsPtr->SetLastError(
1847 VE_INVALID_ARGUMENT, kTraceError,
1848 "SetISACInitTargetRate() invalid target rate - 1");
1849 return -1;
1850 }
1851 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001852 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001853 }
1854 else if (32000 == sendCodec.plfreq)
1855 {
1856 if ((rateBps != 0 &&
1857 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1858 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1859 {
1860 _engineStatisticsPtr->SetLastError(
1861 VE_INVALID_ARGUMENT, kTraceError,
1862 "SetISACInitTargetRate() invalid target rate - 2");
1863 return -1;
1864 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001865 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001866 }
1867
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001868 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001869 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1870 {
1871 _engineStatisticsPtr->SetLastError(
1872 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1873 "SetISACInitTargetRate() iSAC BWE config failed");
1874 return -1;
1875 }
1876
1877 return 0;
1878}
1879
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001880int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001881Channel::SetISACMaxRate(int rateBps)
1882{
1883 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1884 "Channel::SetISACMaxRate()");
1885
1886 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001887 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001888 {
1889 _engineStatisticsPtr->SetLastError(
1890 VE_CODEC_ERROR, kTraceError,
1891 "SetISACMaxRate() failed to retrieve send codec");
1892 return -1;
1893 }
1894 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1895 {
1896 // This API is only valid if iSAC is selected as sending codec.
1897 _engineStatisticsPtr->SetLastError(
1898 VE_CODEC_ERROR, kTraceError,
1899 "SetISACMaxRate() send codec is not iSAC");
1900 return -1;
1901 }
1902 if (16000 == sendCodec.plfreq)
1903 {
1904 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1905 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1906 {
1907 _engineStatisticsPtr->SetLastError(
1908 VE_INVALID_ARGUMENT, kTraceError,
1909 "SetISACMaxRate() invalid max rate - 1");
1910 return -1;
1911 }
1912 }
1913 else if (32000 == sendCodec.plfreq)
1914 {
1915 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1916 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_INVALID_ARGUMENT, kTraceError,
1920 "SetISACMaxRate() invalid max rate - 2");
1921 return -1;
1922 }
1923 }
1924 if (_sending)
1925 {
1926 _engineStatisticsPtr->SetLastError(
1927 VE_SENDING, kTraceError,
1928 "SetISACMaxRate() unable to set max rate while sending");
1929 return -1;
1930 }
1931
1932 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1933 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001934 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 {
1936 _engineStatisticsPtr->SetLastError(
1937 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1938 "SetISACMaxRate() failed to set max rate");
1939 return -1;
1940 }
1941
1942 return 0;
1943}
1944
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001945int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001946Channel::SetISACMaxPayloadSize(int sizeBytes)
1947{
1948 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1949 "Channel::SetISACMaxPayloadSize()");
1950 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001951 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001952 {
1953 _engineStatisticsPtr->SetLastError(
1954 VE_CODEC_ERROR, kTraceError,
1955 "SetISACMaxPayloadSize() failed to retrieve send codec");
1956 return -1;
1957 }
1958 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1959 {
1960 _engineStatisticsPtr->SetLastError(
1961 VE_CODEC_ERROR, kTraceError,
1962 "SetISACMaxPayloadSize() send codec is not iSAC");
1963 return -1;
1964 }
1965 if (16000 == sendCodec.plfreq)
1966 {
1967 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1968 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1969 {
1970 _engineStatisticsPtr->SetLastError(
1971 VE_INVALID_ARGUMENT, kTraceError,
1972 "SetISACMaxPayloadSize() invalid max payload - 1");
1973 return -1;
1974 }
1975 }
1976 else if (32000 == sendCodec.plfreq)
1977 {
1978 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1979 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1980 {
1981 _engineStatisticsPtr->SetLastError(
1982 VE_INVALID_ARGUMENT, kTraceError,
1983 "SetISACMaxPayloadSize() invalid max payload - 2");
1984 return -1;
1985 }
1986 }
1987 if (_sending)
1988 {
1989 _engineStatisticsPtr->SetLastError(
1990 VE_SENDING, kTraceError,
1991 "SetISACMaxPayloadSize() unable to set max rate while sending");
1992 return -1;
1993 }
1994
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001995 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001996 {
1997 _engineStatisticsPtr->SetLastError(
1998 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1999 "SetISACMaxPayloadSize() failed to set max payload size");
2000 return -1;
2001 }
2002 return 0;
2003}
2004
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002005int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002006{
2007 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2008 "Channel::RegisterExternalTransport()");
2009
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002010 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002011
niklase@google.com470e71d2011-07-07 08:21:25 +00002012 if (_externalTransport)
2013 {
2014 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2015 kTraceError,
2016 "RegisterExternalTransport() external transport already enabled");
2017 return -1;
2018 }
2019 _externalTransport = true;
2020 _transportPtr = &transport;
2021 return 0;
2022}
2023
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002024int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002025Channel::DeRegisterExternalTransport()
2026{
2027 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2028 "Channel::DeRegisterExternalTransport()");
2029
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002030 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002031
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 if (!_transportPtr)
2033 {
2034 _engineStatisticsPtr->SetLastError(
2035 VE_INVALID_OPERATION, kTraceWarning,
2036 "DeRegisterExternalTransport() external transport already "
2037 "disabled");
2038 return 0;
2039 }
2040 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002041 _transportPtr = NULL;
2042 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2043 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002044 return 0;
2045}
2046
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002047int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002048 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2049 "Channel::ReceivedRTPPacket()");
2050
2051 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002052 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002053
2054 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002055 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2056 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002057 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2058 VoEId(_instanceId,_channelId),
2059 "Channel::SendPacket() RTP dump to input file failed");
2060 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002061 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002062 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002063 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2064 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2065 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002066 return -1;
2067 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002068 header.payload_type_frequency =
2069 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002070 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002071 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002072 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002073 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002074 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002075 rtp_payload_registry_->SetIncomingPayloadType(header);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002076 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002077}
2078
2079bool Channel::ReceivePacket(const uint8_t* packet,
2080 int packet_length,
2081 const RTPHeader& header,
2082 bool in_order) {
2083 if (rtp_payload_registry_->IsEncapsulated(header)) {
2084 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002085 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002086 const uint8_t* payload = packet + header.headerLength;
2087 int payload_length = packet_length - header.headerLength;
2088 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002089 PayloadUnion payload_specific;
2090 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002091 &payload_specific)) {
2092 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002093 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002094 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2095 payload_specific, in_order);
2096}
2097
2098bool Channel::HandleEncapsulation(const uint8_t* packet,
2099 int packet_length,
2100 const RTPHeader& header) {
2101 if (!rtp_payload_registry_->IsRtx(header))
2102 return false;
2103
2104 // Remove the RTX header and parse the original RTP header.
2105 if (packet_length < header.headerLength)
2106 return false;
2107 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2108 return false;
2109 if (restored_packet_in_use_) {
2110 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2111 "Multiple RTX headers detected, dropping packet");
2112 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002113 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002114 uint8_t* restored_packet_ptr = restored_packet_;
2115 if (!rtp_payload_registry_->RestoreOriginalPacket(
2116 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2117 header)) {
2118 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2119 "Incoming RTX packet: invalid RTP header");
2120 return false;
2121 }
2122 restored_packet_in_use_ = true;
2123 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2124 restored_packet_in_use_ = false;
2125 return ret;
2126}
2127
2128bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2129 StreamStatistician* statistician =
2130 rtp_receive_statistics_->GetStatistician(header.ssrc);
2131 if (!statistician)
2132 return false;
2133 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002134}
2135
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002136bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2137 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002138 // Retransmissions are handled separately if RTX is enabled.
2139 if (rtp_payload_registry_->RtxEnabled())
2140 return false;
2141 StreamStatistician* statistician =
2142 rtp_receive_statistics_->GetStatistician(header.ssrc);
2143 if (!statistician)
2144 return false;
2145 // Check if this is a retransmission.
2146 uint16_t min_rtt = 0;
2147 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002148 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002149 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002150}
2151
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002152int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002153 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2154 "Channel::ReceivedRTCPPacket()");
2155 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002156 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002157
2158 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002159 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2160 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002161 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2162 VoEId(_instanceId,_channelId),
2163 "Channel::SendPacket() RTCP dump to input file failed");
2164 }
2165
2166 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002167 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2168 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002169 _engineStatisticsPtr->SetLastError(
2170 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2171 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2172 }
2173 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002174}
2175
niklase@google.com470e71d2011-07-07 08:21:25 +00002176int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002177 bool loop,
2178 FileFormats format,
2179 int startPosition,
2180 float volumeScaling,
2181 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002182 const CodecInst* codecInst)
2183{
2184 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2185 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2186 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2187 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2188 startPosition, stopPosition);
2189
2190 if (_outputFilePlaying)
2191 {
2192 _engineStatisticsPtr->SetLastError(
2193 VE_ALREADY_PLAYING, kTraceError,
2194 "StartPlayingFileLocally() is already playing");
2195 return -1;
2196 }
2197
niklase@google.com470e71d2011-07-07 08:21:25 +00002198 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002199 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002200
2201 if (_outputFilePlayerPtr)
2202 {
2203 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2204 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2205 _outputFilePlayerPtr = NULL;
2206 }
2207
2208 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2209 _outputFilePlayerId, (const FileFormats)format);
2210
2211 if (_outputFilePlayerPtr == NULL)
2212 {
2213 _engineStatisticsPtr->SetLastError(
2214 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002215 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002216 return -1;
2217 }
2218
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002219 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002220
2221 if (_outputFilePlayerPtr->StartPlayingFile(
2222 fileName,
2223 loop,
2224 startPosition,
2225 volumeScaling,
2226 notificationTime,
2227 stopPosition,
2228 (const CodecInst*)codecInst) != 0)
2229 {
2230 _engineStatisticsPtr->SetLastError(
2231 VE_BAD_FILE, kTraceError,
2232 "StartPlayingFile() failed to start file playout");
2233 _outputFilePlayerPtr->StopPlayingFile();
2234 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2235 _outputFilePlayerPtr = NULL;
2236 return -1;
2237 }
2238 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2239 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002240 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002241
2242 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002243 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002244
2245 return 0;
2246}
2247
2248int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002249 FileFormats format,
2250 int startPosition,
2251 float volumeScaling,
2252 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002253 const CodecInst* codecInst)
2254{
2255 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2256 "Channel::StartPlayingFileLocally(format=%d,"
2257 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2258 format, volumeScaling, startPosition, stopPosition);
2259
2260 if(stream == NULL)
2261 {
2262 _engineStatisticsPtr->SetLastError(
2263 VE_BAD_FILE, kTraceError,
2264 "StartPlayingFileLocally() NULL as input stream");
2265 return -1;
2266 }
2267
2268
2269 if (_outputFilePlaying)
2270 {
2271 _engineStatisticsPtr->SetLastError(
2272 VE_ALREADY_PLAYING, kTraceError,
2273 "StartPlayingFileLocally() is already playing");
2274 return -1;
2275 }
2276
niklase@google.com470e71d2011-07-07 08:21:25 +00002277 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002278 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002279
2280 // Destroy the old instance
2281 if (_outputFilePlayerPtr)
2282 {
2283 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2284 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2285 _outputFilePlayerPtr = NULL;
2286 }
2287
2288 // Create the instance
2289 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2290 _outputFilePlayerId,
2291 (const FileFormats)format);
2292
2293 if (_outputFilePlayerPtr == NULL)
2294 {
2295 _engineStatisticsPtr->SetLastError(
2296 VE_INVALID_ARGUMENT, kTraceError,
2297 "StartPlayingFileLocally() filePlayer format isnot correct");
2298 return -1;
2299 }
2300
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002301 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002302
2303 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2304 volumeScaling,
2305 notificationTime,
2306 stopPosition, codecInst) != 0)
2307 {
2308 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2309 "StartPlayingFile() failed to "
2310 "start file playout");
2311 _outputFilePlayerPtr->StopPlayingFile();
2312 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2313 _outputFilePlayerPtr = NULL;
2314 return -1;
2315 }
2316 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2317 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002318 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002319
2320 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002321 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002322
niklase@google.com470e71d2011-07-07 08:21:25 +00002323 return 0;
2324}
2325
2326int Channel::StopPlayingFileLocally()
2327{
2328 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2329 "Channel::StopPlayingFileLocally()");
2330
2331 if (!_outputFilePlaying)
2332 {
2333 _engineStatisticsPtr->SetLastError(
2334 VE_INVALID_OPERATION, kTraceWarning,
2335 "StopPlayingFileLocally() isnot playing");
2336 return 0;
2337 }
2338
niklase@google.com470e71d2011-07-07 08:21:25 +00002339 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002340 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002341
2342 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2343 {
2344 _engineStatisticsPtr->SetLastError(
2345 VE_STOP_RECORDING_FAILED, kTraceError,
2346 "StopPlayingFile() could not stop playing");
2347 return -1;
2348 }
2349 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2350 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2351 _outputFilePlayerPtr = NULL;
2352 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002353 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002354 // _fileCritSect cannot be taken while calling
2355 // SetAnonymousMixibilityStatus. Refer to comments in
2356 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002357 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2358 {
2359 _engineStatisticsPtr->SetLastError(
2360 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002361 "StopPlayingFile() failed to stop participant from playing as"
2362 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002363 return -1;
2364 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002365
2366 return 0;
2367}
2368
2369int Channel::IsPlayingFileLocally() const
2370{
2371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2372 "Channel::IsPlayingFileLocally()");
2373
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002374 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002375}
2376
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002377int Channel::RegisterFilePlayingToMixer()
2378{
2379 // Return success for not registering for file playing to mixer if:
2380 // 1. playing file before playout is started on that channel.
2381 // 2. starting playout without file playing on that channel.
2382 if (!_playing || !_outputFilePlaying)
2383 {
2384 return 0;
2385 }
2386
2387 // |_fileCritSect| cannot be taken while calling
2388 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2389 // frames can be pulled by the mixer. Since the frames are generated from
2390 // the file, _fileCritSect will be taken. This would result in a deadlock.
2391 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2392 {
2393 CriticalSectionScoped cs(&_fileCritSect);
2394 _outputFilePlaying = false;
2395 _engineStatisticsPtr->SetLastError(
2396 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2397 "StartPlayingFile() failed to add participant as file to mixer");
2398 _outputFilePlayerPtr->StopPlayingFile();
2399 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2400 _outputFilePlayerPtr = NULL;
2401 return -1;
2402 }
2403
2404 return 0;
2405}
2406
pbos@webrtc.org92135212013-05-14 08:31:39 +00002407int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002408{
2409 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2410 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2411
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002412 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002413
2414 if (!_outputFilePlaying)
2415 {
2416 _engineStatisticsPtr->SetLastError(
2417 VE_INVALID_OPERATION, kTraceError,
2418 "ScaleLocalFilePlayout() isnot playing");
2419 return -1;
2420 }
2421 if ((_outputFilePlayerPtr == NULL) ||
2422 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2423 {
2424 _engineStatisticsPtr->SetLastError(
2425 VE_BAD_ARGUMENT, kTraceError,
2426 "SetAudioScaling() failed to scale the playout");
2427 return -1;
2428 }
2429
2430 return 0;
2431}
2432
2433int Channel::GetLocalPlayoutPosition(int& positionMs)
2434{
2435 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2436 "Channel::GetLocalPlayoutPosition(position=?)");
2437
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002438 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002439
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002440 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002441
2442 if (_outputFilePlayerPtr == NULL)
2443 {
2444 _engineStatisticsPtr->SetLastError(
2445 VE_INVALID_OPERATION, kTraceError,
2446 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2447 return -1;
2448 }
2449
2450 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2451 {
2452 _engineStatisticsPtr->SetLastError(
2453 VE_BAD_FILE, kTraceError,
2454 "GetLocalPlayoutPosition() failed");
2455 return -1;
2456 }
2457 positionMs = position;
2458
2459 return 0;
2460}
2461
2462int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002463 bool loop,
2464 FileFormats format,
2465 int startPosition,
2466 float volumeScaling,
2467 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002468 const CodecInst* codecInst)
2469{
2470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2471 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2472 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2473 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2474 startPosition, stopPosition);
2475
2476 if (_inputFilePlaying)
2477 {
2478 _engineStatisticsPtr->SetLastError(
2479 VE_ALREADY_PLAYING, kTraceWarning,
2480 "StartPlayingFileAsMicrophone() filePlayer is playing");
2481 return 0;
2482 }
2483
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002484 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002485
2486 // Destroy the old instance
2487 if (_inputFilePlayerPtr)
2488 {
2489 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2490 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2491 _inputFilePlayerPtr = NULL;
2492 }
2493
2494 // Create the instance
2495 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2496 _inputFilePlayerId, (const FileFormats)format);
2497
2498 if (_inputFilePlayerPtr == NULL)
2499 {
2500 _engineStatisticsPtr->SetLastError(
2501 VE_INVALID_ARGUMENT, kTraceError,
2502 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2503 return -1;
2504 }
2505
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002506 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002507
2508 if (_inputFilePlayerPtr->StartPlayingFile(
2509 fileName,
2510 loop,
2511 startPosition,
2512 volumeScaling,
2513 notificationTime,
2514 stopPosition,
2515 (const CodecInst*)codecInst) != 0)
2516 {
2517 _engineStatisticsPtr->SetLastError(
2518 VE_BAD_FILE, kTraceError,
2519 "StartPlayingFile() failed to start file playout");
2520 _inputFilePlayerPtr->StopPlayingFile();
2521 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2522 _inputFilePlayerPtr = NULL;
2523 return -1;
2524 }
2525 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2526 _inputFilePlaying = true;
2527
2528 return 0;
2529}
2530
2531int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002532 FileFormats format,
2533 int startPosition,
2534 float volumeScaling,
2535 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002536 const CodecInst* codecInst)
2537{
2538 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2539 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2540 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2541 format, volumeScaling, startPosition, stopPosition);
2542
2543 if(stream == NULL)
2544 {
2545 _engineStatisticsPtr->SetLastError(
2546 VE_BAD_FILE, kTraceError,
2547 "StartPlayingFileAsMicrophone NULL as input stream");
2548 return -1;
2549 }
2550
2551 if (_inputFilePlaying)
2552 {
2553 _engineStatisticsPtr->SetLastError(
2554 VE_ALREADY_PLAYING, kTraceWarning,
2555 "StartPlayingFileAsMicrophone() is playing");
2556 return 0;
2557 }
2558
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002559 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002560
2561 // Destroy the old instance
2562 if (_inputFilePlayerPtr)
2563 {
2564 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2565 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2566 _inputFilePlayerPtr = NULL;
2567 }
2568
2569 // Create the instance
2570 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2571 _inputFilePlayerId, (const FileFormats)format);
2572
2573 if (_inputFilePlayerPtr == NULL)
2574 {
2575 _engineStatisticsPtr->SetLastError(
2576 VE_INVALID_ARGUMENT, kTraceError,
2577 "StartPlayingInputFile() filePlayer format isnot correct");
2578 return -1;
2579 }
2580
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002581 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002582
2583 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2584 volumeScaling, notificationTime,
2585 stopPosition, codecInst) != 0)
2586 {
2587 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2588 "StartPlayingFile() failed to start "
2589 "file playout");
2590 _inputFilePlayerPtr->StopPlayingFile();
2591 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2592 _inputFilePlayerPtr = NULL;
2593 return -1;
2594 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002595
niklase@google.com470e71d2011-07-07 08:21:25 +00002596 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2597 _inputFilePlaying = true;
2598
2599 return 0;
2600}
2601
2602int Channel::StopPlayingFileAsMicrophone()
2603{
2604 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2605 "Channel::StopPlayingFileAsMicrophone()");
2606
2607 if (!_inputFilePlaying)
2608 {
2609 _engineStatisticsPtr->SetLastError(
2610 VE_INVALID_OPERATION, kTraceWarning,
2611 "StopPlayingFileAsMicrophone() isnot playing");
2612 return 0;
2613 }
2614
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002615 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002616 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2617 {
2618 _engineStatisticsPtr->SetLastError(
2619 VE_STOP_RECORDING_FAILED, kTraceError,
2620 "StopPlayingFile() could not stop playing");
2621 return -1;
2622 }
2623 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2624 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2625 _inputFilePlayerPtr = NULL;
2626 _inputFilePlaying = false;
2627
2628 return 0;
2629}
2630
2631int Channel::IsPlayingFileAsMicrophone() const
2632{
2633 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2634 "Channel::IsPlayingFileAsMicrophone()");
2635
2636 return _inputFilePlaying;
2637}
2638
pbos@webrtc.org92135212013-05-14 08:31:39 +00002639int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002640{
2641 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2642 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2643
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002644 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002645
2646 if (!_inputFilePlaying)
2647 {
2648 _engineStatisticsPtr->SetLastError(
2649 VE_INVALID_OPERATION, kTraceError,
2650 "ScaleFileAsMicrophonePlayout() isnot playing");
2651 return -1;
2652 }
2653
2654 if ((_inputFilePlayerPtr == NULL) ||
2655 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2656 {
2657 _engineStatisticsPtr->SetLastError(
2658 VE_BAD_ARGUMENT, kTraceError,
2659 "SetAudioScaling() failed to scale playout");
2660 return -1;
2661 }
2662
2663 return 0;
2664}
2665
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002666int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002667 const CodecInst* codecInst)
2668{
2669 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2670 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2671
2672 if (_outputFileRecording)
2673 {
2674 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2675 "StartRecordingPlayout() is already recording");
2676 return 0;
2677 }
2678
2679 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002680 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002681 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2682
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002683 if ((codecInst != NULL) &&
2684 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002685 {
2686 _engineStatisticsPtr->SetLastError(
2687 VE_BAD_ARGUMENT, kTraceError,
2688 "StartRecordingPlayout() invalid compression");
2689 return(-1);
2690 }
2691 if(codecInst == NULL)
2692 {
2693 format = kFileFormatPcm16kHzFile;
2694 codecInst=&dummyCodec;
2695 }
2696 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2697 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2698 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2699 {
2700 format = kFileFormatWavFile;
2701 }
2702 else
2703 {
2704 format = kFileFormatCompressedFile;
2705 }
2706
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002707 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002708
2709 // Destroy the old instance
2710 if (_outputFileRecorderPtr)
2711 {
2712 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2713 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2714 _outputFileRecorderPtr = NULL;
2715 }
2716
2717 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2718 _outputFileRecorderId, (const FileFormats)format);
2719 if (_outputFileRecorderPtr == NULL)
2720 {
2721 _engineStatisticsPtr->SetLastError(
2722 VE_INVALID_ARGUMENT, kTraceError,
2723 "StartRecordingPlayout() fileRecorder format isnot correct");
2724 return -1;
2725 }
2726
2727 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2728 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2729 {
2730 _engineStatisticsPtr->SetLastError(
2731 VE_BAD_FILE, kTraceError,
2732 "StartRecordingAudioFile() failed to start file recording");
2733 _outputFileRecorderPtr->StopRecording();
2734 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2735 _outputFileRecorderPtr = NULL;
2736 return -1;
2737 }
2738 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2739 _outputFileRecording = true;
2740
2741 return 0;
2742}
2743
2744int Channel::StartRecordingPlayout(OutStream* stream,
2745 const CodecInst* codecInst)
2746{
2747 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2748 "Channel::StartRecordingPlayout()");
2749
2750 if (_outputFileRecording)
2751 {
2752 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2753 "StartRecordingPlayout() is already recording");
2754 return 0;
2755 }
2756
2757 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002758 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002759 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2760
2761 if (codecInst != NULL && codecInst->channels != 1)
2762 {
2763 _engineStatisticsPtr->SetLastError(
2764 VE_BAD_ARGUMENT, kTraceError,
2765 "StartRecordingPlayout() invalid compression");
2766 return(-1);
2767 }
2768 if(codecInst == NULL)
2769 {
2770 format = kFileFormatPcm16kHzFile;
2771 codecInst=&dummyCodec;
2772 }
2773 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2774 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2775 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2776 {
2777 format = kFileFormatWavFile;
2778 }
2779 else
2780 {
2781 format = kFileFormatCompressedFile;
2782 }
2783
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002784 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002785
2786 // Destroy the old instance
2787 if (_outputFileRecorderPtr)
2788 {
2789 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2790 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2791 _outputFileRecorderPtr = NULL;
2792 }
2793
2794 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2795 _outputFileRecorderId, (const FileFormats)format);
2796 if (_outputFileRecorderPtr == NULL)
2797 {
2798 _engineStatisticsPtr->SetLastError(
2799 VE_INVALID_ARGUMENT, kTraceError,
2800 "StartRecordingPlayout() fileRecorder format isnot correct");
2801 return -1;
2802 }
2803
2804 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2805 notificationTime) != 0)
2806 {
2807 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2808 "StartRecordingPlayout() failed to "
2809 "start file recording");
2810 _outputFileRecorderPtr->StopRecording();
2811 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2812 _outputFileRecorderPtr = NULL;
2813 return -1;
2814 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002815
niklase@google.com470e71d2011-07-07 08:21:25 +00002816 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2817 _outputFileRecording = true;
2818
2819 return 0;
2820}
2821
2822int Channel::StopRecordingPlayout()
2823{
2824 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2825 "Channel::StopRecordingPlayout()");
2826
2827 if (!_outputFileRecording)
2828 {
2829 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2830 "StopRecordingPlayout() isnot recording");
2831 return -1;
2832 }
2833
2834
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002835 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002836
2837 if (_outputFileRecorderPtr->StopRecording() != 0)
2838 {
2839 _engineStatisticsPtr->SetLastError(
2840 VE_STOP_RECORDING_FAILED, kTraceError,
2841 "StopRecording() could not stop recording");
2842 return(-1);
2843 }
2844 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2845 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2846 _outputFileRecorderPtr = NULL;
2847 _outputFileRecording = false;
2848
2849 return 0;
2850}
2851
2852void
2853Channel::SetMixWithMicStatus(bool mix)
2854{
2855 _mixFileWithMicrophone=mix;
2856}
2857
2858int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002859Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002860{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002861 int8_t currentLevel = _outputAudioLevel.Level();
2862 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002863 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2864 VoEId(_instanceId,_channelId),
2865 "GetSpeechOutputLevel() => level=%u", level);
2866 return 0;
2867}
2868
2869int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002870Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002871{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002872 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2873 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002874 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2875 VoEId(_instanceId,_channelId),
2876 "GetSpeechOutputLevelFullRange() => level=%u", level);
2877 return 0;
2878}
2879
2880int
2881Channel::SetMute(bool enable)
2882{
wu@webrtc.org63420662013-10-17 18:28:55 +00002883 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002884 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2885 "Channel::SetMute(enable=%d)", enable);
2886 _mute = enable;
2887 return 0;
2888}
2889
2890bool
2891Channel::Mute() const
2892{
wu@webrtc.org63420662013-10-17 18:28:55 +00002893 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002894 return _mute;
2895}
2896
2897int
2898Channel::SetOutputVolumePan(float left, float right)
2899{
wu@webrtc.org63420662013-10-17 18:28:55 +00002900 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2902 "Channel::SetOutputVolumePan()");
2903 _panLeft = left;
2904 _panRight = right;
2905 return 0;
2906}
2907
2908int
2909Channel::GetOutputVolumePan(float& left, float& right) const
2910{
wu@webrtc.org63420662013-10-17 18:28:55 +00002911 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002912 left = _panLeft;
2913 right = _panRight;
2914 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2915 VoEId(_instanceId,_channelId),
2916 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2917 return 0;
2918}
2919
2920int
2921Channel::SetChannelOutputVolumeScaling(float scaling)
2922{
wu@webrtc.org63420662013-10-17 18:28:55 +00002923 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002924 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2925 "Channel::SetChannelOutputVolumeScaling()");
2926 _outputGain = scaling;
2927 return 0;
2928}
2929
2930int
2931Channel::GetChannelOutputVolumeScaling(float& scaling) const
2932{
wu@webrtc.org63420662013-10-17 18:28:55 +00002933 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002934 scaling = _outputGain;
2935 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2936 VoEId(_instanceId,_channelId),
2937 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2938 return 0;
2939}
2940
niklase@google.com470e71d2011-07-07 08:21:25 +00002941int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002942 int lengthMs, int attenuationDb,
2943 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002944{
2945 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2946 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2947 playDtmfEvent);
2948
2949 _playOutbandDtmfEvent = playDtmfEvent;
2950
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002951 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002952 attenuationDb) != 0)
2953 {
2954 _engineStatisticsPtr->SetLastError(
2955 VE_SEND_DTMF_FAILED,
2956 kTraceWarning,
2957 "SendTelephoneEventOutband() failed to send event");
2958 return -1;
2959 }
2960 return 0;
2961}
2962
2963int Channel::SendTelephoneEventInband(unsigned char eventCode,
2964 int lengthMs,
2965 int attenuationDb,
2966 bool playDtmfEvent)
2967{
2968 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2969 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2970 playDtmfEvent);
2971
2972 _playInbandDtmfEvent = playDtmfEvent;
2973 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2974
2975 return 0;
2976}
2977
2978int
2979Channel::SetDtmfPlayoutStatus(bool enable)
2980{
2981 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2982 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002983 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002984 {
2985 _engineStatisticsPtr->SetLastError(
2986 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2987 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2988 return -1;
2989 }
2990 return 0;
2991}
2992
2993bool
2994Channel::DtmfPlayoutStatus() const
2995{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002996 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002997}
2998
2999int
3000Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3001{
3002 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3003 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003004 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003005 {
3006 _engineStatisticsPtr->SetLastError(
3007 VE_INVALID_ARGUMENT, kTraceError,
3008 "SetSendTelephoneEventPayloadType() invalid type");
3009 return -1;
3010 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003011 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003012 codec.plfreq = 8000;
3013 codec.pltype = type;
3014 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003015 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003016 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003017 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3018 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3019 _engineStatisticsPtr->SetLastError(
3020 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3021 "SetSendTelephoneEventPayloadType() failed to register send"
3022 "payload type");
3023 return -1;
3024 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003025 }
3026 _sendTelephoneEventPayloadType = type;
3027 return 0;
3028}
3029
3030int
3031Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3032{
3033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3034 "Channel::GetSendTelephoneEventPayloadType()");
3035 type = _sendTelephoneEventPayloadType;
3036 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3037 VoEId(_instanceId,_channelId),
3038 "GetSendTelephoneEventPayloadType() => type=%u", type);
3039 return 0;
3040}
3041
niklase@google.com470e71d2011-07-07 08:21:25 +00003042int
3043Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3044{
3045 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3046 "Channel::UpdateRxVadDetection()");
3047
3048 int vadDecision = 1;
3049
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003050 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003051
3052 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3053 {
3054 OnRxVadDetected(vadDecision);
3055 _oldVadDecision = vadDecision;
3056 }
3057
3058 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3059 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3060 vadDecision);
3061 return 0;
3062}
3063
3064int
3065Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3066{
3067 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3068 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003069 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003070
3071 if (_rxVadObserverPtr)
3072 {
3073 _engineStatisticsPtr->SetLastError(
3074 VE_INVALID_OPERATION, kTraceError,
3075 "RegisterRxVadObserver() observer already enabled");
3076 return -1;
3077 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003078 _rxVadObserverPtr = &observer;
3079 _RxVadDetection = true;
3080 return 0;
3081}
3082
3083int
3084Channel::DeRegisterRxVadObserver()
3085{
3086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3087 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003088 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003089
3090 if (!_rxVadObserverPtr)
3091 {
3092 _engineStatisticsPtr->SetLastError(
3093 VE_INVALID_OPERATION, kTraceWarning,
3094 "DeRegisterRxVadObserver() observer already disabled");
3095 return 0;
3096 }
3097 _rxVadObserverPtr = NULL;
3098 _RxVadDetection = false;
3099 return 0;
3100}
3101
3102int
3103Channel::VoiceActivityIndicator(int &activity)
3104{
3105 activity = _sendFrameType;
3106
3107 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003108 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003109 return 0;
3110}
3111
3112#ifdef WEBRTC_VOICE_ENGINE_AGC
3113
3114int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003115Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003116{
3117 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3118 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3119 (int)enable, (int)mode);
3120
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003121 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003122 switch (mode)
3123 {
3124 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 break;
3126 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003127 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003128 break;
3129 case kAgcFixedDigital:
3130 agcMode = GainControl::kFixedDigital;
3131 break;
3132 case kAgcAdaptiveDigital:
3133 agcMode =GainControl::kAdaptiveDigital;
3134 break;
3135 default:
3136 _engineStatisticsPtr->SetLastError(
3137 VE_INVALID_ARGUMENT, kTraceError,
3138 "SetRxAgcStatus() invalid Agc mode");
3139 return -1;
3140 }
3141
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003142 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003143 {
3144 _engineStatisticsPtr->SetLastError(
3145 VE_APM_ERROR, kTraceError,
3146 "SetRxAgcStatus() failed to set Agc mode");
3147 return -1;
3148 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003149 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003150 {
3151 _engineStatisticsPtr->SetLastError(
3152 VE_APM_ERROR, kTraceError,
3153 "SetRxAgcStatus() failed to set Agc state");
3154 return -1;
3155 }
3156
3157 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003158 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3159
3160 return 0;
3161}
3162
3163int
3164Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3165{
3166 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3167 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3168
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003169 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003170 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003171 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003172
3173 enabled = enable;
3174
3175 switch (agcMode)
3176 {
3177 case GainControl::kFixedDigital:
3178 mode = kAgcFixedDigital;
3179 break;
3180 case GainControl::kAdaptiveDigital:
3181 mode = kAgcAdaptiveDigital;
3182 break;
3183 default:
3184 _engineStatisticsPtr->SetLastError(
3185 VE_APM_ERROR, kTraceError,
3186 "GetRxAgcStatus() invalid Agc mode");
3187 return -1;
3188 }
3189
3190 return 0;
3191}
3192
3193int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003194Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003195{
3196 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3197 "Channel::SetRxAgcConfig()");
3198
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003199 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003200 config.targetLeveldBOv) != 0)
3201 {
3202 _engineStatisticsPtr->SetLastError(
3203 VE_APM_ERROR, kTraceError,
3204 "SetRxAgcConfig() failed to set target peak |level|"
3205 "(or envelope) of the Agc");
3206 return -1;
3207 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003208 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003209 config.digitalCompressionGaindB) != 0)
3210 {
3211 _engineStatisticsPtr->SetLastError(
3212 VE_APM_ERROR, kTraceError,
3213 "SetRxAgcConfig() failed to set the range in |gain| the"
3214 " digital compression stage may apply");
3215 return -1;
3216 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003217 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003218 config.limiterEnable) != 0)
3219 {
3220 _engineStatisticsPtr->SetLastError(
3221 VE_APM_ERROR, kTraceError,
3222 "SetRxAgcConfig() failed to set hard limiter to the signal");
3223 return -1;
3224 }
3225
3226 return 0;
3227}
3228
3229int
3230Channel::GetRxAgcConfig(AgcConfig& config)
3231{
3232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3233 "Channel::GetRxAgcConfig(config=%?)");
3234
3235 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003236 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003237 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003238 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003239 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003240 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003241
3242 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3243 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3244 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3245 " limiterEnable=%d",
3246 config.targetLeveldBOv,
3247 config.digitalCompressionGaindB,
3248 config.limiterEnable);
3249
3250 return 0;
3251}
3252
3253#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3254
3255#ifdef WEBRTC_VOICE_ENGINE_NR
3256
3257int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003258Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003259{
3260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3261 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3262 (int)enable, (int)mode);
3263
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003264 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 switch (mode)
3266 {
3267
3268 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003269 break;
3270 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003271 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003272 break;
3273 case kNsConference:
3274 nsLevel = NoiseSuppression::kHigh;
3275 break;
3276 case kNsLowSuppression:
3277 nsLevel = NoiseSuppression::kLow;
3278 break;
3279 case kNsModerateSuppression:
3280 nsLevel = NoiseSuppression::kModerate;
3281 break;
3282 case kNsHighSuppression:
3283 nsLevel = NoiseSuppression::kHigh;
3284 break;
3285 case kNsVeryHighSuppression:
3286 nsLevel = NoiseSuppression::kVeryHigh;
3287 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003288 }
3289
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003290 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003291 != 0)
3292 {
3293 _engineStatisticsPtr->SetLastError(
3294 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003295 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003296 return -1;
3297 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003298 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003299 {
3300 _engineStatisticsPtr->SetLastError(
3301 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003302 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003303 return -1;
3304 }
3305
3306 _rxNsIsEnabled = enable;
3307 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3308
3309 return 0;
3310}
3311
3312int
3313Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3314{
3315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3316 "Channel::GetRxNsStatus(enable=?, mode=?)");
3317
3318 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003319 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003320 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003321 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003322
3323 enabled = enable;
3324
3325 switch (ncLevel)
3326 {
3327 case NoiseSuppression::kLow:
3328 mode = kNsLowSuppression;
3329 break;
3330 case NoiseSuppression::kModerate:
3331 mode = kNsModerateSuppression;
3332 break;
3333 case NoiseSuppression::kHigh:
3334 mode = kNsHighSuppression;
3335 break;
3336 case NoiseSuppression::kVeryHigh:
3337 mode = kNsVeryHighSuppression;
3338 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003339 }
3340
3341 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3342 VoEId(_instanceId,_channelId),
3343 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3344 return 0;
3345}
3346
3347#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3348
3349int
3350Channel::RegisterRTPObserver(VoERTPObserver& observer)
3351{
3352 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3353 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003354 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003355
3356 if (_rtpObserverPtr)
3357 {
3358 _engineStatisticsPtr->SetLastError(
3359 VE_INVALID_OPERATION, kTraceError,
3360 "RegisterRTPObserver() observer already enabled");
3361 return -1;
3362 }
3363
3364 _rtpObserverPtr = &observer;
3365 _rtpObserver = true;
3366
3367 return 0;
3368}
3369
3370int
3371Channel::DeRegisterRTPObserver()
3372{
3373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3374 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003375 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003376
3377 if (!_rtpObserverPtr)
3378 {
3379 _engineStatisticsPtr->SetLastError(
3380 VE_INVALID_OPERATION, kTraceWarning,
3381 "DeRegisterRTPObserver() observer already disabled");
3382 return 0;
3383 }
3384
3385 _rtpObserver = false;
3386 _rtpObserverPtr = NULL;
3387
3388 return 0;
3389}
3390
3391int
3392Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3393{
3394 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3395 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003396 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003397
3398 if (_rtcpObserverPtr)
3399 {
3400 _engineStatisticsPtr->SetLastError(
3401 VE_INVALID_OPERATION, kTraceError,
3402 "RegisterRTCPObserver() observer already enabled");
3403 return -1;
3404 }
3405
3406 _rtcpObserverPtr = &observer;
3407 _rtcpObserver = true;
3408
3409 return 0;
3410}
3411
3412int
3413Channel::DeRegisterRTCPObserver()
3414{
3415 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3416 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003417 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003418
3419 if (!_rtcpObserverPtr)
3420 {
3421 _engineStatisticsPtr->SetLastError(
3422 VE_INVALID_OPERATION, kTraceWarning,
3423 "DeRegisterRTCPObserver() observer already disabled");
3424 return 0;
3425 }
3426
3427 _rtcpObserver = false;
3428 _rtcpObserverPtr = NULL;
3429
3430 return 0;
3431}
3432
3433int
3434Channel::SetLocalSSRC(unsigned int ssrc)
3435{
3436 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3437 "Channel::SetLocalSSRC()");
3438 if (_sending)
3439 {
3440 _engineStatisticsPtr->SetLastError(
3441 VE_ALREADY_SENDING, kTraceError,
3442 "SetLocalSSRC() already sending");
3443 return -1;
3444 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003445 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003446 {
3447 _engineStatisticsPtr->SetLastError(
3448 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3449 "SetLocalSSRC() failed to set SSRC");
3450 return -1;
3451 }
3452 return 0;
3453}
3454
3455int
3456Channel::GetLocalSSRC(unsigned int& ssrc)
3457{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003458 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003459 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3460 VoEId(_instanceId,_channelId),
3461 "GetLocalSSRC() => ssrc=%lu", ssrc);
3462 return 0;
3463}
3464
3465int
3466Channel::GetRemoteSSRC(unsigned int& ssrc)
3467{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003468 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003469 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3470 VoEId(_instanceId,_channelId),
3471 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3472 return 0;
3473}
3474
3475int
3476Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3477{
3478 if (arrCSRC == NULL)
3479 {
3480 _engineStatisticsPtr->SetLastError(
3481 VE_INVALID_ARGUMENT, kTraceError,
3482 "GetRemoteCSRCs() invalid array argument");
3483 return -1;
3484 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003485 uint32_t arrOfCSRC[kRtpCsrcSize];
3486 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003487 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003488 if (CSRCs > 0)
3489 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003490 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003491 for (int i = 0; i < (int) CSRCs; i++)
3492 {
3493 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3494 VoEId(_instanceId, _channelId),
3495 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3496 }
3497 } else
3498 {
3499 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3500 VoEId(_instanceId, _channelId),
3501 "GetRemoteCSRCs() => list is empty!");
3502 }
3503 return CSRCs;
3504}
3505
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003506int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003507 if (rtp_audioproc_.get() == NULL) {
3508 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3509 _channelId)));
3510 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003511
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003512 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3513 AudioProcessing::kNoError) {
3514 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3515 "Failed to enable AudioProcessing::level_estimator()");
3516 return -1;
3517 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003518
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003519 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003520
3521 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003522}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003523
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003524int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3525 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3526}
3527
3528int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3529 rtp_header_parser_->DeregisterRtpHeaderExtension(
3530 kRtpExtensionAbsoluteSendTime);
3531 if (enable) {
3532 if (!rtp_header_parser_->RegisterRtpHeaderExtension(
3533 kRtpExtensionAbsoluteSendTime, id)) {
3534 return -1;
3535 }
3536 }
3537 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003538}
3539
3540int
3541Channel::SetRTCPStatus(bool enable)
3542{
3543 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3544 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003545 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003546 kRtcpCompound : kRtcpOff) != 0)
3547 {
3548 _engineStatisticsPtr->SetLastError(
3549 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3550 "SetRTCPStatus() failed to set RTCP status");
3551 return -1;
3552 }
3553 return 0;
3554}
3555
3556int
3557Channel::GetRTCPStatus(bool& enabled)
3558{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003559 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003560 enabled = (method != kRtcpOff);
3561 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3562 VoEId(_instanceId,_channelId),
3563 "GetRTCPStatus() => enabled=%d", enabled);
3564 return 0;
3565}
3566
3567int
3568Channel::SetRTCP_CNAME(const char cName[256])
3569{
3570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3571 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003572 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003573 {
3574 _engineStatisticsPtr->SetLastError(
3575 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3576 "SetRTCP_CNAME() failed to set RTCP CNAME");
3577 return -1;
3578 }
3579 return 0;
3580}
3581
3582int
3583Channel::GetRTCP_CNAME(char cName[256])
3584{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003585 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003586 {
3587 _engineStatisticsPtr->SetLastError(
3588 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3589 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3590 return -1;
3591 }
3592 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3593 VoEId(_instanceId, _channelId),
3594 "GetRTCP_CNAME() => cName=%s", cName);
3595 return 0;
3596}
3597
3598int
3599Channel::GetRemoteRTCP_CNAME(char cName[256])
3600{
3601 if (cName == NULL)
3602 {
3603 _engineStatisticsPtr->SetLastError(
3604 VE_INVALID_ARGUMENT, kTraceError,
3605 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3606 return -1;
3607 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003608 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003609 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003610 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003611 {
3612 _engineStatisticsPtr->SetLastError(
3613 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3614 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3615 return -1;
3616 }
3617 strcpy(cName, cname);
3618 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3619 VoEId(_instanceId, _channelId),
3620 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3621 return 0;
3622}
3623
3624int
3625Channel::GetRemoteRTCPData(
3626 unsigned int& NTPHigh,
3627 unsigned int& NTPLow,
3628 unsigned int& timestamp,
3629 unsigned int& playoutTimestamp,
3630 unsigned int* jitter,
3631 unsigned short* fractionLost)
3632{
3633 // --- Information from sender info in received Sender Reports
3634
3635 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003636 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003637 {
3638 _engineStatisticsPtr->SetLastError(
3639 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003640 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003641 "side");
3642 return -1;
3643 }
3644
3645 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3646 // and octet count)
3647 NTPHigh = senderInfo.NTPseconds;
3648 NTPLow = senderInfo.NTPfraction;
3649 timestamp = senderInfo.RTPtimeStamp;
3650
3651 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3652 VoEId(_instanceId, _channelId),
3653 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3654 "timestamp=%lu",
3655 NTPHigh, NTPLow, timestamp);
3656
3657 // --- Locally derived information
3658
3659 // This value is updated on each incoming RTCP packet (0 when no packet
3660 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003661 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003662
3663 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3664 VoEId(_instanceId, _channelId),
3665 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003666 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003667
3668 if (NULL != jitter || NULL != fractionLost)
3669 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003670 // Get all RTCP receiver report blocks that have been received on this
3671 // channel. If we receive RTP packets from a remote source we know the
3672 // remote SSRC and use the report block from him.
3673 // Otherwise use the first report block.
3674 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003675 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003676 remote_stats.empty()) {
3677 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3678 VoEId(_instanceId, _channelId),
3679 "GetRemoteRTCPData() failed to measure statistics due"
3680 " to lack of received RTP and/or RTCP packets");
3681 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003682 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003683
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003684 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003685 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3686 for (; it != remote_stats.end(); ++it) {
3687 if (it->remoteSSRC == remoteSSRC)
3688 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003689 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003690
3691 if (it == remote_stats.end()) {
3692 // If we have not received any RTCP packets from this SSRC it probably
3693 // means that we have not received any RTP packets.
3694 // Use the first received report block instead.
3695 it = remote_stats.begin();
3696 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003697 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003698
xians@webrtc.org79af7342012-01-31 12:22:14 +00003699 if (jitter) {
3700 *jitter = it->jitter;
3701 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3702 VoEId(_instanceId, _channelId),
3703 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3704 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003705
xians@webrtc.org79af7342012-01-31 12:22:14 +00003706 if (fractionLost) {
3707 *fractionLost = it->fractionLost;
3708 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3709 VoEId(_instanceId, _channelId),
3710 "GetRemoteRTCPData() => fractionLost = %lu",
3711 *fractionLost);
3712 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003713 }
3714 return 0;
3715}
3716
3717int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003718Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003719 unsigned int name,
3720 const char* data,
3721 unsigned short dataLengthInBytes)
3722{
3723 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3724 "Channel::SendApplicationDefinedRTCPPacket()");
3725 if (!_sending)
3726 {
3727 _engineStatisticsPtr->SetLastError(
3728 VE_NOT_SENDING, kTraceError,
3729 "SendApplicationDefinedRTCPPacket() not sending");
3730 return -1;
3731 }
3732 if (NULL == data)
3733 {
3734 _engineStatisticsPtr->SetLastError(
3735 VE_INVALID_ARGUMENT, kTraceError,
3736 "SendApplicationDefinedRTCPPacket() invalid data value");
3737 return -1;
3738 }
3739 if (dataLengthInBytes % 4 != 0)
3740 {
3741 _engineStatisticsPtr->SetLastError(
3742 VE_INVALID_ARGUMENT, kTraceError,
3743 "SendApplicationDefinedRTCPPacket() invalid length value");
3744 return -1;
3745 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003746 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003747 if (status == kRtcpOff)
3748 {
3749 _engineStatisticsPtr->SetLastError(
3750 VE_RTCP_ERROR, kTraceError,
3751 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3752 return -1;
3753 }
3754
3755 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003756 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003757 subType,
3758 name,
3759 (const unsigned char*) data,
3760 dataLengthInBytes) != 0)
3761 {
3762 _engineStatisticsPtr->SetLastError(
3763 VE_SEND_ERROR, kTraceError,
3764 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3765 return -1;
3766 }
3767 return 0;
3768}
3769
3770int
3771Channel::GetRTPStatistics(
3772 unsigned int& averageJitterMs,
3773 unsigned int& maxJitterMs,
3774 unsigned int& discardedPackets)
3775{
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 // The jitter statistics is updated for each received RTP packet and is
3777 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003778 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3779 // If RTCP is off, there is no timed thread in the RTCP module regularly
3780 // generating new stats, trigger the update manually here instead.
3781 StreamStatistician* statistician =
3782 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3783 if (statistician) {
3784 // Don't use returned statistics, use data from proxy instead so that
3785 // max jitter can be fetched atomically.
3786 RtcpStatistics s;
3787 statistician->GetStatistics(&s, true);
3788 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003789 }
3790
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003791 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003792 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003793 if (playoutFrequency > 0) {
3794 // Scale RTP statistics given the current playout frequency
3795 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3796 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003797 }
3798
3799 discardedPackets = _numberOfDiscardedPackets;
3800
3801 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3802 VoEId(_instanceId, _channelId),
3803 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003804 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003805 averageJitterMs, maxJitterMs, discardedPackets);
3806 return 0;
3807}
3808
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003809int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3810 if (sender_info == NULL) {
3811 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3812 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3813 return -1;
3814 }
3815
3816 // Get the sender info from the latest received RTCP Sender Report.
3817 RTCPSenderInfo rtcp_sender_info;
3818 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3819 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3820 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3821 return -1;
3822 }
3823
3824 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3825 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3826 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3827 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3828 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3829 return 0;
3830}
3831
3832int Channel::GetRemoteRTCPReportBlocks(
3833 std::vector<ReportBlock>* report_blocks) {
3834 if (report_blocks == NULL) {
3835 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3836 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3837 return -1;
3838 }
3839
3840 // Get the report blocks from the latest received RTCP Sender or Receiver
3841 // Report. Each element in the vector contains the sender's SSRC and a
3842 // report block according to RFC 3550.
3843 std::vector<RTCPReportBlock> rtcp_report_blocks;
3844 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3845 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3846 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3847 return -1;
3848 }
3849
3850 if (rtcp_report_blocks.empty())
3851 return 0;
3852
3853 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3854 for (; it != rtcp_report_blocks.end(); ++it) {
3855 ReportBlock report_block;
3856 report_block.sender_SSRC = it->remoteSSRC;
3857 report_block.source_SSRC = it->sourceSSRC;
3858 report_block.fraction_lost = it->fractionLost;
3859 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3860 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3861 report_block.interarrival_jitter = it->jitter;
3862 report_block.last_SR_timestamp = it->lastSR;
3863 report_block.delay_since_last_SR = it->delaySinceLastSR;
3864 report_blocks->push_back(report_block);
3865 }
3866 return 0;
3867}
3868
niklase@google.com470e71d2011-07-07 08:21:25 +00003869int
3870Channel::GetRTPStatistics(CallStatistics& stats)
3871{
niklase@google.com470e71d2011-07-07 08:21:25 +00003872 // --- Part one of the final structure (four values)
3873
3874 // The jitter statistics is updated for each received RTP packet and is
3875 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003876 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003877 StreamStatistician* statistician =
3878 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3879 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003880 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3881 _engineStatisticsPtr->SetLastError(
3882 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3883 "GetRTPStatistics() failed to read RTP statistics from the "
3884 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003885 }
3886
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003887 stats.fractionLost = statistics.fraction_lost;
3888 stats.cumulativeLost = statistics.cumulative_lost;
3889 stats.extendedMax = statistics.extended_max_sequence_number;
3890 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003891
3892 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3893 VoEId(_instanceId, _channelId),
3894 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003895 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003896 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3897 stats.jitterSamples);
3898
3899 // --- Part two of the final structure (one value)
3900
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003901 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003902 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003903 if (method == kRtcpOff)
3904 {
3905 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3906 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003907 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003908 "measurements cannot be retrieved");
3909 } else
3910 {
3911 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003912 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003913 if (remoteSSRC > 0)
3914 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003915 uint16_t avgRTT(0);
3916 uint16_t maxRTT(0);
3917 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003918
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003919 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003920 != 0)
3921 {
3922 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3923 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003924 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003925 "the RTP/RTCP module");
3926 }
3927 } else
3928 {
3929 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3930 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003931 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003932 "RTP packets have been received yet");
3933 }
3934 }
3935
3936 stats.rttMs = static_cast<int> (RTT);
3937
3938 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3939 VoEId(_instanceId, _channelId),
3940 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3941
3942 // --- Part three of the final structure (four values)
3943
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003944 uint32_t bytesSent(0);
3945 uint32_t packetsSent(0);
3946 uint32_t bytesReceived(0);
3947 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003948
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003949 if (statistician) {
3950 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3951 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003952
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003953 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003954 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003955 {
3956 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3957 VoEId(_instanceId, _channelId),
3958 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003959 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003960 }
3961
3962 stats.bytesSent = bytesSent;
3963 stats.packetsSent = packetsSent;
3964 stats.bytesReceived = bytesReceived;
3965 stats.packetsReceived = packetsReceived;
3966
3967 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3968 VoEId(_instanceId, _channelId),
3969 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003970 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003971 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3972 stats.packetsReceived);
3973
3974 return 0;
3975}
3976
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003977int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3978 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3979 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003980
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003981 if (enable) {
3982 if (redPayloadtype < 0 || redPayloadtype > 127) {
3983 _engineStatisticsPtr->SetLastError(
3984 VE_PLTYPE_ERROR, kTraceError,
3985 "SetFECStatus() invalid RED payload type");
3986 return -1;
3987 }
3988
3989 if (SetRedPayloadType(redPayloadtype) < 0) {
3990 _engineStatisticsPtr->SetLastError(
3991 VE_CODEC_ERROR, kTraceError,
3992 "SetSecondarySendCodec() Failed to register RED ACM");
3993 return -1;
3994 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003995 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003996
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003997 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003998 _engineStatisticsPtr->SetLastError(
3999 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4000 "SetFECStatus() failed to set FEC state in the ACM");
4001 return -1;
4002 }
4003 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004004}
4005
4006int
4007Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4008{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004009 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004010 if (enabled)
4011 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004012 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004013 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004014 {
4015 _engineStatisticsPtr->SetLastError(
4016 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4017 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4018 "module");
4019 return -1;
4020 }
4021 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4022 VoEId(_instanceId, _channelId),
4023 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4024 enabled, redPayloadtype);
4025 return 0;
4026 }
4027 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4028 VoEId(_instanceId, _channelId),
4029 "GetFECStatus() => enabled=%d", enabled);
4030 return 0;
4031}
4032
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004033void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4034 // None of these functions can fail.
4035 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004036 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4037 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004038 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004039 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004040 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004041 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004042}
4043
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004044// Called when we are missing one or more packets.
4045int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004046 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4047}
4048
niklase@google.com470e71d2011-07-07 08:21:25 +00004049int
niklase@google.com470e71d2011-07-07 08:21:25 +00004050Channel::StartRTPDump(const char fileNameUTF8[1024],
4051 RTPDirections direction)
4052{
4053 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4054 "Channel::StartRTPDump()");
4055 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4056 {
4057 _engineStatisticsPtr->SetLastError(
4058 VE_INVALID_ARGUMENT, kTraceError,
4059 "StartRTPDump() invalid RTP direction");
4060 return -1;
4061 }
4062 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4063 &_rtpDumpIn : &_rtpDumpOut;
4064 if (rtpDumpPtr == NULL)
4065 {
4066 assert(false);
4067 return -1;
4068 }
4069 if (rtpDumpPtr->IsActive())
4070 {
4071 rtpDumpPtr->Stop();
4072 }
4073 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4074 {
4075 _engineStatisticsPtr->SetLastError(
4076 VE_BAD_FILE, kTraceError,
4077 "StartRTPDump() failed to create file");
4078 return -1;
4079 }
4080 return 0;
4081}
4082
4083int
4084Channel::StopRTPDump(RTPDirections direction)
4085{
4086 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4087 "Channel::StopRTPDump()");
4088 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4089 {
4090 _engineStatisticsPtr->SetLastError(
4091 VE_INVALID_ARGUMENT, kTraceError,
4092 "StopRTPDump() invalid RTP direction");
4093 return -1;
4094 }
4095 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4096 &_rtpDumpIn : &_rtpDumpOut;
4097 if (rtpDumpPtr == NULL)
4098 {
4099 assert(false);
4100 return -1;
4101 }
4102 if (!rtpDumpPtr->IsActive())
4103 {
4104 return 0;
4105 }
4106 return rtpDumpPtr->Stop();
4107}
4108
4109bool
4110Channel::RTPDumpIsActive(RTPDirections direction)
4111{
4112 if ((direction != kRtpIncoming) &&
4113 (direction != kRtpOutgoing))
4114 {
4115 _engineStatisticsPtr->SetLastError(
4116 VE_INVALID_ARGUMENT, kTraceError,
4117 "RTPDumpIsActive() invalid RTP direction");
4118 return false;
4119 }
4120 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4121 &_rtpDumpIn : &_rtpDumpOut;
4122 return rtpDumpPtr->IsActive();
4123}
4124
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004125uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004126Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004127{
4128 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004129 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004130 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004131 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004132 return 0;
4133}
4134
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004135// TODO(xians): This method borrows quite some code from
4136// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4137// code duplication.
4138void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004139 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004140 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004141 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004142 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4143 static const int kMaxNumberOfFrames = 960;
4144 assert(number_of_frames <= kMaxNumberOfFrames);
4145
4146 // Get the send codec information for doing resampling or downmixing later on.
4147 CodecInst codec;
4148 GetSendCodec(codec);
4149 assert(codec.channels == 1 || codec.channels == 2);
4150 int support_sample_rate = std::min(32000,
4151 std::min(sample_rate, codec.plfreq));
4152
4153 // Downmix the data to mono if needed.
4154 const int16_t* audio_ptr = audio_data;
4155 if (number_of_channels == 2 && codec.channels == 1) {
4156 if (!mono_recording_audio_.get())
4157 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4158
4159 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4160 mono_recording_audio_.get());
4161 audio_ptr = mono_recording_audio_.get();
4162 }
4163
4164 // Resample the data to the sample rate that the codec is using.
4165 if (input_resampler_.InitializeIfNeeded(sample_rate,
4166 support_sample_rate,
4167 codec.channels)) {
4168 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4169 "Channel::Demultiplex() unable to resample");
4170 return;
4171 }
4172
4173 int out_length = input_resampler_.Resample(audio_ptr,
4174 number_of_frames * codec.channels,
4175 _audioFrame.data_,
4176 AudioFrame::kMaxDataSizeSamples);
4177 if (out_length == -1) {
4178 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4179 "Channel::Demultiplex() resampling failed");
4180 return;
4181 }
4182
4183 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4184 _audioFrame.timestamp_ = -1;
4185 _audioFrame.sample_rate_hz_ = support_sample_rate;
4186 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4187 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4188 _audioFrame.num_channels_ = codec.channels;
4189 _audioFrame.id_ = _channelId;
4190}
4191
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004192uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004193Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004194{
4195 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4196 "Channel::PrepareEncodeAndSend()");
4197
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004198 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004199 {
4200 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4201 "Channel::PrepareEncodeAndSend() invalid audio frame");
4202 return -1;
4203 }
4204
4205 if (_inputFilePlaying)
4206 {
4207 MixOrReplaceAudioWithFile(mixingFrequency);
4208 }
4209
wu@webrtc.org63420662013-10-17 18:28:55 +00004210 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004211 {
4212 AudioFrameOperations::Mute(_audioFrame);
4213 }
4214
4215 if (_inputExternalMedia)
4216 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004217 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004218 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004219 if (_inputExternalMediaCallbackPtr)
4220 {
4221 _inputExternalMediaCallbackPtr->Process(
4222 _channelId,
4223 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004224 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004225 _audioFrame.samples_per_channel_,
4226 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004227 isStereo);
4228 }
4229 }
4230
4231 InsertInbandDtmfTone();
4232
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004233 if (_includeAudioLevelIndication) {
4234 // Performs level analysis only; does not affect the signal.
4235 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4236 if (err) {
4237 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4238 assert(false);
4239 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004240 }
4241
niklase@google.com470e71d2011-07-07 08:21:25 +00004242 return 0;
4243}
4244
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004245uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004246Channel::EncodeAndSend()
4247{
4248 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4249 "Channel::EncodeAndSend()");
4250
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004251 assert(_audioFrame.num_channels_ <= 2);
4252 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004253 {
4254 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4255 "Channel::EncodeAndSend() invalid audio frame");
4256 return -1;
4257 }
4258
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004259 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004260
4261 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4262
4263 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004264 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004265 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004266 {
4267 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4268 "Channel::EncodeAndSend() ACM encoding failed");
4269 return -1;
4270 }
4271
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004272 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004273
4274 // --- Encode if complete frame is ready
4275
4276 // This call will trigger AudioPacketizationCallback::SendData if encoding
4277 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004278 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004279}
4280
4281int Channel::RegisterExternalMediaProcessing(
4282 ProcessingTypes type,
4283 VoEMediaProcess& processObject)
4284{
4285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4286 "Channel::RegisterExternalMediaProcessing()");
4287
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004288 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004289
4290 if (kPlaybackPerChannel == type)
4291 {
4292 if (_outputExternalMediaCallbackPtr)
4293 {
4294 _engineStatisticsPtr->SetLastError(
4295 VE_INVALID_OPERATION, kTraceError,
4296 "Channel::RegisterExternalMediaProcessing() "
4297 "output external media already enabled");
4298 return -1;
4299 }
4300 _outputExternalMediaCallbackPtr = &processObject;
4301 _outputExternalMedia = true;
4302 }
4303 else if (kRecordingPerChannel == type)
4304 {
4305 if (_inputExternalMediaCallbackPtr)
4306 {
4307 _engineStatisticsPtr->SetLastError(
4308 VE_INVALID_OPERATION, kTraceError,
4309 "Channel::RegisterExternalMediaProcessing() "
4310 "output external media already enabled");
4311 return -1;
4312 }
4313 _inputExternalMediaCallbackPtr = &processObject;
4314 _inputExternalMedia = true;
4315 }
4316 return 0;
4317}
4318
4319int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4320{
4321 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4322 "Channel::DeRegisterExternalMediaProcessing()");
4323
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004324 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004325
4326 if (kPlaybackPerChannel == type)
4327 {
4328 if (!_outputExternalMediaCallbackPtr)
4329 {
4330 _engineStatisticsPtr->SetLastError(
4331 VE_INVALID_OPERATION, kTraceWarning,
4332 "Channel::DeRegisterExternalMediaProcessing() "
4333 "output external media already disabled");
4334 return 0;
4335 }
4336 _outputExternalMedia = false;
4337 _outputExternalMediaCallbackPtr = NULL;
4338 }
4339 else if (kRecordingPerChannel == type)
4340 {
4341 if (!_inputExternalMediaCallbackPtr)
4342 {
4343 _engineStatisticsPtr->SetLastError(
4344 VE_INVALID_OPERATION, kTraceWarning,
4345 "Channel::DeRegisterExternalMediaProcessing() "
4346 "input external media already disabled");
4347 return 0;
4348 }
4349 _inputExternalMedia = false;
4350 _inputExternalMediaCallbackPtr = NULL;
4351 }
4352
4353 return 0;
4354}
4355
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004356int Channel::SetExternalMixing(bool enabled) {
4357 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4358 "Channel::SetExternalMixing(enabled=%d)", enabled);
4359
4360 if (_playing)
4361 {
4362 _engineStatisticsPtr->SetLastError(
4363 VE_INVALID_OPERATION, kTraceError,
4364 "Channel::SetExternalMixing() "
4365 "external mixing cannot be changed while playing.");
4366 return -1;
4367 }
4368
4369 _externalMixing = enabled;
4370
4371 return 0;
4372}
4373
niklase@google.com470e71d2011-07-07 08:21:25 +00004374int
4375Channel::ResetRTCPStatistics()
4376{
4377 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4378 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004379 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004380 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004381 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004382}
4383
4384int
4385Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4386{
4387 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4388 "Channel::GetRoundTripTimeSummary()");
4389 // Override default module outputs for the case when RTCP is disabled.
4390 // This is done to ensure that we are backward compatible with the
4391 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004392 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004393 {
4394 delaysMs.min = -1;
4395 delaysMs.max = -1;
4396 delaysMs.average = -1;
4397 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4398 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4399 " valid RTT measurements cannot be retrieved");
4400 return 0;
4401 }
4402
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004403 uint32_t remoteSSRC;
4404 uint16_t RTT;
4405 uint16_t avgRTT;
4406 uint16_t maxRTT;
4407 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004408 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004409 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004410 if (remoteSSRC == 0)
4411 {
4412 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4413 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4414 " since no RTP packet has been received yet");
4415 }
4416
4417 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4418 // channel and SSRC. The SSRC is required to parse out the correct source
4419 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004420 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004421 {
4422 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4423 "GetRoundTripTimeSummary unable to retrieve RTT values"
4424 " from the RTCP layer");
4425 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4426 }
4427 else
4428 {
4429 delaysMs.min = minRTT;
4430 delaysMs.max = maxRTT;
4431 delaysMs.average = avgRTT;
4432 }
4433 return 0;
4434}
4435
4436int
4437Channel::GetNetworkStatistics(NetworkStatistics& stats)
4438{
4439 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4440 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004441 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004442 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004443 if (return_value >= 0) {
4444 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4445 }
4446 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004447}
4448
wu@webrtc.org24301a62013-12-13 19:17:43 +00004449void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4450 audio_coding_->GetDecodingCallStatistics(stats);
4451}
4452
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004453bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4454 int* playout_buffer_delay_ms) const {
4455 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004456 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004457 "Channel::GetDelayEstimate() no valid estimate.");
4458 return false;
4459 }
4460 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4461 _recPacketDelayMs;
4462 *playout_buffer_delay_ms = playout_delay_ms_;
4463 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4464 "Channel::GetDelayEstimate()");
4465 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004466}
4467
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004468int Channel::SetInitialPlayoutDelay(int delay_ms)
4469{
4470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4471 "Channel::SetInitialPlayoutDelay()");
4472 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4473 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4474 {
4475 _engineStatisticsPtr->SetLastError(
4476 VE_INVALID_ARGUMENT, kTraceError,
4477 "SetInitialPlayoutDelay() invalid min delay");
4478 return -1;
4479 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004480 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004481 {
4482 _engineStatisticsPtr->SetLastError(
4483 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4484 "SetInitialPlayoutDelay() failed to set min playout delay");
4485 return -1;
4486 }
4487 return 0;
4488}
4489
4490
niklase@google.com470e71d2011-07-07 08:21:25 +00004491int
4492Channel::SetMinimumPlayoutDelay(int delayMs)
4493{
4494 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4495 "Channel::SetMinimumPlayoutDelay()");
4496 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4497 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4498 {
4499 _engineStatisticsPtr->SetLastError(
4500 VE_INVALID_ARGUMENT, kTraceError,
4501 "SetMinimumPlayoutDelay() invalid min delay");
4502 return -1;
4503 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004504 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004505 {
4506 _engineStatisticsPtr->SetLastError(
4507 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4508 "SetMinimumPlayoutDelay() failed to set min playout delay");
4509 return -1;
4510 }
4511 return 0;
4512}
4513
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004514void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4515 uint32_t playout_timestamp = 0;
4516
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004517 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004518 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4519 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4520 " timestamp from the ACM");
4521 _engineStatisticsPtr->SetLastError(
4522 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4523 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4524 return;
4525 }
4526
4527 uint16_t delay_ms = 0;
4528 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4529 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4530 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4531 " delay from the ADM");
4532 _engineStatisticsPtr->SetLastError(
4533 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4534 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4535 return;
4536 }
4537
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004538 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004539 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004540 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004541 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4542 playout_frequency = 8000;
4543 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4544 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004545 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004546 }
4547
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004548 jitter_buffer_playout_timestamp_ = playout_timestamp;
4549
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004550 // Remove the playout delay.
4551 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4552
4553 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4554 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4555 playout_timestamp);
4556
4557 if (rtcp) {
4558 playout_timestamp_rtcp_ = playout_timestamp;
4559 } else {
4560 playout_timestamp_rtp_ = playout_timestamp;
4561 }
4562 playout_delay_ms_ = delay_ms;
4563}
4564
4565int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4567 "Channel::GetPlayoutTimestamp()");
4568 if (playout_timestamp_rtp_ == 0) {
4569 _engineStatisticsPtr->SetLastError(
4570 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4571 "GetPlayoutTimestamp() failed to retrieve timestamp");
4572 return -1;
4573 }
4574 timestamp = playout_timestamp_rtp_;
4575 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4576 VoEId(_instanceId,_channelId),
4577 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4578 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004579}
4580
4581int
4582Channel::SetInitTimestamp(unsigned int timestamp)
4583{
4584 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4585 "Channel::SetInitTimestamp()");
4586 if (_sending)
4587 {
4588 _engineStatisticsPtr->SetLastError(
4589 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4590 return -1;
4591 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004592 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004593 {
4594 _engineStatisticsPtr->SetLastError(
4595 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4596 "SetInitTimestamp() failed to set timestamp");
4597 return -1;
4598 }
4599 return 0;
4600}
4601
4602int
4603Channel::SetInitSequenceNumber(short sequenceNumber)
4604{
4605 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4606 "Channel::SetInitSequenceNumber()");
4607 if (_sending)
4608 {
4609 _engineStatisticsPtr->SetLastError(
4610 VE_SENDING, kTraceError,
4611 "SetInitSequenceNumber() already sending");
4612 return -1;
4613 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004614 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004615 {
4616 _engineStatisticsPtr->SetLastError(
4617 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4618 "SetInitSequenceNumber() failed to set sequence number");
4619 return -1;
4620 }
4621 return 0;
4622}
4623
4624int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004625Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004626{
4627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4628 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004629 *rtpRtcpModule = _rtpRtcpModule.get();
4630 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004631 return 0;
4632}
4633
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004634// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4635// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004636int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004637Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004638{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004639 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004640 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004641
4642 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004643 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004644
4645 if (_inputFilePlayerPtr == NULL)
4646 {
4647 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4648 VoEId(_instanceId, _channelId),
4649 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4650 " doesnt exist");
4651 return -1;
4652 }
4653
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004654 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004655 fileSamples,
4656 mixingFrequency) == -1)
4657 {
4658 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4659 VoEId(_instanceId, _channelId),
4660 "Channel::MixOrReplaceAudioWithFile() file mixing "
4661 "failed");
4662 return -1;
4663 }
4664 if (fileSamples == 0)
4665 {
4666 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4667 VoEId(_instanceId, _channelId),
4668 "Channel::MixOrReplaceAudioWithFile() file is ended");
4669 return 0;
4670 }
4671 }
4672
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004673 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004674
4675 if (_mixFileWithMicrophone)
4676 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004677 // Currently file stream is always mono.
4678 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004679 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004680 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004681 fileBuffer.get(),
4682 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004683 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004684 }
4685 else
4686 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004687 // Replace ACM audio with file.
4688 // Currently file stream is always mono.
4689 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004690 _audioFrame.UpdateFrame(_channelId,
4691 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004692 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004693 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004694 mixingFrequency,
4695 AudioFrame::kNormalSpeech,
4696 AudioFrame::kVadUnknown,
4697 1);
4698
4699 }
4700 return 0;
4701}
4702
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004703int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004704Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004705 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004706{
4707 assert(mixingFrequency <= 32000);
4708
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004709 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004710 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004711
4712 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004713 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004714
4715 if (_outputFilePlayerPtr == NULL)
4716 {
4717 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4718 VoEId(_instanceId, _channelId),
4719 "Channel::MixAudioWithFile() file mixing failed");
4720 return -1;
4721 }
4722
4723 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004724 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004725 fileSamples,
4726 mixingFrequency) == -1)
4727 {
4728 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4729 VoEId(_instanceId, _channelId),
4730 "Channel::MixAudioWithFile() file mixing failed");
4731 return -1;
4732 }
4733 }
4734
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004735 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004736 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004737 // Currently file stream is always mono.
4738 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004739 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004740 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004741 fileBuffer.get(),
4742 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004743 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004744 }
4745 else
4746 {
4747 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004748 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004749 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004750 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004751 return -1;
4752 }
4753
4754 return 0;
4755}
4756
4757int
4758Channel::InsertInbandDtmfTone()
4759{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004760 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004761 if (_inbandDtmfQueue.PendingDtmf() &&
4762 !_inbandDtmfGenerator.IsAddingTone() &&
4763 _inbandDtmfGenerator.DelaySinceLastTone() >
4764 kMinTelephoneEventSeparationMs)
4765 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004766 int8_t eventCode(0);
4767 uint16_t lengthMs(0);
4768 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004769
4770 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4771 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4772 if (_playInbandDtmfEvent)
4773 {
4774 // Add tone to output mixer using a reduced length to minimize
4775 // risk of echo.
4776 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4777 attenuationDb);
4778 }
4779 }
4780
4781 if (_inbandDtmfGenerator.IsAddingTone())
4782 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004783 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004784 _inbandDtmfGenerator.GetSampleRate(frequency);
4785
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004786 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004787 {
4788 // Update sample rate of Dtmf tone since the mixing frequency
4789 // has changed.
4790 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004791 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004792 // Reset the tone to be added taking the new sample rate into
4793 // account.
4794 _inbandDtmfGenerator.ResetTone();
4795 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004796
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004797 int16_t toneBuffer[320];
4798 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004799 // Get 10ms tone segment and set time since last tone to zero
4800 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4801 {
4802 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4803 VoEId(_instanceId, _channelId),
4804 "Channel::EncodeAndSend() inserting Dtmf failed");
4805 return -1;
4806 }
4807
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004808 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004809 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004810 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004811 sample++)
4812 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004813 for (int channel = 0;
4814 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004815 channel++)
4816 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004817 const int index = sample * _audioFrame.num_channels_ + channel;
4818 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004819 }
4820 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004821
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004822 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004823 } else
4824 {
4825 // Add 10ms to "delay-since-last-tone" counter
4826 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4827 }
4828 return 0;
4829}
4830
niklase@google.com470e71d2011-07-07 08:21:25 +00004831void
4832Channel::ResetDeadOrAliveCounters()
4833{
4834 _countDeadDetections = 0;
4835 _countAliveDetections = 0;
4836}
4837
4838void
4839Channel::UpdateDeadOrAliveCounters(bool alive)
4840{
4841 if (alive)
4842 _countAliveDetections++;
4843 else
4844 _countDeadDetections++;
4845}
4846
4847int
4848Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
4849{
niklase@google.com470e71d2011-07-07 08:21:25 +00004850 return 0;
4851}
4852
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004853int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004854Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4855{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004856 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004857 if (_transportPtr == NULL)
4858 {
4859 return -1;
4860 }
4861 if (!RTCP)
4862 {
4863 return _transportPtr->SendPacket(_channelId, data, len);
4864 }
4865 else
4866 {
4867 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4868 }
4869}
4870
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004871// Called for incoming RTP packets after successful RTP header parsing.
4872void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4873 uint16_t sequence_number) {
4874 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4875 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4876 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004877
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004878 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004879 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004880
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004881 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004882 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004883 return;
4884 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004885
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004886 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004887 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004888
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004889 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4890 // Even though the actual sampling rate for G.722 audio is
4891 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4892 // 8,000 Hz because that value was erroneously assigned in
4893 // RFC 1890 and must remain unchanged for backward compatibility.
4894 rtp_receive_frequency = 8000;
4895 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4896 // We are resampling Opus internally to 32,000 Hz until all our
4897 // DSP routines can operate at 48,000 Hz, but the RTP clock
4898 // rate for the Opus payload format is standardized to 48,000 Hz,
4899 // because that is the maximum supported decoding sampling rate.
4900 rtp_receive_frequency = 48000;
4901 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004902
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004903 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4904 // every incoming packet.
4905 uint32_t timestamp_diff_ms = (rtp_timestamp -
4906 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004907
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004908 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4909 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004910
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004911 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004912
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004913 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4914 timestamp_diff_ms = 0;
4915 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004916
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004917 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004918
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004919 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4920 _recPacketDelayMs = packet_delay_ms;
4921 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004922
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004923 if (_average_jitter_buffer_delay_us == 0) {
4924 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4925 return;
4926 }
4927
4928 // Filter average delay value using exponential filter (alpha is
4929 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4930 // risk of rounding error) and compensate for it in GetDelayEstimate()
4931 // later.
4932 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4933 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004934}
4935
4936void
4937Channel::RegisterReceiveCodecsToRTPModule()
4938{
4939 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4940 "Channel::RegisterReceiveCodecsToRTPModule()");
4941
4942
4943 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004944 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004945
4946 for (int idx = 0; idx < nSupportedCodecs; idx++)
4947 {
4948 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004949 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004950 (rtp_receiver_->RegisterReceivePayload(
4951 codec.plname,
4952 codec.pltype,
4953 codec.plfreq,
4954 codec.channels,
4955 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004956 {
4957 WEBRTC_TRACE(
4958 kTraceWarning,
4959 kTraceVoice,
4960 VoEId(_instanceId, _channelId),
4961 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4962 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4963 codec.plname, codec.pltype, codec.plfreq,
4964 codec.channels, codec.rate);
4965 }
4966 else
4967 {
4968 WEBRTC_TRACE(
4969 kTraceInfo,
4970 kTraceVoice,
4971 VoEId(_instanceId, _channelId),
4972 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004973 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004974 "receiver",
4975 codec.plname, codec.pltype, codec.plfreq,
4976 codec.channels, codec.rate);
4977 }
4978 }
4979}
4980
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004981int Channel::SetSecondarySendCodec(const CodecInst& codec,
4982 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004983 // Sanity check for payload type.
4984 if (red_payload_type < 0 || red_payload_type > 127) {
4985 _engineStatisticsPtr->SetLastError(
4986 VE_PLTYPE_ERROR, kTraceError,
4987 "SetRedPayloadType() invalid RED payload type");
4988 return -1;
4989 }
4990
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004991 if (SetRedPayloadType(red_payload_type) < 0) {
4992 _engineStatisticsPtr->SetLastError(
4993 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4994 "SetSecondarySendCodec() Failed to register RED ACM");
4995 return -1;
4996 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004997 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004998 _engineStatisticsPtr->SetLastError(
4999 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5000 "SetSecondarySendCodec() Failed to register secondary send codec in "
5001 "ACM");
5002 return -1;
5003 }
5004
5005 return 0;
5006}
5007
5008void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005009 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005010}
5011
5012int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005013 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005014 _engineStatisticsPtr->SetLastError(
5015 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5016 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5017 return -1;
5018 }
5019 return 0;
5020}
5021
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005022// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005023int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005024 CodecInst codec;
5025 bool found_red = false;
5026
5027 // Get default RED settings from the ACM database
5028 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5029 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005030 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005031 if (!STR_CASE_CMP(codec.plname, "RED")) {
5032 found_red = true;
5033 break;
5034 }
5035 }
5036
5037 if (!found_red) {
5038 _engineStatisticsPtr->SetLastError(
5039 VE_CODEC_ERROR, kTraceError,
5040 "SetRedPayloadType() RED is not supported");
5041 return -1;
5042 }
5043
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005044 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005045 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005046 _engineStatisticsPtr->SetLastError(
5047 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5048 "SetRedPayloadType() RED registration in ACM module failed");
5049 return -1;
5050 }
5051
5052 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5053 _engineStatisticsPtr->SetLastError(
5054 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5055 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5056 return -1;
5057 }
5058 return 0;
5059}
5060
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00005061int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
5062 unsigned char id) {
5063 int error = 0;
5064 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
5065 if (enable) {
5066 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
5067 }
5068 return error;
5069}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005070} // namespace voe
5071} // namespace webrtc