blob: e14ee78d4c8aaa87b64cd70599c1692c3245a145 [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 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000413 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 {
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.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000491 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 {
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
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000530 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 {
532 // Avoid inserting into NetEQ when we are not playing. Count the
533 // packet as discarded.
534 WEBRTC_TRACE(kTraceStream, kTraceVoice,
535 VoEId(_instanceId, _channelId),
536 "received packet is discarded since playing is not"
537 " activated");
538 _numberOfDiscardedPackets++;
539 return 0;
540 }
541
542 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000543 if (audio_coding_->IncomingPacket(payloadData,
544 payloadSize,
545 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 {
547 _engineStatisticsPtr->SetLastError(
548 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
549 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
550 return -1;
551 }
552
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000553 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000554 UpdatePacketDelay(rtpHeader->header.timestamp,
555 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000556
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000557 uint16_t round_trip_time = 0;
558 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
559 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000560
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000561 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000562 round_trip_time);
563 if (!nack_list.empty()) {
564 // Can't use nack_list.data() since it's not supported by all
565 // compilers.
566 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000567 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 return 0;
569}
570
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000571bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
572 int rtp_packet_length) {
573 RTPHeader header;
574 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
575 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
576 "IncomingPacket invalid RTP header");
577 return false;
578 }
579 header.payload_type_frequency =
580 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
581 if (header.payload_type_frequency < 0)
582 return false;
583 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
584}
585
pbos@webrtc.org92135212013-05-14 08:31:39 +0000586int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000587{
588 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
589 "Channel::GetAudioFrame(id=%d)", id);
590
591 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000592 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
593 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 {
595 WEBRTC_TRACE(kTraceError, kTraceVoice,
596 VoEId(_instanceId,_channelId),
597 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000598 // In all likelihood, the audio in this frame is garbage. We return an
599 // error so that the audio mixer module doesn't add it to the mix. As
600 // a result, it won't be played out and the actions skipped here are
601 // irrelevant.
602 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000603 }
604
605 if (_RxVadDetection)
606 {
607 UpdateRxVadDetection(audioFrame);
608 }
609
610 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000611 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000613 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000615 ChannelState::State state = channel_state_.Get();
616
617 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000618 int err = rx_audioproc_->ProcessStream(&audioFrame);
619 if (err) {
620 LOG(LS_ERROR) << "ProcessStream() error: " << err;
621 assert(false);
622 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 }
624
wu@webrtc.org63420662013-10-17 18:28:55 +0000625 float output_gain = 1.0f;
626 float left_pan = 1.0f;
627 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000629 CriticalSectionScoped cs(&volume_settings_critsect_);
630 output_gain = _outputGain;
631 left_pan = _panLeft;
632 right_pan= _panRight;
633 }
634
635 // Output volume scaling
636 if (output_gain < 0.99f || output_gain > 1.01f)
637 {
638 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 }
640
641 // Scale left and/or right channel(s) if stereo and master balance is
642 // active
643
wu@webrtc.org63420662013-10-17 18:28:55 +0000644 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000645 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000646 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 {
648 // Emulate stereo mode since panning is active.
649 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000650 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 }
652 // For true stereo mode (when we are receiving a stereo signal), no
653 // action is needed.
654
655 // Do the panning operation (the audio frame contains stereo at this
656 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000657 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658 }
659
660 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000661 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000663 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 }
665
666 // Place channel in on-hold state (~muted) if on-hold is activated
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000667 if (state.output_is_on_hold)
niklase@google.com470e71d2011-07-07 08:21:25 +0000668 {
669 AudioFrameOperations::Mute(audioFrame);
670 }
671
672 // External media
673 if (_outputExternalMedia)
674 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000675 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000676 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 if (_outputExternalMediaCallbackPtr)
678 {
679 _outputExternalMediaCallbackPtr->Process(
680 _channelId,
681 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000682 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000683 audioFrame.samples_per_channel_,
684 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 isStereo);
686 }
687 }
688
689 // Record playout if enabled
690 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000691 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000692
693 if (_outputFileRecording && _outputFileRecorderPtr)
694 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000695 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 }
697 }
698
699 // Measure audio level (0-9)
700 _outputAudioLevel.ComputeLevel(audioFrame);
701
702 return 0;
703}
704
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000705int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000706Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000707{
708 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
709 "Channel::NeededFrequency(id=%d)", id);
710
711 int highestNeeded = 0;
712
713 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000714 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000715
716 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000717 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000719 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
721 else
722 {
723 highestNeeded = receiveFrequency;
724 }
725
726 // Special case, if we're playing a file on the playout side
727 // we take that frequency into consideration as well
728 // This is not needed on sending side, since the codec will
729 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000730 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000731 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000732 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000733 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000734 {
735 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
736 {
737 highestNeeded=_outputFilePlayerPtr->Frequency();
738 }
739 }
740 }
741
742 return(highestNeeded);
743}
744
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000745int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000746Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000747 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000748 uint32_t instanceId,
749 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000750{
751 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
752 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
753 channelId, instanceId);
754
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000755 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 if (channel == NULL)
757 {
758 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
759 VoEId(instanceId,channelId),
760 "Channel::CreateChannel() unable to allocate memory for"
761 " channel");
762 return -1;
763 }
764 return 0;
765}
766
767void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000768Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000769{
770 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
771 "Channel::PlayNotification(id=%d, durationMs=%d)",
772 id, durationMs);
773
774 // Not implement yet
775}
776
777void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000778Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000779{
780 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
781 "Channel::RecordNotification(id=%d, durationMs=%d)",
782 id, durationMs);
783
784 // Not implement yet
785}
786
787void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000788Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000789{
790 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
791 "Channel::PlayFileEnded(id=%d)", id);
792
793 if (id == _inputFilePlayerId)
794 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000795 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
797 VoEId(_instanceId,_channelId),
798 "Channel::PlayFileEnded() => input file player module is"
799 " shutdown");
800 }
801 else if (id == _outputFilePlayerId)
802 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000803 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
805 VoEId(_instanceId,_channelId),
806 "Channel::PlayFileEnded() => output file player module is"
807 " shutdown");
808 }
809}
810
811void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000812Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000813{
814 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
815 "Channel::RecordFileEnded(id=%d)", id);
816
817 assert(id == _outputFileRecorderId);
818
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000819 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000820
821 _outputFileRecording = false;
822 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
823 VoEId(_instanceId,_channelId),
824 "Channel::RecordFileEnded() => output file recorder module is"
825 " shutdown");
826}
827
pbos@webrtc.org92135212013-05-14 08:31:39 +0000828Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000829 uint32_t instanceId,
830 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000831 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
832 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000833 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000834 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000835 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000836 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000837 rtp_payload_registry_(
838 new RTPPayloadRegistry(channelId,
839 RTPPayloadStrategy::CreateStrategy(true))),
840 rtp_receive_statistics_(ReceiveStatistics::Create(
841 Clock::GetRealTimeClock())),
842 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
843 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
844 this, this, rtp_payload_registry_.get())),
845 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000846 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000847 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 _rtpDumpIn(*RtpDump::CreateRtpDump()),
849 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000851 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000852 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000853 _inputFilePlayerPtr(NULL),
854 _outputFilePlayerPtr(NULL),
855 _outputFileRecorderPtr(NULL),
856 // Avoid conflict with other channels by adding 1024 - 1026,
857 // won't use as much as 1024 channels.
858 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
859 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
860 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000862 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
863 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000864 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000865 _inputExternalMediaCallbackPtr(NULL),
866 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000867 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
868 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000869 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000870 playout_timestamp_rtp_(0),
871 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000872 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000873 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000874 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000876 _outputMixerPtr(NULL),
877 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000878 _moduleProcessThreadPtr(NULL),
879 _audioDeviceModulePtr(NULL),
880 _voiceEngineObserverPtr(NULL),
881 _callbackCritSectPtr(NULL),
882 _transportPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000883 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000884 _rxVadObserverPtr(NULL),
885 _oldVadDecision(-1),
886 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000887 _rtpObserverPtr(NULL),
888 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000889 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000890 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000891 _inputIsOnHold(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000892 _mixFileWithMicrophone(false),
893 _rtpObserver(false),
894 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000895 _mute(false),
896 _panLeft(1.0f),
897 _panRight(1.0f),
898 _outputGain(1.0f),
899 _playOutbandDtmfEvent(false),
900 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +0000902 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000904 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000905 _rtpPacketTimedOut(false),
906 _rtpPacketTimeOutIsEnabled(false),
907 _rtpTimeOutSeconds(0),
908 _connectionObserver(false),
909 _connectionObserverPtr(NULL),
910 _countAliveDetections(0),
911 _countDeadDetections(0),
912 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000913 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000914 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000915 _previousTimestamp(0),
916 _recPacketDelayMs(20),
917 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000918 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000919 _rxNsIsEnabled(false),
920 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000921{
922 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
923 "Channel::Channel() - ctor");
924 _inbandDtmfQueue.ResetDtmf();
925 _inbandDtmfGenerator.Init();
926 _outputAudioLevel.Clear();
927
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000928 RtpRtcp::Configuration configuration;
929 configuration.id = VoEModuleId(instanceId, channelId);
930 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000931 configuration.outgoing_transport = this;
932 configuration.rtcp_feedback = this;
933 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000934 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000935
936 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000937
938 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
939 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
940 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +0000941}
942
943Channel::~Channel()
944{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000945 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
947 "Channel::~Channel() - dtor");
948
949 if (_outputExternalMedia)
950 {
951 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
952 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000953 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 {
955 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
956 }
957 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 StopPlayout();
959
960 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000961 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 if (_inputFilePlayerPtr)
963 {
964 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
965 _inputFilePlayerPtr->StopPlayingFile();
966 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
967 _inputFilePlayerPtr = NULL;
968 }
969 if (_outputFilePlayerPtr)
970 {
971 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
972 _outputFilePlayerPtr->StopPlayingFile();
973 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
974 _outputFilePlayerPtr = NULL;
975 }
976 if (_outputFileRecorderPtr)
977 {
978 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
979 _outputFileRecorderPtr->StopRecording();
980 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
981 _outputFileRecorderPtr = NULL;
982 }
983 }
984
985 // The order to safely shutdown modules in a channel is:
986 // 1. De-register callbacks in modules
987 // 2. De-register modules in process thread
988 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000989 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 {
991 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
992 VoEId(_instanceId,_channelId),
993 "~Channel() failed to de-register transport callback"
994 " (Audio coding module)");
995 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000996 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 {
998 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
999 VoEId(_instanceId,_channelId),
1000 "~Channel() failed to de-register VAD callback"
1001 " (Audio coding module)");
1002 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001004 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 {
1006 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1007 VoEId(_instanceId,_channelId),
1008 "~Channel() failed to deregister RTP/RTCP module");
1009 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 // End of modules shutdown
1011
1012 // Delete other objects
1013 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1014 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001016 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001017 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001018}
1019
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001020int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001021Channel::Init()
1022{
1023 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1024 "Channel::Init()");
1025
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001026 channel_state_.Reset();
1027
niklase@google.com470e71d2011-07-07 08:21:25 +00001028 // --- Initial sanity
1029
1030 if ((_engineStatisticsPtr == NULL) ||
1031 (_moduleProcessThreadPtr == NULL))
1032 {
1033 WEBRTC_TRACE(kTraceError, kTraceVoice,
1034 VoEId(_instanceId,_channelId),
1035 "Channel::Init() must call SetEngineInformation() first");
1036 return -1;
1037 }
1038
1039 // --- Add modules to process thread (for periodic schedulation)
1040
1041 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001042 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 if (processThreadFail)
1045 {
1046 _engineStatisticsPtr->SetLastError(
1047 VE_CANNOT_INIT_CHANNEL, kTraceError,
1048 "Channel::Init() modules not registered");
1049 return -1;
1050 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001051 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001052
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001053 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001054#ifdef WEBRTC_CODEC_AVT
1055 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001056 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001057#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001058 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 {
1060 _engineStatisticsPtr->SetLastError(
1061 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1062 "Channel::Init() unable to initialize the ACM - 1");
1063 return -1;
1064 }
1065
1066 // --- RTP/RTCP module initialization
1067
1068 // Ensure that RTCP is enabled by default for the created channel.
1069 // Note that, the module will keep generating RTCP until it is explicitly
1070 // disabled by the user.
1071 // After StopListen (when no sockets exists), RTCP packets will no longer
1072 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001073 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1074 // RTCP is enabled by default.
1075 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001076 {
1077 _engineStatisticsPtr->SetLastError(
1078 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1079 "Channel::Init() RTP/RTCP module not initialized");
1080 return -1;
1081 }
1082
1083 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001084 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001085 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1086 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001087
1088 if (fail)
1089 {
1090 _engineStatisticsPtr->SetLastError(
1091 VE_CANNOT_INIT_CHANNEL, kTraceError,
1092 "Channel::Init() callbacks not registered");
1093 return -1;
1094 }
1095
1096 // --- Register all supported codecs to the receiving side of the
1097 // RTP/RTCP module
1098
1099 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001100 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001101
1102 for (int idx = 0; idx < nSupportedCodecs; idx++)
1103 {
1104 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001105 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001106 (rtp_receiver_->RegisterReceivePayload(
1107 codec.plname,
1108 codec.pltype,
1109 codec.plfreq,
1110 codec.channels,
1111 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 {
1113 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1114 VoEId(_instanceId,_channelId),
1115 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1116 "to RTP/RTCP receiver",
1117 codec.plname, codec.pltype, codec.plfreq,
1118 codec.channels, codec.rate);
1119 }
1120 else
1121 {
1122 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1123 VoEId(_instanceId,_channelId),
1124 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1125 "the RTP/RTCP receiver",
1126 codec.plname, codec.pltype, codec.plfreq,
1127 codec.channels, codec.rate);
1128 }
1129
1130 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001131 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 {
1133 SetSendCodec(codec);
1134 }
1135
1136 // Register default PT for outband 'telephone-event'
1137 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1138 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001139 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001140 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001141 {
1142 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1143 VoEId(_instanceId,_channelId),
1144 "Channel::Init() failed to register outband "
1145 "'telephone-event' (%d/%d) correctly",
1146 codec.pltype, codec.plfreq);
1147 }
1148 }
1149
1150 if (!STR_CASE_CMP(codec.plname, "CN"))
1151 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001152 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1153 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001154 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001155 {
1156 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1157 VoEId(_instanceId,_channelId),
1158 "Channel::Init() failed to register CN (%d/%d) "
1159 "correctly - 1",
1160 codec.pltype, codec.plfreq);
1161 }
1162 }
1163#ifdef WEBRTC_CODEC_RED
1164 // Register RED to the receiving side of the ACM.
1165 // We will not receive an OnInitializeDecoder() callback for RED.
1166 if (!STR_CASE_CMP(codec.plname, "RED"))
1167 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001168 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 {
1170 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1171 VoEId(_instanceId,_channelId),
1172 "Channel::Init() failed to register RED (%d/%d) "
1173 "correctly",
1174 codec.pltype, codec.plfreq);
1175 }
1176 }
1177#endif
1178 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001179
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001180 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1181 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1182 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001183 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001184 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1185 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1186 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 }
1188
1189 return 0;
1190}
1191
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001192int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001193Channel::SetEngineInformation(Statistics& engineStatistics,
1194 OutputMixer& outputMixer,
1195 voe::TransmitMixer& transmitMixer,
1196 ProcessThread& moduleProcessThread,
1197 AudioDeviceModule& audioDeviceModule,
1198 VoiceEngineObserver* voiceEngineObserver,
1199 CriticalSectionWrapper* callbackCritSect)
1200{
1201 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1202 "Channel::SetEngineInformation()");
1203 _engineStatisticsPtr = &engineStatistics;
1204 _outputMixerPtr = &outputMixer;
1205 _transmitMixerPtr = &transmitMixer,
1206 _moduleProcessThreadPtr = &moduleProcessThread;
1207 _audioDeviceModulePtr = &audioDeviceModule;
1208 _voiceEngineObserverPtr = voiceEngineObserver;
1209 _callbackCritSectPtr = callbackCritSect;
1210 return 0;
1211}
1212
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001213int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001214Channel::UpdateLocalTimeStamp()
1215{
1216
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001217 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 return 0;
1219}
1220
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001221int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001222Channel::StartPlayout()
1223{
1224 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1225 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001226 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 {
1228 return 0;
1229 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001230
1231 if (!_externalMixing) {
1232 // Add participant as candidates for mixing.
1233 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1234 {
1235 _engineStatisticsPtr->SetLastError(
1236 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1237 "StartPlayout() failed to add participant to mixer");
1238 return -1;
1239 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 }
1241
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001242 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001243 if (RegisterFilePlayingToMixer() != 0)
1244 return -1;
1245
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 return 0;
1247}
1248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001249int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001250Channel::StopPlayout()
1251{
1252 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1253 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001254 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001255 {
1256 return 0;
1257 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001258
1259 if (!_externalMixing) {
1260 // Remove participant as candidates for mixing
1261 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1262 {
1263 _engineStatisticsPtr->SetLastError(
1264 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1265 "StopPlayout() failed to remove participant from mixer");
1266 return -1;
1267 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001268 }
1269
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001270 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 _outputAudioLevel.Clear();
1272
1273 return 0;
1274}
1275
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001276int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001277Channel::StartSend()
1278{
1279 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1280 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001281 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001282 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001283 if (send_sequence_number_)
1284 SetInitSequenceNumber(send_sequence_number_);
1285
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001286 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001287 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001288 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001290 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001291
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001292 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 {
1294 _engineStatisticsPtr->SetLastError(
1295 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1296 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001297 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001298 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 return -1;
1300 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001301
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 return 0;
1303}
1304
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001305int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001306Channel::StopSend()
1307{
1308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1309 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001310 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001311 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001312 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001313 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001314 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001315
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001316 // Store the sequence number to be able to pick up the same sequence for
1317 // the next StartSend(). This is needed for restarting device, otherwise
1318 // it might cause libSRTP to complain about packets being replayed.
1319 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1320 // CL is landed. See issue
1321 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1322 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1323
niklase@google.com470e71d2011-07-07 08:21:25 +00001324 // Reset sending SSRC and sequence number and triggers direct transmission
1325 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001326 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1327 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 {
1329 _engineStatisticsPtr->SetLastError(
1330 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1331 "StartSend() RTP/RTCP failed to stop sending");
1332 }
1333
niklase@google.com470e71d2011-07-07 08:21:25 +00001334 return 0;
1335}
1336
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001337int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001338Channel::StartReceiving()
1339{
1340 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1341 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001342 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001343 {
1344 return 0;
1345 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001346 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 _numberOfDiscardedPackets = 0;
1348 return 0;
1349}
1350
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001351int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001352Channel::StopReceiving()
1353{
1354 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1355 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001356 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001357 {
1358 return 0;
1359 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001360
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001361 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001362 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001363 RegisterReceiveCodecsToRTPModule();
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001364 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001365 return 0;
1366}
1367
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001368int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001369Channel::SetNetEQPlayoutMode(NetEqModes mode)
1370{
1371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1372 "Channel::SetNetEQPlayoutMode()");
1373 AudioPlayoutMode playoutMode(voice);
1374 switch (mode)
1375 {
1376 case kNetEqDefault:
1377 playoutMode = voice;
1378 break;
1379 case kNetEqStreaming:
1380 playoutMode = streaming;
1381 break;
1382 case kNetEqFax:
1383 playoutMode = fax;
1384 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001385 case kNetEqOff:
1386 playoutMode = off;
1387 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001388 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001389 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 {
1391 _engineStatisticsPtr->SetLastError(
1392 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1393 "SetNetEQPlayoutMode() failed to set playout mode");
1394 return -1;
1395 }
1396 return 0;
1397}
1398
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001399int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001400Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1401{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001402 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 switch (playoutMode)
1404 {
1405 case voice:
1406 mode = kNetEqDefault;
1407 break;
1408 case streaming:
1409 mode = kNetEqStreaming;
1410 break;
1411 case fax:
1412 mode = kNetEqFax;
1413 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001414 case off:
1415 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001416 }
1417 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1418 VoEId(_instanceId,_channelId),
1419 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1420 return 0;
1421}
1422
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001423int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001424Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1425{
1426 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1427 "Channel::SetOnHoldStatus()");
1428 if (mode == kHoldSendAndPlay)
1429 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001430 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001431 _inputIsOnHold = enable;
1432 }
1433 else if (mode == kHoldPlayOnly)
1434 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001435 channel_state_.SetOutputIsOnHold(enable);
niklase@google.com470e71d2011-07-07 08:21:25 +00001436 }
1437 if (mode == kHoldSendOnly)
1438 {
1439 _inputIsOnHold = enable;
1440 }
1441 return 0;
1442}
1443
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001444int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001445Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1446{
1447 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1448 "Channel::GetOnHoldStatus()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001449 bool output_is_on_hold = channel_state_.Get().output_is_on_hold;
1450 enabled = (output_is_on_hold || _inputIsOnHold);
1451 if (output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
1453 mode = kHoldSendAndPlay;
1454 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001455 else if (output_is_on_hold && !_inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001456 {
1457 mode = kHoldPlayOnly;
1458 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001459 else if (!output_is_on_hold && _inputIsOnHold)
niklase@google.com470e71d2011-07-07 08:21:25 +00001460 {
1461 mode = kHoldSendOnly;
1462 }
1463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1464 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1465 enabled, mode);
1466 return 0;
1467}
1468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001469int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001470Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1471{
1472 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1473 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001474 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001475
1476 if (_voiceEngineObserverPtr)
1477 {
1478 _engineStatisticsPtr->SetLastError(
1479 VE_INVALID_OPERATION, kTraceError,
1480 "RegisterVoiceEngineObserver() observer already enabled");
1481 return -1;
1482 }
1483 _voiceEngineObserverPtr = &observer;
1484 return 0;
1485}
1486
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001487int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001488Channel::DeRegisterVoiceEngineObserver()
1489{
1490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1491 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001492 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001493
1494 if (!_voiceEngineObserverPtr)
1495 {
1496 _engineStatisticsPtr->SetLastError(
1497 VE_INVALID_OPERATION, kTraceWarning,
1498 "DeRegisterVoiceEngineObserver() observer already disabled");
1499 return 0;
1500 }
1501 _voiceEngineObserverPtr = NULL;
1502 return 0;
1503}
1504
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001505int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001506Channel::GetSendCodec(CodecInst& codec)
1507{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001508 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001509}
1510
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001511int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001512Channel::GetRecCodec(CodecInst& codec)
1513{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001514 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001515}
1516
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001517int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001518Channel::SetSendCodec(const CodecInst& codec)
1519{
1520 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1521 "Channel::SetSendCodec()");
1522
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001523 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001524 {
1525 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1526 "SetSendCodec() failed to register codec to ACM");
1527 return -1;
1528 }
1529
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001530 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001531 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001532 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1533 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
1535 WEBRTC_TRACE(
1536 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1537 "SetSendCodec() failed to register codec to"
1538 " RTP/RTCP module");
1539 return -1;
1540 }
1541 }
1542
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001543 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001544 {
1545 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1546 "SetSendCodec() failed to set audio packet size");
1547 return -1;
1548 }
1549
1550 return 0;
1551}
1552
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001553int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001554Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1555{
1556 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1557 "Channel::SetVADStatus(mode=%d)", mode);
1558 // To disable VAD, DTX must be disabled too
1559 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001560 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001561 {
1562 _engineStatisticsPtr->SetLastError(
1563 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1564 "SetVADStatus() failed to set VAD");
1565 return -1;
1566 }
1567 return 0;
1568}
1569
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001570int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001571Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1572{
1573 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1574 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001575 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001576 {
1577 _engineStatisticsPtr->SetLastError(
1578 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1579 "GetVADStatus() failed to get VAD status");
1580 return -1;
1581 }
1582 disabledDTX = !disabledDTX;
1583 return 0;
1584}
1585
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001586int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001587Channel::SetRecPayloadType(const CodecInst& codec)
1588{
1589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1590 "Channel::SetRecPayloadType()");
1591
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001592 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001593 {
1594 _engineStatisticsPtr->SetLastError(
1595 VE_ALREADY_PLAYING, kTraceError,
1596 "SetRecPayloadType() unable to set PT while playing");
1597 return -1;
1598 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001599 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001600 {
1601 _engineStatisticsPtr->SetLastError(
1602 VE_ALREADY_LISTENING, kTraceError,
1603 "SetRecPayloadType() unable to set PT while listening");
1604 return -1;
1605 }
1606
1607 if (codec.pltype == -1)
1608 {
1609 // De-register the selected codec (RTP/RTCP module and ACM)
1610
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001611 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001612 CodecInst rxCodec = codec;
1613
1614 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001615 rtp_payload_registry_->ReceivePayloadType(
1616 rxCodec.plname,
1617 rxCodec.plfreq,
1618 rxCodec.channels,
1619 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1620 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001621 rxCodec.pltype = pltype;
1622
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001623 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001624 {
1625 _engineStatisticsPtr->SetLastError(
1626 VE_RTP_RTCP_MODULE_ERROR,
1627 kTraceError,
1628 "SetRecPayloadType() RTP/RTCP-module deregistration "
1629 "failed");
1630 return -1;
1631 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001632 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001633 {
1634 _engineStatisticsPtr->SetLastError(
1635 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1636 "SetRecPayloadType() ACM deregistration failed - 1");
1637 return -1;
1638 }
1639 return 0;
1640 }
1641
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001642 if (rtp_receiver_->RegisterReceivePayload(
1643 codec.plname,
1644 codec.pltype,
1645 codec.plfreq,
1646 codec.channels,
1647 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001648 {
1649 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001650 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1651 if (rtp_receiver_->RegisterReceivePayload(
1652 codec.plname,
1653 codec.pltype,
1654 codec.plfreq,
1655 codec.channels,
1656 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001657 {
1658 _engineStatisticsPtr->SetLastError(
1659 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1660 "SetRecPayloadType() RTP/RTCP-module registration failed");
1661 return -1;
1662 }
1663 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001664 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001665 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001666 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1667 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001668 {
1669 _engineStatisticsPtr->SetLastError(
1670 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1671 "SetRecPayloadType() ACM registration failed - 1");
1672 return -1;
1673 }
1674 }
1675 return 0;
1676}
1677
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001678int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001679Channel::GetRecPayloadType(CodecInst& codec)
1680{
1681 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1682 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001683 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001684 if (rtp_payload_registry_->ReceivePayloadType(
1685 codec.plname,
1686 codec.plfreq,
1687 codec.channels,
1688 (codec.rate < 0) ? 0 : codec.rate,
1689 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001690 {
1691 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001692 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001693 "GetRecPayloadType() failed to retrieve RX payload type");
1694 return -1;
1695 }
1696 codec.pltype = payloadType;
1697 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1698 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1699 return 0;
1700}
1701
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001702int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001703Channel::SetAMREncFormat(AmrMode mode)
1704{
1705 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1706 "Channel::SetAMREncFormat()");
1707
1708 // ACM doesn't support AMR
1709 return -1;
1710}
1711
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001712int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001713Channel::SetAMRDecFormat(AmrMode mode)
1714{
1715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1716 "Channel::SetAMRDecFormat()");
1717
1718 // ACM doesn't support AMR
1719 return -1;
1720}
1721
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001722int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001723Channel::SetAMRWbEncFormat(AmrMode mode)
1724{
1725 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1726 "Channel::SetAMRWbEncFormat()");
1727
1728 // ACM doesn't support AMR
1729 return -1;
1730
1731}
1732
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001733int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001734Channel::SetAMRWbDecFormat(AmrMode mode)
1735{
1736 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1737 "Channel::SetAMRWbDecFormat()");
1738
1739 // ACM doesn't support AMR
1740 return -1;
1741}
1742
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001743int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001744Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1745{
1746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1747 "Channel::SetSendCNPayloadType()");
1748
1749 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001750 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001751 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001752 if (frequency == kFreq32000Hz)
1753 samplingFreqHz = 32000;
1754 else if (frequency == kFreq16000Hz)
1755 samplingFreqHz = 16000;
1756
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001757 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001758 {
1759 _engineStatisticsPtr->SetLastError(
1760 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1761 "SetSendCNPayloadType() failed to retrieve default CN codec "
1762 "settings");
1763 return -1;
1764 }
1765
1766 // Modify the payload type (must be set to dynamic range)
1767 codec.pltype = type;
1768
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001769 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001770 {
1771 _engineStatisticsPtr->SetLastError(
1772 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1773 "SetSendCNPayloadType() failed to register CN to ACM");
1774 return -1;
1775 }
1776
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001777 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001778 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001779 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1780 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001781 {
1782 _engineStatisticsPtr->SetLastError(
1783 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1784 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1785 "module");
1786 return -1;
1787 }
1788 }
1789 return 0;
1790}
1791
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001792int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001793Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1794{
1795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1796 "Channel::SetISACInitTargetRate()");
1797
1798 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001799 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001800 {
1801 _engineStatisticsPtr->SetLastError(
1802 VE_CODEC_ERROR, kTraceError,
1803 "SetISACInitTargetRate() failed to retrieve send codec");
1804 return -1;
1805 }
1806 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1807 {
1808 // This API is only valid if iSAC is setup to run in channel-adaptive
1809 // mode.
1810 // We do not validate the adaptive mode here. It is done later in the
1811 // ConfigISACBandwidthEstimator() API.
1812 _engineStatisticsPtr->SetLastError(
1813 VE_CODEC_ERROR, kTraceError,
1814 "SetISACInitTargetRate() send codec is not iSAC");
1815 return -1;
1816 }
1817
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001818 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001819 if (16000 == sendCodec.plfreq)
1820 {
1821 // Note that 0 is a valid and corresponds to "use default
1822 if ((rateBps != 0 &&
1823 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1824 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1825 {
1826 _engineStatisticsPtr->SetLastError(
1827 VE_INVALID_ARGUMENT, kTraceError,
1828 "SetISACInitTargetRate() invalid target rate - 1");
1829 return -1;
1830 }
1831 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001832 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001833 }
1834 else if (32000 == sendCodec.plfreq)
1835 {
1836 if ((rateBps != 0 &&
1837 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1838 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1839 {
1840 _engineStatisticsPtr->SetLastError(
1841 VE_INVALID_ARGUMENT, kTraceError,
1842 "SetISACInitTargetRate() invalid target rate - 2");
1843 return -1;
1844 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001845 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001846 }
1847
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001848 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001849 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1850 {
1851 _engineStatisticsPtr->SetLastError(
1852 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1853 "SetISACInitTargetRate() iSAC BWE config failed");
1854 return -1;
1855 }
1856
1857 return 0;
1858}
1859
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001860int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001861Channel::SetISACMaxRate(int rateBps)
1862{
1863 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1864 "Channel::SetISACMaxRate()");
1865
1866 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001867 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001868 {
1869 _engineStatisticsPtr->SetLastError(
1870 VE_CODEC_ERROR, kTraceError,
1871 "SetISACMaxRate() failed to retrieve send codec");
1872 return -1;
1873 }
1874 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1875 {
1876 // This API is only valid if iSAC is selected as sending codec.
1877 _engineStatisticsPtr->SetLastError(
1878 VE_CODEC_ERROR, kTraceError,
1879 "SetISACMaxRate() send codec is not iSAC");
1880 return -1;
1881 }
1882 if (16000 == sendCodec.plfreq)
1883 {
1884 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
1885 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
1886 {
1887 _engineStatisticsPtr->SetLastError(
1888 VE_INVALID_ARGUMENT, kTraceError,
1889 "SetISACMaxRate() invalid max rate - 1");
1890 return -1;
1891 }
1892 }
1893 else if (32000 == sendCodec.plfreq)
1894 {
1895 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
1896 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
1897 {
1898 _engineStatisticsPtr->SetLastError(
1899 VE_INVALID_ARGUMENT, kTraceError,
1900 "SetISACMaxRate() invalid max rate - 2");
1901 return -1;
1902 }
1903 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001904 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001905 {
1906 _engineStatisticsPtr->SetLastError(
1907 VE_SENDING, kTraceError,
1908 "SetISACMaxRate() unable to set max rate while sending");
1909 return -1;
1910 }
1911
1912 // Set the maximum instantaneous rate of iSAC (works for both adaptive
1913 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001914 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001915 {
1916 _engineStatisticsPtr->SetLastError(
1917 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1918 "SetISACMaxRate() failed to set max rate");
1919 return -1;
1920 }
1921
1922 return 0;
1923}
1924
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001925int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001926Channel::SetISACMaxPayloadSize(int sizeBytes)
1927{
1928 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1929 "Channel::SetISACMaxPayloadSize()");
1930 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001931 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001932 {
1933 _engineStatisticsPtr->SetLastError(
1934 VE_CODEC_ERROR, kTraceError,
1935 "SetISACMaxPayloadSize() failed to retrieve send codec");
1936 return -1;
1937 }
1938 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1939 {
1940 _engineStatisticsPtr->SetLastError(
1941 VE_CODEC_ERROR, kTraceError,
1942 "SetISACMaxPayloadSize() send codec is not iSAC");
1943 return -1;
1944 }
1945 if (16000 == sendCodec.plfreq)
1946 {
1947 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
1948 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
1949 {
1950 _engineStatisticsPtr->SetLastError(
1951 VE_INVALID_ARGUMENT, kTraceError,
1952 "SetISACMaxPayloadSize() invalid max payload - 1");
1953 return -1;
1954 }
1955 }
1956 else if (32000 == sendCodec.plfreq)
1957 {
1958 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
1959 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
1960 {
1961 _engineStatisticsPtr->SetLastError(
1962 VE_INVALID_ARGUMENT, kTraceError,
1963 "SetISACMaxPayloadSize() invalid max payload - 2");
1964 return -1;
1965 }
1966 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001967 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001968 {
1969 _engineStatisticsPtr->SetLastError(
1970 VE_SENDING, kTraceError,
1971 "SetISACMaxPayloadSize() unable to set max rate while sending");
1972 return -1;
1973 }
1974
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001975 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001976 {
1977 _engineStatisticsPtr->SetLastError(
1978 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1979 "SetISACMaxPayloadSize() failed to set max payload size");
1980 return -1;
1981 }
1982 return 0;
1983}
1984
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001985int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001986{
1987 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1988 "Channel::RegisterExternalTransport()");
1989
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001990 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001991
niklase@google.com470e71d2011-07-07 08:21:25 +00001992 if (_externalTransport)
1993 {
1994 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1995 kTraceError,
1996 "RegisterExternalTransport() external transport already enabled");
1997 return -1;
1998 }
1999 _externalTransport = true;
2000 _transportPtr = &transport;
2001 return 0;
2002}
2003
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002004int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002005Channel::DeRegisterExternalTransport()
2006{
2007 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2008 "Channel::DeRegisterExternalTransport()");
2009
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002010 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002011
niklase@google.com470e71d2011-07-07 08:21:25 +00002012 if (!_transportPtr)
2013 {
2014 _engineStatisticsPtr->SetLastError(
2015 VE_INVALID_OPERATION, kTraceWarning,
2016 "DeRegisterExternalTransport() external transport already "
2017 "disabled");
2018 return 0;
2019 }
2020 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 _transportPtr = NULL;
2022 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2023 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002024 return 0;
2025}
2026
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002027int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002028 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2029 "Channel::ReceivedRTPPacket()");
2030
2031 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002032 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002033
2034 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002035 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2036 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002037 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2038 VoEId(_instanceId,_channelId),
2039 "Channel::SendPacket() RTP dump to input file failed");
2040 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002041 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002042 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002043 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2044 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2045 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002046 return -1;
2047 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002048 header.payload_type_frequency =
2049 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002050 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002051 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002052 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002053 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002054 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002055 rtp_payload_registry_->SetIncomingPayloadType(header);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002056 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002057}
2058
2059bool Channel::ReceivePacket(const uint8_t* packet,
2060 int packet_length,
2061 const RTPHeader& header,
2062 bool in_order) {
2063 if (rtp_payload_registry_->IsEncapsulated(header)) {
2064 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002065 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002066 const uint8_t* payload = packet + header.headerLength;
2067 int payload_length = packet_length - header.headerLength;
2068 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002069 PayloadUnion payload_specific;
2070 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002071 &payload_specific)) {
2072 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002073 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002074 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2075 payload_specific, in_order);
2076}
2077
2078bool Channel::HandleEncapsulation(const uint8_t* packet,
2079 int packet_length,
2080 const RTPHeader& header) {
2081 if (!rtp_payload_registry_->IsRtx(header))
2082 return false;
2083
2084 // Remove the RTX header and parse the original RTP header.
2085 if (packet_length < header.headerLength)
2086 return false;
2087 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2088 return false;
2089 if (restored_packet_in_use_) {
2090 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2091 "Multiple RTX headers detected, dropping packet");
2092 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002093 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002094 uint8_t* restored_packet_ptr = restored_packet_;
2095 if (!rtp_payload_registry_->RestoreOriginalPacket(
2096 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2097 header)) {
2098 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2099 "Incoming RTX packet: invalid RTP header");
2100 return false;
2101 }
2102 restored_packet_in_use_ = true;
2103 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2104 restored_packet_in_use_ = false;
2105 return ret;
2106}
2107
2108bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2109 StreamStatistician* statistician =
2110 rtp_receive_statistics_->GetStatistician(header.ssrc);
2111 if (!statistician)
2112 return false;
2113 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002114}
2115
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002116bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2117 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002118 // Retransmissions are handled separately if RTX is enabled.
2119 if (rtp_payload_registry_->RtxEnabled())
2120 return false;
2121 StreamStatistician* statistician =
2122 rtp_receive_statistics_->GetStatistician(header.ssrc);
2123 if (!statistician)
2124 return false;
2125 // Check if this is a retransmission.
2126 uint16_t min_rtt = 0;
2127 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002128 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002129 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002130}
2131
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002132int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002133 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2134 "Channel::ReceivedRTCPPacket()");
2135 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002136 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002137
2138 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002139 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2140 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002141 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2142 VoEId(_instanceId,_channelId),
2143 "Channel::SendPacket() RTCP dump to input file failed");
2144 }
2145
2146 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002147 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2148 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002149 _engineStatisticsPtr->SetLastError(
2150 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2151 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2152 }
2153 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002154}
2155
niklase@google.com470e71d2011-07-07 08:21:25 +00002156int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002157 bool loop,
2158 FileFormats format,
2159 int startPosition,
2160 float volumeScaling,
2161 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002162 const CodecInst* codecInst)
2163{
2164 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2165 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2166 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2167 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2168 startPosition, stopPosition);
2169
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002170 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002171 {
2172 _engineStatisticsPtr->SetLastError(
2173 VE_ALREADY_PLAYING, kTraceError,
2174 "StartPlayingFileLocally() is already playing");
2175 return -1;
2176 }
2177
niklase@google.com470e71d2011-07-07 08:21:25 +00002178 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002179 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002180
2181 if (_outputFilePlayerPtr)
2182 {
2183 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2184 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2185 _outputFilePlayerPtr = NULL;
2186 }
2187
2188 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2189 _outputFilePlayerId, (const FileFormats)format);
2190
2191 if (_outputFilePlayerPtr == NULL)
2192 {
2193 _engineStatisticsPtr->SetLastError(
2194 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002195 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002196 return -1;
2197 }
2198
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002199 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002200
2201 if (_outputFilePlayerPtr->StartPlayingFile(
2202 fileName,
2203 loop,
2204 startPosition,
2205 volumeScaling,
2206 notificationTime,
2207 stopPosition,
2208 (const CodecInst*)codecInst) != 0)
2209 {
2210 _engineStatisticsPtr->SetLastError(
2211 VE_BAD_FILE, kTraceError,
2212 "StartPlayingFile() failed to start file playout");
2213 _outputFilePlayerPtr->StopPlayingFile();
2214 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2215 _outputFilePlayerPtr = NULL;
2216 return -1;
2217 }
2218 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002219 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002220 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002221
2222 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002223 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002224
2225 return 0;
2226}
2227
2228int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002229 FileFormats format,
2230 int startPosition,
2231 float volumeScaling,
2232 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002233 const CodecInst* codecInst)
2234{
2235 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2236 "Channel::StartPlayingFileLocally(format=%d,"
2237 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2238 format, volumeScaling, startPosition, stopPosition);
2239
2240 if(stream == NULL)
2241 {
2242 _engineStatisticsPtr->SetLastError(
2243 VE_BAD_FILE, kTraceError,
2244 "StartPlayingFileLocally() NULL as input stream");
2245 return -1;
2246 }
2247
2248
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002249 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002250 {
2251 _engineStatisticsPtr->SetLastError(
2252 VE_ALREADY_PLAYING, kTraceError,
2253 "StartPlayingFileLocally() is already playing");
2254 return -1;
2255 }
2256
niklase@google.com470e71d2011-07-07 08:21:25 +00002257 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002258 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002259
2260 // Destroy the old instance
2261 if (_outputFilePlayerPtr)
2262 {
2263 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2264 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2265 _outputFilePlayerPtr = NULL;
2266 }
2267
2268 // Create the instance
2269 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2270 _outputFilePlayerId,
2271 (const FileFormats)format);
2272
2273 if (_outputFilePlayerPtr == NULL)
2274 {
2275 _engineStatisticsPtr->SetLastError(
2276 VE_INVALID_ARGUMENT, kTraceError,
2277 "StartPlayingFileLocally() filePlayer format isnot correct");
2278 return -1;
2279 }
2280
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002281 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002282
2283 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2284 volumeScaling,
2285 notificationTime,
2286 stopPosition, codecInst) != 0)
2287 {
2288 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2289 "StartPlayingFile() failed to "
2290 "start file playout");
2291 _outputFilePlayerPtr->StopPlayingFile();
2292 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2293 _outputFilePlayerPtr = NULL;
2294 return -1;
2295 }
2296 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002297 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002298 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002299
2300 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002301 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002302
niklase@google.com470e71d2011-07-07 08:21:25 +00002303 return 0;
2304}
2305
2306int Channel::StopPlayingFileLocally()
2307{
2308 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2309 "Channel::StopPlayingFileLocally()");
2310
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002311 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002312 {
2313 _engineStatisticsPtr->SetLastError(
2314 VE_INVALID_OPERATION, kTraceWarning,
2315 "StopPlayingFileLocally() isnot playing");
2316 return 0;
2317 }
2318
niklase@google.com470e71d2011-07-07 08:21:25 +00002319 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002320 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002321
2322 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2323 {
2324 _engineStatisticsPtr->SetLastError(
2325 VE_STOP_RECORDING_FAILED, kTraceError,
2326 "StopPlayingFile() could not stop playing");
2327 return -1;
2328 }
2329 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2330 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2331 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002332 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002333 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002334 // _fileCritSect cannot be taken while calling
2335 // SetAnonymousMixibilityStatus. Refer to comments in
2336 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002337 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2338 {
2339 _engineStatisticsPtr->SetLastError(
2340 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002341 "StopPlayingFile() failed to stop participant from playing as"
2342 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002343 return -1;
2344 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002345
2346 return 0;
2347}
2348
2349int Channel::IsPlayingFileLocally() const
2350{
2351 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2352 "Channel::IsPlayingFileLocally()");
2353
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002354 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002355}
2356
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002357int Channel::RegisterFilePlayingToMixer()
2358{
2359 // Return success for not registering for file playing to mixer if:
2360 // 1. playing file before playout is started on that channel.
2361 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002362 if (!channel_state_.Get().playing ||
2363 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002364 {
2365 return 0;
2366 }
2367
2368 // |_fileCritSect| cannot be taken while calling
2369 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2370 // frames can be pulled by the mixer. Since the frames are generated from
2371 // the file, _fileCritSect will be taken. This would result in a deadlock.
2372 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2373 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002374 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002375 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002376 _engineStatisticsPtr->SetLastError(
2377 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2378 "StartPlayingFile() failed to add participant as file to mixer");
2379 _outputFilePlayerPtr->StopPlayingFile();
2380 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2381 _outputFilePlayerPtr = NULL;
2382 return -1;
2383 }
2384
2385 return 0;
2386}
2387
pbos@webrtc.org92135212013-05-14 08:31:39 +00002388int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002389{
2390 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2391 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2392
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002393 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002394
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002395 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002396 {
2397 _engineStatisticsPtr->SetLastError(
2398 VE_INVALID_OPERATION, kTraceError,
2399 "ScaleLocalFilePlayout() isnot playing");
2400 return -1;
2401 }
2402 if ((_outputFilePlayerPtr == NULL) ||
2403 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2404 {
2405 _engineStatisticsPtr->SetLastError(
2406 VE_BAD_ARGUMENT, kTraceError,
2407 "SetAudioScaling() failed to scale the playout");
2408 return -1;
2409 }
2410
2411 return 0;
2412}
2413
2414int Channel::GetLocalPlayoutPosition(int& positionMs)
2415{
2416 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2417 "Channel::GetLocalPlayoutPosition(position=?)");
2418
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002419 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002420
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002421 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002422
2423 if (_outputFilePlayerPtr == NULL)
2424 {
2425 _engineStatisticsPtr->SetLastError(
2426 VE_INVALID_OPERATION, kTraceError,
2427 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2428 return -1;
2429 }
2430
2431 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2432 {
2433 _engineStatisticsPtr->SetLastError(
2434 VE_BAD_FILE, kTraceError,
2435 "GetLocalPlayoutPosition() failed");
2436 return -1;
2437 }
2438 positionMs = position;
2439
2440 return 0;
2441}
2442
2443int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002444 bool loop,
2445 FileFormats format,
2446 int startPosition,
2447 float volumeScaling,
2448 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002449 const CodecInst* codecInst)
2450{
2451 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2452 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2453 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2454 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2455 startPosition, stopPosition);
2456
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002457 CriticalSectionScoped cs(&_fileCritSect);
2458
2459 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002460 {
2461 _engineStatisticsPtr->SetLastError(
2462 VE_ALREADY_PLAYING, kTraceWarning,
2463 "StartPlayingFileAsMicrophone() filePlayer is playing");
2464 return 0;
2465 }
2466
niklase@google.com470e71d2011-07-07 08:21:25 +00002467 // Destroy the old instance
2468 if (_inputFilePlayerPtr)
2469 {
2470 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2471 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2472 _inputFilePlayerPtr = NULL;
2473 }
2474
2475 // Create the instance
2476 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2477 _inputFilePlayerId, (const FileFormats)format);
2478
2479 if (_inputFilePlayerPtr == NULL)
2480 {
2481 _engineStatisticsPtr->SetLastError(
2482 VE_INVALID_ARGUMENT, kTraceError,
2483 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2484 return -1;
2485 }
2486
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002487 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002488
2489 if (_inputFilePlayerPtr->StartPlayingFile(
2490 fileName,
2491 loop,
2492 startPosition,
2493 volumeScaling,
2494 notificationTime,
2495 stopPosition,
2496 (const CodecInst*)codecInst) != 0)
2497 {
2498 _engineStatisticsPtr->SetLastError(
2499 VE_BAD_FILE, kTraceError,
2500 "StartPlayingFile() failed to start file playout");
2501 _inputFilePlayerPtr->StopPlayingFile();
2502 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2503 _inputFilePlayerPtr = NULL;
2504 return -1;
2505 }
2506 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002507 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002508
2509 return 0;
2510}
2511
2512int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002513 FileFormats format,
2514 int startPosition,
2515 float volumeScaling,
2516 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002517 const CodecInst* codecInst)
2518{
2519 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2520 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2521 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2522 format, volumeScaling, startPosition, stopPosition);
2523
2524 if(stream == NULL)
2525 {
2526 _engineStatisticsPtr->SetLastError(
2527 VE_BAD_FILE, kTraceError,
2528 "StartPlayingFileAsMicrophone NULL as input stream");
2529 return -1;
2530 }
2531
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002532 CriticalSectionScoped cs(&_fileCritSect);
2533
2534 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002535 {
2536 _engineStatisticsPtr->SetLastError(
2537 VE_ALREADY_PLAYING, kTraceWarning,
2538 "StartPlayingFileAsMicrophone() is playing");
2539 return 0;
2540 }
2541
niklase@google.com470e71d2011-07-07 08:21:25 +00002542 // Destroy the old instance
2543 if (_inputFilePlayerPtr)
2544 {
2545 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2546 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2547 _inputFilePlayerPtr = NULL;
2548 }
2549
2550 // Create the instance
2551 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2552 _inputFilePlayerId, (const FileFormats)format);
2553
2554 if (_inputFilePlayerPtr == NULL)
2555 {
2556 _engineStatisticsPtr->SetLastError(
2557 VE_INVALID_ARGUMENT, kTraceError,
2558 "StartPlayingInputFile() filePlayer format isnot correct");
2559 return -1;
2560 }
2561
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002562 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002563
2564 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2565 volumeScaling, notificationTime,
2566 stopPosition, codecInst) != 0)
2567 {
2568 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2569 "StartPlayingFile() failed to start "
2570 "file playout");
2571 _inputFilePlayerPtr->StopPlayingFile();
2572 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2573 _inputFilePlayerPtr = NULL;
2574 return -1;
2575 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002576
niklase@google.com470e71d2011-07-07 08:21:25 +00002577 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002578 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002579
2580 return 0;
2581}
2582
2583int Channel::StopPlayingFileAsMicrophone()
2584{
2585 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2586 "Channel::StopPlayingFileAsMicrophone()");
2587
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002588 CriticalSectionScoped cs(&_fileCritSect);
2589
2590 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002591 {
2592 _engineStatisticsPtr->SetLastError(
2593 VE_INVALID_OPERATION, kTraceWarning,
2594 "StopPlayingFileAsMicrophone() isnot playing");
2595 return 0;
2596 }
2597
niklase@google.com470e71d2011-07-07 08:21:25 +00002598 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2599 {
2600 _engineStatisticsPtr->SetLastError(
2601 VE_STOP_RECORDING_FAILED, kTraceError,
2602 "StopPlayingFile() could not stop playing");
2603 return -1;
2604 }
2605 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2606 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2607 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002608 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002609
2610 return 0;
2611}
2612
2613int Channel::IsPlayingFileAsMicrophone() const
2614{
2615 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2616 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002617 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002618}
2619
pbos@webrtc.org92135212013-05-14 08:31:39 +00002620int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002621{
2622 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2623 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2624
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002625 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002626
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002627 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002628 {
2629 _engineStatisticsPtr->SetLastError(
2630 VE_INVALID_OPERATION, kTraceError,
2631 "ScaleFileAsMicrophonePlayout() isnot playing");
2632 return -1;
2633 }
2634
2635 if ((_inputFilePlayerPtr == NULL) ||
2636 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2637 {
2638 _engineStatisticsPtr->SetLastError(
2639 VE_BAD_ARGUMENT, kTraceError,
2640 "SetAudioScaling() failed to scale playout");
2641 return -1;
2642 }
2643
2644 return 0;
2645}
2646
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002647int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002648 const CodecInst* codecInst)
2649{
2650 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2651 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2652
2653 if (_outputFileRecording)
2654 {
2655 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2656 "StartRecordingPlayout() is already recording");
2657 return 0;
2658 }
2659
2660 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002661 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002662 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2663
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002664 if ((codecInst != NULL) &&
2665 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002666 {
2667 _engineStatisticsPtr->SetLastError(
2668 VE_BAD_ARGUMENT, kTraceError,
2669 "StartRecordingPlayout() invalid compression");
2670 return(-1);
2671 }
2672 if(codecInst == NULL)
2673 {
2674 format = kFileFormatPcm16kHzFile;
2675 codecInst=&dummyCodec;
2676 }
2677 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2678 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2679 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2680 {
2681 format = kFileFormatWavFile;
2682 }
2683 else
2684 {
2685 format = kFileFormatCompressedFile;
2686 }
2687
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002688 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002689
2690 // Destroy the old instance
2691 if (_outputFileRecorderPtr)
2692 {
2693 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2694 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2695 _outputFileRecorderPtr = NULL;
2696 }
2697
2698 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2699 _outputFileRecorderId, (const FileFormats)format);
2700 if (_outputFileRecorderPtr == NULL)
2701 {
2702 _engineStatisticsPtr->SetLastError(
2703 VE_INVALID_ARGUMENT, kTraceError,
2704 "StartRecordingPlayout() fileRecorder format isnot correct");
2705 return -1;
2706 }
2707
2708 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2709 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2710 {
2711 _engineStatisticsPtr->SetLastError(
2712 VE_BAD_FILE, kTraceError,
2713 "StartRecordingAudioFile() failed to start file recording");
2714 _outputFileRecorderPtr->StopRecording();
2715 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2716 _outputFileRecorderPtr = NULL;
2717 return -1;
2718 }
2719 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2720 _outputFileRecording = true;
2721
2722 return 0;
2723}
2724
2725int Channel::StartRecordingPlayout(OutStream* stream,
2726 const CodecInst* codecInst)
2727{
2728 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2729 "Channel::StartRecordingPlayout()");
2730
2731 if (_outputFileRecording)
2732 {
2733 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2734 "StartRecordingPlayout() is already recording");
2735 return 0;
2736 }
2737
2738 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002739 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002740 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2741
2742 if (codecInst != NULL && codecInst->channels != 1)
2743 {
2744 _engineStatisticsPtr->SetLastError(
2745 VE_BAD_ARGUMENT, kTraceError,
2746 "StartRecordingPlayout() invalid compression");
2747 return(-1);
2748 }
2749 if(codecInst == NULL)
2750 {
2751 format = kFileFormatPcm16kHzFile;
2752 codecInst=&dummyCodec;
2753 }
2754 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2755 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2756 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2757 {
2758 format = kFileFormatWavFile;
2759 }
2760 else
2761 {
2762 format = kFileFormatCompressedFile;
2763 }
2764
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002765 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002766
2767 // Destroy the old instance
2768 if (_outputFileRecorderPtr)
2769 {
2770 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2771 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2772 _outputFileRecorderPtr = NULL;
2773 }
2774
2775 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2776 _outputFileRecorderId, (const FileFormats)format);
2777 if (_outputFileRecorderPtr == NULL)
2778 {
2779 _engineStatisticsPtr->SetLastError(
2780 VE_INVALID_ARGUMENT, kTraceError,
2781 "StartRecordingPlayout() fileRecorder format isnot correct");
2782 return -1;
2783 }
2784
2785 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2786 notificationTime) != 0)
2787 {
2788 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2789 "StartRecordingPlayout() failed to "
2790 "start file recording");
2791 _outputFileRecorderPtr->StopRecording();
2792 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2793 _outputFileRecorderPtr = NULL;
2794 return -1;
2795 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002796
niklase@google.com470e71d2011-07-07 08:21:25 +00002797 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2798 _outputFileRecording = true;
2799
2800 return 0;
2801}
2802
2803int Channel::StopRecordingPlayout()
2804{
2805 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2806 "Channel::StopRecordingPlayout()");
2807
2808 if (!_outputFileRecording)
2809 {
2810 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2811 "StopRecordingPlayout() isnot recording");
2812 return -1;
2813 }
2814
2815
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002816 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002817
2818 if (_outputFileRecorderPtr->StopRecording() != 0)
2819 {
2820 _engineStatisticsPtr->SetLastError(
2821 VE_STOP_RECORDING_FAILED, kTraceError,
2822 "StopRecording() could not stop recording");
2823 return(-1);
2824 }
2825 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2826 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2827 _outputFileRecorderPtr = NULL;
2828 _outputFileRecording = false;
2829
2830 return 0;
2831}
2832
2833void
2834Channel::SetMixWithMicStatus(bool mix)
2835{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002836 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002837 _mixFileWithMicrophone=mix;
2838}
2839
2840int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002841Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002842{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002843 int8_t currentLevel = _outputAudioLevel.Level();
2844 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002845 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2846 VoEId(_instanceId,_channelId),
2847 "GetSpeechOutputLevel() => level=%u", level);
2848 return 0;
2849}
2850
2851int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002852Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002853{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002854 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2855 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002856 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2857 VoEId(_instanceId,_channelId),
2858 "GetSpeechOutputLevelFullRange() => level=%u", level);
2859 return 0;
2860}
2861
2862int
2863Channel::SetMute(bool enable)
2864{
wu@webrtc.org63420662013-10-17 18:28:55 +00002865 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002866 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2867 "Channel::SetMute(enable=%d)", enable);
2868 _mute = enable;
2869 return 0;
2870}
2871
2872bool
2873Channel::Mute() const
2874{
wu@webrtc.org63420662013-10-17 18:28:55 +00002875 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002876 return _mute;
2877}
2878
2879int
2880Channel::SetOutputVolumePan(float left, float right)
2881{
wu@webrtc.org63420662013-10-17 18:28:55 +00002882 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002883 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2884 "Channel::SetOutputVolumePan()");
2885 _panLeft = left;
2886 _panRight = right;
2887 return 0;
2888}
2889
2890int
2891Channel::GetOutputVolumePan(float& left, float& right) 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 left = _panLeft;
2895 right = _panRight;
2896 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2897 VoEId(_instanceId,_channelId),
2898 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2899 return 0;
2900}
2901
2902int
2903Channel::SetChannelOutputVolumeScaling(float scaling)
2904{
wu@webrtc.org63420662013-10-17 18:28:55 +00002905 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002906 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2907 "Channel::SetChannelOutputVolumeScaling()");
2908 _outputGain = scaling;
2909 return 0;
2910}
2911
2912int
2913Channel::GetChannelOutputVolumeScaling(float& scaling) const
2914{
wu@webrtc.org63420662013-10-17 18:28:55 +00002915 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002916 scaling = _outputGain;
2917 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2918 VoEId(_instanceId,_channelId),
2919 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2920 return 0;
2921}
2922
niklase@google.com470e71d2011-07-07 08:21:25 +00002923int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002924 int lengthMs, int attenuationDb,
2925 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002926{
2927 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2928 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2929 playDtmfEvent);
2930
2931 _playOutbandDtmfEvent = playDtmfEvent;
2932
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002933 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002934 attenuationDb) != 0)
2935 {
2936 _engineStatisticsPtr->SetLastError(
2937 VE_SEND_DTMF_FAILED,
2938 kTraceWarning,
2939 "SendTelephoneEventOutband() failed to send event");
2940 return -1;
2941 }
2942 return 0;
2943}
2944
2945int Channel::SendTelephoneEventInband(unsigned char eventCode,
2946 int lengthMs,
2947 int attenuationDb,
2948 bool playDtmfEvent)
2949{
2950 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2951 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2952 playDtmfEvent);
2953
2954 _playInbandDtmfEvent = playDtmfEvent;
2955 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2956
2957 return 0;
2958}
2959
2960int
2961Channel::SetDtmfPlayoutStatus(bool enable)
2962{
2963 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2964 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002965 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002966 {
2967 _engineStatisticsPtr->SetLastError(
2968 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2969 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2970 return -1;
2971 }
2972 return 0;
2973}
2974
2975bool
2976Channel::DtmfPlayoutStatus() const
2977{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002978 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002979}
2980
2981int
2982Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2983{
2984 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2985 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002986 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002987 {
2988 _engineStatisticsPtr->SetLastError(
2989 VE_INVALID_ARGUMENT, kTraceError,
2990 "SetSendTelephoneEventPayloadType() invalid type");
2991 return -1;
2992 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002993 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002994 codec.plfreq = 8000;
2995 codec.pltype = type;
2996 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002997 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002998 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002999 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3000 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3001 _engineStatisticsPtr->SetLastError(
3002 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3003 "SetSendTelephoneEventPayloadType() failed to register send"
3004 "payload type");
3005 return -1;
3006 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003007 }
3008 _sendTelephoneEventPayloadType = type;
3009 return 0;
3010}
3011
3012int
3013Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3014{
3015 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3016 "Channel::GetSendTelephoneEventPayloadType()");
3017 type = _sendTelephoneEventPayloadType;
3018 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3019 VoEId(_instanceId,_channelId),
3020 "GetSendTelephoneEventPayloadType() => type=%u", type);
3021 return 0;
3022}
3023
niklase@google.com470e71d2011-07-07 08:21:25 +00003024int
3025Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3026{
3027 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3028 "Channel::UpdateRxVadDetection()");
3029
3030 int vadDecision = 1;
3031
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003032 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003033
3034 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3035 {
3036 OnRxVadDetected(vadDecision);
3037 _oldVadDecision = vadDecision;
3038 }
3039
3040 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3041 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3042 vadDecision);
3043 return 0;
3044}
3045
3046int
3047Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3048{
3049 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3050 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003051 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003052
3053 if (_rxVadObserverPtr)
3054 {
3055 _engineStatisticsPtr->SetLastError(
3056 VE_INVALID_OPERATION, kTraceError,
3057 "RegisterRxVadObserver() observer already enabled");
3058 return -1;
3059 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003060 _rxVadObserverPtr = &observer;
3061 _RxVadDetection = true;
3062 return 0;
3063}
3064
3065int
3066Channel::DeRegisterRxVadObserver()
3067{
3068 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3069 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003070 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003071
3072 if (!_rxVadObserverPtr)
3073 {
3074 _engineStatisticsPtr->SetLastError(
3075 VE_INVALID_OPERATION, kTraceWarning,
3076 "DeRegisterRxVadObserver() observer already disabled");
3077 return 0;
3078 }
3079 _rxVadObserverPtr = NULL;
3080 _RxVadDetection = false;
3081 return 0;
3082}
3083
3084int
3085Channel::VoiceActivityIndicator(int &activity)
3086{
3087 activity = _sendFrameType;
3088
3089 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003090 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003091 return 0;
3092}
3093
3094#ifdef WEBRTC_VOICE_ENGINE_AGC
3095
3096int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003097Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003098{
3099 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3100 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3101 (int)enable, (int)mode);
3102
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003103 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003104 switch (mode)
3105 {
3106 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003107 break;
3108 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003109 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003110 break;
3111 case kAgcFixedDigital:
3112 agcMode = GainControl::kFixedDigital;
3113 break;
3114 case kAgcAdaptiveDigital:
3115 agcMode =GainControl::kAdaptiveDigital;
3116 break;
3117 default:
3118 _engineStatisticsPtr->SetLastError(
3119 VE_INVALID_ARGUMENT, kTraceError,
3120 "SetRxAgcStatus() invalid Agc mode");
3121 return -1;
3122 }
3123
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003124 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 {
3126 _engineStatisticsPtr->SetLastError(
3127 VE_APM_ERROR, kTraceError,
3128 "SetRxAgcStatus() failed to set Agc mode");
3129 return -1;
3130 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003131 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003132 {
3133 _engineStatisticsPtr->SetLastError(
3134 VE_APM_ERROR, kTraceError,
3135 "SetRxAgcStatus() failed to set Agc state");
3136 return -1;
3137 }
3138
3139 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003140 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003141
3142 return 0;
3143}
3144
3145int
3146Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3147{
3148 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3149 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3150
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003151 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003152 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003153 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003154
3155 enabled = enable;
3156
3157 switch (agcMode)
3158 {
3159 case GainControl::kFixedDigital:
3160 mode = kAgcFixedDigital;
3161 break;
3162 case GainControl::kAdaptiveDigital:
3163 mode = kAgcAdaptiveDigital;
3164 break;
3165 default:
3166 _engineStatisticsPtr->SetLastError(
3167 VE_APM_ERROR, kTraceError,
3168 "GetRxAgcStatus() invalid Agc mode");
3169 return -1;
3170 }
3171
3172 return 0;
3173}
3174
3175int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003176Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003177{
3178 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3179 "Channel::SetRxAgcConfig()");
3180
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003181 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003182 config.targetLeveldBOv) != 0)
3183 {
3184 _engineStatisticsPtr->SetLastError(
3185 VE_APM_ERROR, kTraceError,
3186 "SetRxAgcConfig() failed to set target peak |level|"
3187 "(or envelope) of the Agc");
3188 return -1;
3189 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003190 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003191 config.digitalCompressionGaindB) != 0)
3192 {
3193 _engineStatisticsPtr->SetLastError(
3194 VE_APM_ERROR, kTraceError,
3195 "SetRxAgcConfig() failed to set the range in |gain| the"
3196 " digital compression stage may apply");
3197 return -1;
3198 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003199 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003200 config.limiterEnable) != 0)
3201 {
3202 _engineStatisticsPtr->SetLastError(
3203 VE_APM_ERROR, kTraceError,
3204 "SetRxAgcConfig() failed to set hard limiter to the signal");
3205 return -1;
3206 }
3207
3208 return 0;
3209}
3210
3211int
3212Channel::GetRxAgcConfig(AgcConfig& config)
3213{
3214 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3215 "Channel::GetRxAgcConfig(config=%?)");
3216
3217 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003218 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003219 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003220 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003221 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003222 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003223
3224 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3225 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3226 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3227 " limiterEnable=%d",
3228 config.targetLeveldBOv,
3229 config.digitalCompressionGaindB,
3230 config.limiterEnable);
3231
3232 return 0;
3233}
3234
3235#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3236
3237#ifdef WEBRTC_VOICE_ENGINE_NR
3238
3239int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003240Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003241{
3242 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3243 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3244 (int)enable, (int)mode);
3245
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003246 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003247 switch (mode)
3248 {
3249
3250 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003251 break;
3252 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003253 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003254 break;
3255 case kNsConference:
3256 nsLevel = NoiseSuppression::kHigh;
3257 break;
3258 case kNsLowSuppression:
3259 nsLevel = NoiseSuppression::kLow;
3260 break;
3261 case kNsModerateSuppression:
3262 nsLevel = NoiseSuppression::kModerate;
3263 break;
3264 case kNsHighSuppression:
3265 nsLevel = NoiseSuppression::kHigh;
3266 break;
3267 case kNsVeryHighSuppression:
3268 nsLevel = NoiseSuppression::kVeryHigh;
3269 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003270 }
3271
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003272 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003273 != 0)
3274 {
3275 _engineStatisticsPtr->SetLastError(
3276 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003277 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003278 return -1;
3279 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003280 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003281 {
3282 _engineStatisticsPtr->SetLastError(
3283 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003284 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003285 return -1;
3286 }
3287
3288 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003289 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00003290
3291 return 0;
3292}
3293
3294int
3295Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3296{
3297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3298 "Channel::GetRxNsStatus(enable=?, mode=?)");
3299
3300 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003301 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003302 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003303 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003304
3305 enabled = enable;
3306
3307 switch (ncLevel)
3308 {
3309 case NoiseSuppression::kLow:
3310 mode = kNsLowSuppression;
3311 break;
3312 case NoiseSuppression::kModerate:
3313 mode = kNsModerateSuppression;
3314 break;
3315 case NoiseSuppression::kHigh:
3316 mode = kNsHighSuppression;
3317 break;
3318 case NoiseSuppression::kVeryHigh:
3319 mode = kNsVeryHighSuppression;
3320 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003321 }
3322
3323 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3324 VoEId(_instanceId,_channelId),
3325 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3326 return 0;
3327}
3328
3329#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3330
3331int
3332Channel::RegisterRTPObserver(VoERTPObserver& observer)
3333{
3334 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3335 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003336 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003337
3338 if (_rtpObserverPtr)
3339 {
3340 _engineStatisticsPtr->SetLastError(
3341 VE_INVALID_OPERATION, kTraceError,
3342 "RegisterRTPObserver() observer already enabled");
3343 return -1;
3344 }
3345
3346 _rtpObserverPtr = &observer;
3347 _rtpObserver = true;
3348
3349 return 0;
3350}
3351
3352int
3353Channel::DeRegisterRTPObserver()
3354{
3355 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3356 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003357 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003358
3359 if (!_rtpObserverPtr)
3360 {
3361 _engineStatisticsPtr->SetLastError(
3362 VE_INVALID_OPERATION, kTraceWarning,
3363 "DeRegisterRTPObserver() observer already disabled");
3364 return 0;
3365 }
3366
3367 _rtpObserver = false;
3368 _rtpObserverPtr = NULL;
3369
3370 return 0;
3371}
3372
3373int
3374Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3375{
3376 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3377 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003378 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003379
3380 if (_rtcpObserverPtr)
3381 {
3382 _engineStatisticsPtr->SetLastError(
3383 VE_INVALID_OPERATION, kTraceError,
3384 "RegisterRTCPObserver() observer already enabled");
3385 return -1;
3386 }
3387
3388 _rtcpObserverPtr = &observer;
3389 _rtcpObserver = true;
3390
3391 return 0;
3392}
3393
3394int
3395Channel::DeRegisterRTCPObserver()
3396{
3397 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3398 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003399 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003400
3401 if (!_rtcpObserverPtr)
3402 {
3403 _engineStatisticsPtr->SetLastError(
3404 VE_INVALID_OPERATION, kTraceWarning,
3405 "DeRegisterRTCPObserver() observer already disabled");
3406 return 0;
3407 }
3408
3409 _rtcpObserver = false;
3410 _rtcpObserverPtr = NULL;
3411
3412 return 0;
3413}
3414
3415int
3416Channel::SetLocalSSRC(unsigned int ssrc)
3417{
3418 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3419 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003420 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003421 {
3422 _engineStatisticsPtr->SetLastError(
3423 VE_ALREADY_SENDING, kTraceError,
3424 "SetLocalSSRC() already sending");
3425 return -1;
3426 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003427 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003428 {
3429 _engineStatisticsPtr->SetLastError(
3430 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3431 "SetLocalSSRC() failed to set SSRC");
3432 return -1;
3433 }
3434 return 0;
3435}
3436
3437int
3438Channel::GetLocalSSRC(unsigned int& ssrc)
3439{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003440 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003441 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3442 VoEId(_instanceId,_channelId),
3443 "GetLocalSSRC() => ssrc=%lu", ssrc);
3444 return 0;
3445}
3446
3447int
3448Channel::GetRemoteSSRC(unsigned int& ssrc)
3449{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003450 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003451 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3452 VoEId(_instanceId,_channelId),
3453 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3454 return 0;
3455}
3456
3457int
3458Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3459{
3460 if (arrCSRC == NULL)
3461 {
3462 _engineStatisticsPtr->SetLastError(
3463 VE_INVALID_ARGUMENT, kTraceError,
3464 "GetRemoteCSRCs() invalid array argument");
3465 return -1;
3466 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003467 uint32_t arrOfCSRC[kRtpCsrcSize];
3468 int32_t CSRCs(0);
braveyao@webrtc.orgcdefc912014-03-11 16:19:56 +00003469 CSRCs = rtp_receiver_->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003470 if (CSRCs > 0)
3471 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003472 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003473 for (int i = 0; i < (int) CSRCs; i++)
3474 {
3475 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3476 VoEId(_instanceId, _channelId),
3477 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3478 }
3479 } else
3480 {
3481 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3482 VoEId(_instanceId, _channelId),
3483 "GetRemoteCSRCs() => list is empty!");
3484 }
3485 return CSRCs;
3486}
3487
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003488int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003489 if (rtp_audioproc_.get() == NULL) {
3490 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3491 _channelId)));
3492 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003493
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003494 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3495 AudioProcessing::kNoError) {
3496 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3497 "Failed to enable AudioProcessing::level_estimator()");
3498 return -1;
3499 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003500
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003501 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003502
3503 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003504}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003505
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003506int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3507 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3508}
3509
3510int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3511 rtp_header_parser_->DeregisterRtpHeaderExtension(
3512 kRtpExtensionAbsoluteSendTime);
3513 if (enable) {
3514 if (!rtp_header_parser_->RegisterRtpHeaderExtension(
3515 kRtpExtensionAbsoluteSendTime, id)) {
3516 return -1;
3517 }
3518 }
3519 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003520}
3521
3522int
3523Channel::SetRTCPStatus(bool enable)
3524{
3525 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3526 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003527 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003528 kRtcpCompound : kRtcpOff) != 0)
3529 {
3530 _engineStatisticsPtr->SetLastError(
3531 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3532 "SetRTCPStatus() failed to set RTCP status");
3533 return -1;
3534 }
3535 return 0;
3536}
3537
3538int
3539Channel::GetRTCPStatus(bool& enabled)
3540{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003541 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003542 enabled = (method != kRtcpOff);
3543 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3544 VoEId(_instanceId,_channelId),
3545 "GetRTCPStatus() => enabled=%d", enabled);
3546 return 0;
3547}
3548
3549int
3550Channel::SetRTCP_CNAME(const char cName[256])
3551{
3552 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3553 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003554 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003555 {
3556 _engineStatisticsPtr->SetLastError(
3557 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3558 "SetRTCP_CNAME() failed to set RTCP CNAME");
3559 return -1;
3560 }
3561 return 0;
3562}
3563
3564int
3565Channel::GetRTCP_CNAME(char cName[256])
3566{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003567 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003568 {
3569 _engineStatisticsPtr->SetLastError(
3570 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3571 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3572 return -1;
3573 }
3574 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3575 VoEId(_instanceId, _channelId),
3576 "GetRTCP_CNAME() => cName=%s", cName);
3577 return 0;
3578}
3579
3580int
3581Channel::GetRemoteRTCP_CNAME(char cName[256])
3582{
3583 if (cName == NULL)
3584 {
3585 _engineStatisticsPtr->SetLastError(
3586 VE_INVALID_ARGUMENT, kTraceError,
3587 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3588 return -1;
3589 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003590 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003591 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003592 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003593 {
3594 _engineStatisticsPtr->SetLastError(
3595 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3596 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3597 return -1;
3598 }
3599 strcpy(cName, cname);
3600 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3601 VoEId(_instanceId, _channelId),
3602 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3603 return 0;
3604}
3605
3606int
3607Channel::GetRemoteRTCPData(
3608 unsigned int& NTPHigh,
3609 unsigned int& NTPLow,
3610 unsigned int& timestamp,
3611 unsigned int& playoutTimestamp,
3612 unsigned int* jitter,
3613 unsigned short* fractionLost)
3614{
3615 // --- Information from sender info in received Sender Reports
3616
3617 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003618 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003619 {
3620 _engineStatisticsPtr->SetLastError(
3621 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003622 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003623 "side");
3624 return -1;
3625 }
3626
3627 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3628 // and octet count)
3629 NTPHigh = senderInfo.NTPseconds;
3630 NTPLow = senderInfo.NTPfraction;
3631 timestamp = senderInfo.RTPtimeStamp;
3632
3633 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3634 VoEId(_instanceId, _channelId),
3635 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3636 "timestamp=%lu",
3637 NTPHigh, NTPLow, timestamp);
3638
3639 // --- Locally derived information
3640
3641 // This value is updated on each incoming RTCP packet (0 when no packet
3642 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003643 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003644
3645 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3646 VoEId(_instanceId, _channelId),
3647 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003648 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003649
3650 if (NULL != jitter || NULL != fractionLost)
3651 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003652 // Get all RTCP receiver report blocks that have been received on this
3653 // channel. If we receive RTP packets from a remote source we know the
3654 // remote SSRC and use the report block from him.
3655 // Otherwise use the first report block.
3656 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003657 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003658 remote_stats.empty()) {
3659 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3660 VoEId(_instanceId, _channelId),
3661 "GetRemoteRTCPData() failed to measure statistics due"
3662 " to lack of received RTP and/or RTCP packets");
3663 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003664 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003665
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003666 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003667 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3668 for (; it != remote_stats.end(); ++it) {
3669 if (it->remoteSSRC == remoteSSRC)
3670 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003671 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003672
3673 if (it == remote_stats.end()) {
3674 // If we have not received any RTCP packets from this SSRC it probably
3675 // means that we have not received any RTP packets.
3676 // Use the first received report block instead.
3677 it = remote_stats.begin();
3678 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003679 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003680
xians@webrtc.org79af7342012-01-31 12:22:14 +00003681 if (jitter) {
3682 *jitter = it->jitter;
3683 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3684 VoEId(_instanceId, _channelId),
3685 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3686 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003687
xians@webrtc.org79af7342012-01-31 12:22:14 +00003688 if (fractionLost) {
3689 *fractionLost = it->fractionLost;
3690 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3691 VoEId(_instanceId, _channelId),
3692 "GetRemoteRTCPData() => fractionLost = %lu",
3693 *fractionLost);
3694 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003695 }
3696 return 0;
3697}
3698
3699int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003700Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003701 unsigned int name,
3702 const char* data,
3703 unsigned short dataLengthInBytes)
3704{
3705 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3706 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003707 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003708 {
3709 _engineStatisticsPtr->SetLastError(
3710 VE_NOT_SENDING, kTraceError,
3711 "SendApplicationDefinedRTCPPacket() not sending");
3712 return -1;
3713 }
3714 if (NULL == data)
3715 {
3716 _engineStatisticsPtr->SetLastError(
3717 VE_INVALID_ARGUMENT, kTraceError,
3718 "SendApplicationDefinedRTCPPacket() invalid data value");
3719 return -1;
3720 }
3721 if (dataLengthInBytes % 4 != 0)
3722 {
3723 _engineStatisticsPtr->SetLastError(
3724 VE_INVALID_ARGUMENT, kTraceError,
3725 "SendApplicationDefinedRTCPPacket() invalid length value");
3726 return -1;
3727 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003728 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003729 if (status == kRtcpOff)
3730 {
3731 _engineStatisticsPtr->SetLastError(
3732 VE_RTCP_ERROR, kTraceError,
3733 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3734 return -1;
3735 }
3736
3737 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003738 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003739 subType,
3740 name,
3741 (const unsigned char*) data,
3742 dataLengthInBytes) != 0)
3743 {
3744 _engineStatisticsPtr->SetLastError(
3745 VE_SEND_ERROR, kTraceError,
3746 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3747 return -1;
3748 }
3749 return 0;
3750}
3751
3752int
3753Channel::GetRTPStatistics(
3754 unsigned int& averageJitterMs,
3755 unsigned int& maxJitterMs,
3756 unsigned int& discardedPackets)
3757{
niklase@google.com470e71d2011-07-07 08:21:25 +00003758 // The jitter statistics is updated for each received RTP packet and is
3759 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003760 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3761 // If RTCP is off, there is no timed thread in the RTCP module regularly
3762 // generating new stats, trigger the update manually here instead.
3763 StreamStatistician* statistician =
3764 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3765 if (statistician) {
3766 // Don't use returned statistics, use data from proxy instead so that
3767 // max jitter can be fetched atomically.
3768 RtcpStatistics s;
3769 statistician->GetStatistics(&s, true);
3770 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003771 }
3772
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003773 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003774 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003775 if (playoutFrequency > 0) {
3776 // Scale RTP statistics given the current playout frequency
3777 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3778 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003779 }
3780
3781 discardedPackets = _numberOfDiscardedPackets;
3782
3783 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3784 VoEId(_instanceId, _channelId),
3785 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003786 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003787 averageJitterMs, maxJitterMs, discardedPackets);
3788 return 0;
3789}
3790
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003791int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3792 if (sender_info == NULL) {
3793 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3794 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3795 return -1;
3796 }
3797
3798 // Get the sender info from the latest received RTCP Sender Report.
3799 RTCPSenderInfo rtcp_sender_info;
3800 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3801 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3802 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3803 return -1;
3804 }
3805
3806 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3807 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3808 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3809 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3810 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3811 return 0;
3812}
3813
3814int Channel::GetRemoteRTCPReportBlocks(
3815 std::vector<ReportBlock>* report_blocks) {
3816 if (report_blocks == NULL) {
3817 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3818 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3819 return -1;
3820 }
3821
3822 // Get the report blocks from the latest received RTCP Sender or Receiver
3823 // Report. Each element in the vector contains the sender's SSRC and a
3824 // report block according to RFC 3550.
3825 std::vector<RTCPReportBlock> rtcp_report_blocks;
3826 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3827 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3828 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3829 return -1;
3830 }
3831
3832 if (rtcp_report_blocks.empty())
3833 return 0;
3834
3835 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3836 for (; it != rtcp_report_blocks.end(); ++it) {
3837 ReportBlock report_block;
3838 report_block.sender_SSRC = it->remoteSSRC;
3839 report_block.source_SSRC = it->sourceSSRC;
3840 report_block.fraction_lost = it->fractionLost;
3841 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3842 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3843 report_block.interarrival_jitter = it->jitter;
3844 report_block.last_SR_timestamp = it->lastSR;
3845 report_block.delay_since_last_SR = it->delaySinceLastSR;
3846 report_blocks->push_back(report_block);
3847 }
3848 return 0;
3849}
3850
niklase@google.com470e71d2011-07-07 08:21:25 +00003851int
3852Channel::GetRTPStatistics(CallStatistics& stats)
3853{
niklase@google.com470e71d2011-07-07 08:21:25 +00003854 // --- Part one of the final structure (four values)
3855
3856 // The jitter statistics is updated for each received RTP packet and is
3857 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003858 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003859 StreamStatistician* statistician =
3860 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3861 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003862 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3863 _engineStatisticsPtr->SetLastError(
3864 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3865 "GetRTPStatistics() failed to read RTP statistics from the "
3866 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003867 }
3868
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003869 stats.fractionLost = statistics.fraction_lost;
3870 stats.cumulativeLost = statistics.cumulative_lost;
3871 stats.extendedMax = statistics.extended_max_sequence_number;
3872 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003873
3874 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3875 VoEId(_instanceId, _channelId),
3876 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003877 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003878 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3879 stats.jitterSamples);
3880
3881 // --- Part two of the final structure (one value)
3882
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003883 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003884 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003885 if (method == kRtcpOff)
3886 {
3887 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3888 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003889 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003890 "measurements cannot be retrieved");
3891 } else
3892 {
3893 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003894 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003895 if (remoteSSRC > 0)
3896 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003897 uint16_t avgRTT(0);
3898 uint16_t maxRTT(0);
3899 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003900
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003901 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003902 != 0)
3903 {
3904 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3905 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003906 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003907 "the RTP/RTCP module");
3908 }
3909 } else
3910 {
3911 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3912 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003913 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003914 "RTP packets have been received yet");
3915 }
3916 }
3917
3918 stats.rttMs = static_cast<int> (RTT);
3919
3920 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3921 VoEId(_instanceId, _channelId),
3922 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3923
3924 // --- Part three of the final structure (four values)
3925
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003926 uint32_t bytesSent(0);
3927 uint32_t packetsSent(0);
3928 uint32_t bytesReceived(0);
3929 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003930
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003931 if (statistician) {
3932 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3933 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003934
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003935 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003936 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003937 {
3938 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3939 VoEId(_instanceId, _channelId),
3940 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003941 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003942 }
3943
3944 stats.bytesSent = bytesSent;
3945 stats.packetsSent = packetsSent;
3946 stats.bytesReceived = bytesReceived;
3947 stats.packetsReceived = packetsReceived;
3948
3949 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3950 VoEId(_instanceId, _channelId),
3951 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003952 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003953 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3954 stats.packetsReceived);
3955
3956 return 0;
3957}
3958
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003959int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3960 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3961 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003962
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003963 if (enable) {
3964 if (redPayloadtype < 0 || redPayloadtype > 127) {
3965 _engineStatisticsPtr->SetLastError(
3966 VE_PLTYPE_ERROR, kTraceError,
3967 "SetFECStatus() invalid RED payload type");
3968 return -1;
3969 }
3970
3971 if (SetRedPayloadType(redPayloadtype) < 0) {
3972 _engineStatisticsPtr->SetLastError(
3973 VE_CODEC_ERROR, kTraceError,
3974 "SetSecondarySendCodec() Failed to register RED ACM");
3975 return -1;
3976 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003977 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003978
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003979 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003980 _engineStatisticsPtr->SetLastError(
3981 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3982 "SetFECStatus() failed to set FEC state in the ACM");
3983 return -1;
3984 }
3985 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003986}
3987
3988int
3989Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
3990{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003991 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003992 if (enabled)
3993 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003994 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003995 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003996 {
3997 _engineStatisticsPtr->SetLastError(
3998 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3999 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4000 "module");
4001 return -1;
4002 }
4003 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4004 VoEId(_instanceId, _channelId),
4005 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4006 enabled, redPayloadtype);
4007 return 0;
4008 }
4009 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4010 VoEId(_instanceId, _channelId),
4011 "GetFECStatus() => enabled=%d", enabled);
4012 return 0;
4013}
4014
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004015void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4016 // None of these functions can fail.
4017 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004018 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4019 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004020 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004021 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004022 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004023 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004024}
4025
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004026// Called when we are missing one or more packets.
4027int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004028 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4029}
4030
niklase@google.com470e71d2011-07-07 08:21:25 +00004031int
niklase@google.com470e71d2011-07-07 08:21:25 +00004032Channel::StartRTPDump(const char fileNameUTF8[1024],
4033 RTPDirections direction)
4034{
4035 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4036 "Channel::StartRTPDump()");
4037 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4038 {
4039 _engineStatisticsPtr->SetLastError(
4040 VE_INVALID_ARGUMENT, kTraceError,
4041 "StartRTPDump() invalid RTP direction");
4042 return -1;
4043 }
4044 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4045 &_rtpDumpIn : &_rtpDumpOut;
4046 if (rtpDumpPtr == NULL)
4047 {
4048 assert(false);
4049 return -1;
4050 }
4051 if (rtpDumpPtr->IsActive())
4052 {
4053 rtpDumpPtr->Stop();
4054 }
4055 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4056 {
4057 _engineStatisticsPtr->SetLastError(
4058 VE_BAD_FILE, kTraceError,
4059 "StartRTPDump() failed to create file");
4060 return -1;
4061 }
4062 return 0;
4063}
4064
4065int
4066Channel::StopRTPDump(RTPDirections direction)
4067{
4068 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4069 "Channel::StopRTPDump()");
4070 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4071 {
4072 _engineStatisticsPtr->SetLastError(
4073 VE_INVALID_ARGUMENT, kTraceError,
4074 "StopRTPDump() invalid RTP direction");
4075 return -1;
4076 }
4077 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4078 &_rtpDumpIn : &_rtpDumpOut;
4079 if (rtpDumpPtr == NULL)
4080 {
4081 assert(false);
4082 return -1;
4083 }
4084 if (!rtpDumpPtr->IsActive())
4085 {
4086 return 0;
4087 }
4088 return rtpDumpPtr->Stop();
4089}
4090
4091bool
4092Channel::RTPDumpIsActive(RTPDirections direction)
4093{
4094 if ((direction != kRtpIncoming) &&
4095 (direction != kRtpOutgoing))
4096 {
4097 _engineStatisticsPtr->SetLastError(
4098 VE_INVALID_ARGUMENT, kTraceError,
4099 "RTPDumpIsActive() invalid RTP direction");
4100 return false;
4101 }
4102 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4103 &_rtpDumpIn : &_rtpDumpOut;
4104 return rtpDumpPtr->IsActive();
4105}
4106
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004107uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004108Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004109{
4110 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004111 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004112 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004113 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004114 return 0;
4115}
4116
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004117// TODO(xians): This method borrows quite some code from
4118// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4119// code duplication.
4120void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004121 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004122 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004123 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004124 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4125 static const int kMaxNumberOfFrames = 960;
4126 assert(number_of_frames <= kMaxNumberOfFrames);
4127
4128 // Get the send codec information for doing resampling or downmixing later on.
4129 CodecInst codec;
4130 GetSendCodec(codec);
4131 assert(codec.channels == 1 || codec.channels == 2);
4132 int support_sample_rate = std::min(32000,
4133 std::min(sample_rate, codec.plfreq));
4134
4135 // Downmix the data to mono if needed.
4136 const int16_t* audio_ptr = audio_data;
4137 if (number_of_channels == 2 && codec.channels == 1) {
4138 if (!mono_recording_audio_.get())
4139 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4140
4141 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4142 mono_recording_audio_.get());
4143 audio_ptr = mono_recording_audio_.get();
4144 }
4145
4146 // Resample the data to the sample rate that the codec is using.
4147 if (input_resampler_.InitializeIfNeeded(sample_rate,
4148 support_sample_rate,
4149 codec.channels)) {
4150 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4151 "Channel::Demultiplex() unable to resample");
4152 return;
4153 }
4154
4155 int out_length = input_resampler_.Resample(audio_ptr,
4156 number_of_frames * codec.channels,
4157 _audioFrame.data_,
4158 AudioFrame::kMaxDataSizeSamples);
4159 if (out_length == -1) {
4160 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4161 "Channel::Demultiplex() resampling failed");
4162 return;
4163 }
4164
4165 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4166 _audioFrame.timestamp_ = -1;
4167 _audioFrame.sample_rate_hz_ = support_sample_rate;
4168 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4169 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4170 _audioFrame.num_channels_ = codec.channels;
4171 _audioFrame.id_ = _channelId;
4172}
4173
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004174uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004175Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004176{
4177 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4178 "Channel::PrepareEncodeAndSend()");
4179
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004180 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004181 {
4182 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4183 "Channel::PrepareEncodeAndSend() invalid audio frame");
4184 return -1;
4185 }
4186
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004187 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00004188 {
4189 MixOrReplaceAudioWithFile(mixingFrequency);
4190 }
4191
wu@webrtc.org63420662013-10-17 18:28:55 +00004192 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004193 {
4194 AudioFrameOperations::Mute(_audioFrame);
4195 }
4196
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004197 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00004198 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004199 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004200 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004201 if (_inputExternalMediaCallbackPtr)
4202 {
4203 _inputExternalMediaCallbackPtr->Process(
4204 _channelId,
4205 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004206 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004207 _audioFrame.samples_per_channel_,
4208 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004209 isStereo);
4210 }
4211 }
4212
4213 InsertInbandDtmfTone();
4214
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00004215 if (_includeAudioLevelIndication) {
4216 // Performs level analysis only; does not affect the signal.
4217 int err = rtp_audioproc_->ProcessStream(&_audioFrame);
4218 if (err) {
4219 LOG(LS_ERROR) << "ProcessStream() error: " << err;
4220 assert(false);
4221 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004222 }
4223
niklase@google.com470e71d2011-07-07 08:21:25 +00004224 return 0;
4225}
4226
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004227uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004228Channel::EncodeAndSend()
4229{
4230 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4231 "Channel::EncodeAndSend()");
4232
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004233 assert(_audioFrame.num_channels_ <= 2);
4234 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004235 {
4236 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4237 "Channel::EncodeAndSend() invalid audio frame");
4238 return -1;
4239 }
4240
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004241 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004242
4243 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4244
4245 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004246 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004247 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004248 {
4249 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4250 "Channel::EncodeAndSend() ACM encoding failed");
4251 return -1;
4252 }
4253
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004254 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004255
4256 // --- Encode if complete frame is ready
4257
4258 // This call will trigger AudioPacketizationCallback::SendData if encoding
4259 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004260 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004261}
4262
4263int Channel::RegisterExternalMediaProcessing(
4264 ProcessingTypes type,
4265 VoEMediaProcess& processObject)
4266{
4267 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4268 "Channel::RegisterExternalMediaProcessing()");
4269
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004270 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004271
4272 if (kPlaybackPerChannel == type)
4273 {
4274 if (_outputExternalMediaCallbackPtr)
4275 {
4276 _engineStatisticsPtr->SetLastError(
4277 VE_INVALID_OPERATION, kTraceError,
4278 "Channel::RegisterExternalMediaProcessing() "
4279 "output external media already enabled");
4280 return -1;
4281 }
4282 _outputExternalMediaCallbackPtr = &processObject;
4283 _outputExternalMedia = true;
4284 }
4285 else if (kRecordingPerChannel == type)
4286 {
4287 if (_inputExternalMediaCallbackPtr)
4288 {
4289 _engineStatisticsPtr->SetLastError(
4290 VE_INVALID_OPERATION, kTraceError,
4291 "Channel::RegisterExternalMediaProcessing() "
4292 "output external media already enabled");
4293 return -1;
4294 }
4295 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004296 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00004297 }
4298 return 0;
4299}
4300
4301int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4302{
4303 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4304 "Channel::DeRegisterExternalMediaProcessing()");
4305
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004306 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004307
4308 if (kPlaybackPerChannel == type)
4309 {
4310 if (!_outputExternalMediaCallbackPtr)
4311 {
4312 _engineStatisticsPtr->SetLastError(
4313 VE_INVALID_OPERATION, kTraceWarning,
4314 "Channel::DeRegisterExternalMediaProcessing() "
4315 "output external media already disabled");
4316 return 0;
4317 }
4318 _outputExternalMedia = false;
4319 _outputExternalMediaCallbackPtr = NULL;
4320 }
4321 else if (kRecordingPerChannel == type)
4322 {
4323 if (!_inputExternalMediaCallbackPtr)
4324 {
4325 _engineStatisticsPtr->SetLastError(
4326 VE_INVALID_OPERATION, kTraceWarning,
4327 "Channel::DeRegisterExternalMediaProcessing() "
4328 "input external media already disabled");
4329 return 0;
4330 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004331 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00004332 _inputExternalMediaCallbackPtr = NULL;
4333 }
4334
4335 return 0;
4336}
4337
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004338int Channel::SetExternalMixing(bool enabled) {
4339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4340 "Channel::SetExternalMixing(enabled=%d)", enabled);
4341
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004342 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004343 {
4344 _engineStatisticsPtr->SetLastError(
4345 VE_INVALID_OPERATION, kTraceError,
4346 "Channel::SetExternalMixing() "
4347 "external mixing cannot be changed while playing.");
4348 return -1;
4349 }
4350
4351 _externalMixing = enabled;
4352
4353 return 0;
4354}
4355
niklase@google.com470e71d2011-07-07 08:21:25 +00004356int
4357Channel::ResetRTCPStatistics()
4358{
4359 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4360 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004361 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004362 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004363 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004364}
4365
4366int
4367Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4368{
4369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4370 "Channel::GetRoundTripTimeSummary()");
4371 // Override default module outputs for the case when RTCP is disabled.
4372 // This is done to ensure that we are backward compatible with the
4373 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004374 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004375 {
4376 delaysMs.min = -1;
4377 delaysMs.max = -1;
4378 delaysMs.average = -1;
4379 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4380 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4381 " valid RTT measurements cannot be retrieved");
4382 return 0;
4383 }
4384
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004385 uint32_t remoteSSRC;
4386 uint16_t RTT;
4387 uint16_t avgRTT;
4388 uint16_t maxRTT;
4389 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004390 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004391 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004392 if (remoteSSRC == 0)
4393 {
4394 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4395 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4396 " since no RTP packet has been received yet");
4397 }
4398
4399 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4400 // channel and SSRC. The SSRC is required to parse out the correct source
4401 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004402 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004403 {
4404 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4405 "GetRoundTripTimeSummary unable to retrieve RTT values"
4406 " from the RTCP layer");
4407 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4408 }
4409 else
4410 {
4411 delaysMs.min = minRTT;
4412 delaysMs.max = maxRTT;
4413 delaysMs.average = avgRTT;
4414 }
4415 return 0;
4416}
4417
4418int
4419Channel::GetNetworkStatistics(NetworkStatistics& stats)
4420{
4421 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4422 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004423 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004424 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004425 if (return_value >= 0) {
4426 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4427 }
4428 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004429}
4430
wu@webrtc.org24301a62013-12-13 19:17:43 +00004431void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4432 audio_coding_->GetDecodingCallStatistics(stats);
4433}
4434
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004435bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4436 int* playout_buffer_delay_ms) const {
4437 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004439 "Channel::GetDelayEstimate() no valid estimate.");
4440 return false;
4441 }
4442 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4443 _recPacketDelayMs;
4444 *playout_buffer_delay_ms = playout_delay_ms_;
4445 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4446 "Channel::GetDelayEstimate()");
4447 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004448}
4449
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004450int Channel::SetInitialPlayoutDelay(int delay_ms)
4451{
4452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4453 "Channel::SetInitialPlayoutDelay()");
4454 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4455 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4456 {
4457 _engineStatisticsPtr->SetLastError(
4458 VE_INVALID_ARGUMENT, kTraceError,
4459 "SetInitialPlayoutDelay() invalid min delay");
4460 return -1;
4461 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004462 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004463 {
4464 _engineStatisticsPtr->SetLastError(
4465 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4466 "SetInitialPlayoutDelay() failed to set min playout delay");
4467 return -1;
4468 }
4469 return 0;
4470}
4471
4472
niklase@google.com470e71d2011-07-07 08:21:25 +00004473int
4474Channel::SetMinimumPlayoutDelay(int delayMs)
4475{
4476 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4477 "Channel::SetMinimumPlayoutDelay()");
4478 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4479 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4480 {
4481 _engineStatisticsPtr->SetLastError(
4482 VE_INVALID_ARGUMENT, kTraceError,
4483 "SetMinimumPlayoutDelay() invalid min delay");
4484 return -1;
4485 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004486 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004487 {
4488 _engineStatisticsPtr->SetLastError(
4489 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4490 "SetMinimumPlayoutDelay() failed to set min playout delay");
4491 return -1;
4492 }
4493 return 0;
4494}
4495
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004496void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4497 uint32_t playout_timestamp = 0;
4498
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004499 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004500 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4501 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4502 " timestamp from the ACM");
4503 _engineStatisticsPtr->SetLastError(
4504 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4505 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4506 return;
4507 }
4508
4509 uint16_t delay_ms = 0;
4510 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4511 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4512 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4513 " delay from the ADM");
4514 _engineStatisticsPtr->SetLastError(
4515 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4516 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4517 return;
4518 }
4519
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004520 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004521 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004522 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004523 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4524 playout_frequency = 8000;
4525 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4526 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004527 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004528 }
4529
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004530 jitter_buffer_playout_timestamp_ = playout_timestamp;
4531
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004532 // Remove the playout delay.
4533 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4534
4535 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4536 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4537 playout_timestamp);
4538
4539 if (rtcp) {
4540 playout_timestamp_rtcp_ = playout_timestamp;
4541 } else {
4542 playout_timestamp_rtp_ = playout_timestamp;
4543 }
4544 playout_delay_ms_ = delay_ms;
4545}
4546
4547int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4548 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4549 "Channel::GetPlayoutTimestamp()");
4550 if (playout_timestamp_rtp_ == 0) {
4551 _engineStatisticsPtr->SetLastError(
4552 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4553 "GetPlayoutTimestamp() failed to retrieve timestamp");
4554 return -1;
4555 }
4556 timestamp = playout_timestamp_rtp_;
4557 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4558 VoEId(_instanceId,_channelId),
4559 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4560 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004561}
4562
4563int
4564Channel::SetInitTimestamp(unsigned int timestamp)
4565{
4566 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4567 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004568 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004569 {
4570 _engineStatisticsPtr->SetLastError(
4571 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4572 return -1;
4573 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004574 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004575 {
4576 _engineStatisticsPtr->SetLastError(
4577 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4578 "SetInitTimestamp() failed to set timestamp");
4579 return -1;
4580 }
4581 return 0;
4582}
4583
4584int
4585Channel::SetInitSequenceNumber(short sequenceNumber)
4586{
4587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4588 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004589 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004590 {
4591 _engineStatisticsPtr->SetLastError(
4592 VE_SENDING, kTraceError,
4593 "SetInitSequenceNumber() already sending");
4594 return -1;
4595 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004596 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004597 {
4598 _engineStatisticsPtr->SetLastError(
4599 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4600 "SetInitSequenceNumber() failed to set sequence number");
4601 return -1;
4602 }
4603 return 0;
4604}
4605
4606int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004607Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004608{
4609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4610 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004611 *rtpRtcpModule = _rtpRtcpModule.get();
4612 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004613 return 0;
4614}
4615
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004616// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4617// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004618int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004619Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004620{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004621 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004622 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004623
4624 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004625 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004626
4627 if (_inputFilePlayerPtr == NULL)
4628 {
4629 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4630 VoEId(_instanceId, _channelId),
4631 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4632 " doesnt exist");
4633 return -1;
4634 }
4635
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004636 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004637 fileSamples,
4638 mixingFrequency) == -1)
4639 {
4640 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4641 VoEId(_instanceId, _channelId),
4642 "Channel::MixOrReplaceAudioWithFile() file mixing "
4643 "failed");
4644 return -1;
4645 }
4646 if (fileSamples == 0)
4647 {
4648 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4649 VoEId(_instanceId, _channelId),
4650 "Channel::MixOrReplaceAudioWithFile() file is ended");
4651 return 0;
4652 }
4653 }
4654
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004655 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004656
4657 if (_mixFileWithMicrophone)
4658 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004659 // Currently file stream is always mono.
4660 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004661 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004662 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004663 fileBuffer.get(),
4664 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004665 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004666 }
4667 else
4668 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004669 // Replace ACM audio with file.
4670 // Currently file stream is always mono.
4671 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004672 _audioFrame.UpdateFrame(_channelId,
4673 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004674 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004675 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004676 mixingFrequency,
4677 AudioFrame::kNormalSpeech,
4678 AudioFrame::kVadUnknown,
4679 1);
4680
4681 }
4682 return 0;
4683}
4684
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004685int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004686Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004687 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004688{
4689 assert(mixingFrequency <= 32000);
4690
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004691 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004692 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004693
4694 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004695 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004696
4697 if (_outputFilePlayerPtr == NULL)
4698 {
4699 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4700 VoEId(_instanceId, _channelId),
4701 "Channel::MixAudioWithFile() file mixing failed");
4702 return -1;
4703 }
4704
4705 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004706 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004707 fileSamples,
4708 mixingFrequency) == -1)
4709 {
4710 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4711 VoEId(_instanceId, _channelId),
4712 "Channel::MixAudioWithFile() file mixing failed");
4713 return -1;
4714 }
4715 }
4716
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004717 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004718 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004719 // Currently file stream is always mono.
4720 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004721 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004722 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004723 fileBuffer.get(),
4724 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004725 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004726 }
4727 else
4728 {
4729 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004730 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004731 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004732 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004733 return -1;
4734 }
4735
4736 return 0;
4737}
4738
4739int
4740Channel::InsertInbandDtmfTone()
4741{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004742 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004743 if (_inbandDtmfQueue.PendingDtmf() &&
4744 !_inbandDtmfGenerator.IsAddingTone() &&
4745 _inbandDtmfGenerator.DelaySinceLastTone() >
4746 kMinTelephoneEventSeparationMs)
4747 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004748 int8_t eventCode(0);
4749 uint16_t lengthMs(0);
4750 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004751
4752 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4753 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4754 if (_playInbandDtmfEvent)
4755 {
4756 // Add tone to output mixer using a reduced length to minimize
4757 // risk of echo.
4758 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4759 attenuationDb);
4760 }
4761 }
4762
4763 if (_inbandDtmfGenerator.IsAddingTone())
4764 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004765 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004766 _inbandDtmfGenerator.GetSampleRate(frequency);
4767
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004768 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004769 {
4770 // Update sample rate of Dtmf tone since the mixing frequency
4771 // has changed.
4772 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004773 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004774 // Reset the tone to be added taking the new sample rate into
4775 // account.
4776 _inbandDtmfGenerator.ResetTone();
4777 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004778
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004779 int16_t toneBuffer[320];
4780 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004781 // Get 10ms tone segment and set time since last tone to zero
4782 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4783 {
4784 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4785 VoEId(_instanceId, _channelId),
4786 "Channel::EncodeAndSend() inserting Dtmf failed");
4787 return -1;
4788 }
4789
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004790 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004791 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004792 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004793 sample++)
4794 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004795 for (int channel = 0;
4796 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004797 channel++)
4798 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004799 const int index = sample * _audioFrame.num_channels_ + channel;
4800 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004801 }
4802 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004803
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004804 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004805 } else
4806 {
4807 // Add 10ms to "delay-since-last-tone" counter
4808 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4809 }
4810 return 0;
4811}
4812
niklase@google.com470e71d2011-07-07 08:21:25 +00004813void
4814Channel::ResetDeadOrAliveCounters()
4815{
4816 _countDeadDetections = 0;
4817 _countAliveDetections = 0;
4818}
4819
4820void
4821Channel::UpdateDeadOrAliveCounters(bool alive)
4822{
4823 if (alive)
4824 _countAliveDetections++;
4825 else
4826 _countDeadDetections++;
4827}
4828
4829int
4830Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
4831{
niklase@google.com470e71d2011-07-07 08:21:25 +00004832 return 0;
4833}
4834
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004835int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004836Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4837{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004838 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004839 if (_transportPtr == NULL)
4840 {
4841 return -1;
4842 }
4843 if (!RTCP)
4844 {
4845 return _transportPtr->SendPacket(_channelId, data, len);
4846 }
4847 else
4848 {
4849 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4850 }
4851}
4852
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004853// Called for incoming RTP packets after successful RTP header parsing.
4854void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4855 uint16_t sequence_number) {
4856 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4857 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4858 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004859
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004860 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004861 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004862
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004863 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004864 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004865 return;
4866 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004867
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004868 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004869 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004870
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004871 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4872 // Even though the actual sampling rate for G.722 audio is
4873 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4874 // 8,000 Hz because that value was erroneously assigned in
4875 // RFC 1890 and must remain unchanged for backward compatibility.
4876 rtp_receive_frequency = 8000;
4877 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4878 // We are resampling Opus internally to 32,000 Hz until all our
4879 // DSP routines can operate at 48,000 Hz, but the RTP clock
4880 // rate for the Opus payload format is standardized to 48,000 Hz,
4881 // because that is the maximum supported decoding sampling rate.
4882 rtp_receive_frequency = 48000;
4883 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004884
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004885 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4886 // every incoming packet.
4887 uint32_t timestamp_diff_ms = (rtp_timestamp -
4888 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004889
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004890 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4891 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004892
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004893 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004894
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004895 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4896 timestamp_diff_ms = 0;
4897 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004898
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004899 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004900
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004901 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4902 _recPacketDelayMs = packet_delay_ms;
4903 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004904
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004905 if (_average_jitter_buffer_delay_us == 0) {
4906 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4907 return;
4908 }
4909
4910 // Filter average delay value using exponential filter (alpha is
4911 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4912 // risk of rounding error) and compensate for it in GetDelayEstimate()
4913 // later.
4914 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4915 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004916}
4917
4918void
4919Channel::RegisterReceiveCodecsToRTPModule()
4920{
4921 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4922 "Channel::RegisterReceiveCodecsToRTPModule()");
4923
4924
4925 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004926 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004927
4928 for (int idx = 0; idx < nSupportedCodecs; idx++)
4929 {
4930 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004931 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004932 (rtp_receiver_->RegisterReceivePayload(
4933 codec.plname,
4934 codec.pltype,
4935 codec.plfreq,
4936 codec.channels,
4937 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004938 {
4939 WEBRTC_TRACE(
4940 kTraceWarning,
4941 kTraceVoice,
4942 VoEId(_instanceId, _channelId),
4943 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4944 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4945 codec.plname, codec.pltype, codec.plfreq,
4946 codec.channels, codec.rate);
4947 }
4948 else
4949 {
4950 WEBRTC_TRACE(
4951 kTraceInfo,
4952 kTraceVoice,
4953 VoEId(_instanceId, _channelId),
4954 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004955 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004956 "receiver",
4957 codec.plname, codec.pltype, codec.plfreq,
4958 codec.channels, codec.rate);
4959 }
4960 }
4961}
4962
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004963int Channel::SetSecondarySendCodec(const CodecInst& codec,
4964 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004965 // Sanity check for payload type.
4966 if (red_payload_type < 0 || red_payload_type > 127) {
4967 _engineStatisticsPtr->SetLastError(
4968 VE_PLTYPE_ERROR, kTraceError,
4969 "SetRedPayloadType() invalid RED payload type");
4970 return -1;
4971 }
4972
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004973 if (SetRedPayloadType(red_payload_type) < 0) {
4974 _engineStatisticsPtr->SetLastError(
4975 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4976 "SetSecondarySendCodec() Failed to register RED ACM");
4977 return -1;
4978 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004979 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004980 _engineStatisticsPtr->SetLastError(
4981 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4982 "SetSecondarySendCodec() Failed to register secondary send codec in "
4983 "ACM");
4984 return -1;
4985 }
4986
4987 return 0;
4988}
4989
4990void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004991 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004992}
4993
4994int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004995 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004996 _engineStatisticsPtr->SetLastError(
4997 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4998 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4999 return -1;
5000 }
5001 return 0;
5002}
5003
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005004// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005005int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005006 CodecInst codec;
5007 bool found_red = false;
5008
5009 // Get default RED settings from the ACM database
5010 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5011 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005012 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005013 if (!STR_CASE_CMP(codec.plname, "RED")) {
5014 found_red = true;
5015 break;
5016 }
5017 }
5018
5019 if (!found_red) {
5020 _engineStatisticsPtr->SetLastError(
5021 VE_CODEC_ERROR, kTraceError,
5022 "SetRedPayloadType() RED is not supported");
5023 return -1;
5024 }
5025
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005026 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005027 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005028 _engineStatisticsPtr->SetLastError(
5029 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5030 "SetRedPayloadType() RED registration in ACM module failed");
5031 return -1;
5032 }
5033
5034 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5035 _engineStatisticsPtr->SetLastError(
5036 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5037 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5038 return -1;
5039 }
5040 return 0;
5041}
5042
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00005043int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
5044 unsigned char id) {
5045 int error = 0;
5046 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
5047 if (enable) {
5048 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
5049 }
5050 return error;
5051}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005052} // namespace voe
5053} // namespace webrtc