blob: 700f5d668b201639719cd7c73f03b03766de86cf [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000016#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000017#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
wu@webrtc.org82c4b852014-05-20 22:55:01 +000018#include "webrtc/modules/rtp_rtcp/interface/remote_ntp_time_estimator.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000019#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
20#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
21#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000022#include "webrtc/modules/utility/interface/audio_frame_operations.h"
23#include "webrtc/modules/utility/interface/process_thread.h"
24#include "webrtc/modules/utility/interface/rtp_dump.h"
25#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
26#include "webrtc/system_wrappers/interface/logging.h"
27#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000028#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000029#include "webrtc/voice_engine/include/voe_base.h"
30#include "webrtc/voice_engine/include/voe_external_media.h"
31#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
32#include "webrtc/voice_engine/output_mixer.h"
33#include "webrtc/voice_engine/statistics.h"
34#include "webrtc/voice_engine/transmit_mixer.h"
35#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000036
37#if defined(_WIN32)
38#include <Qos.h>
39#endif
40
andrew@webrtc.org50419b02012-11-14 19:07:54 +000041namespace webrtc {
42namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000043
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000044// Extend the default RTCP statistics struct with max_jitter, defined as the
45// maximum jitter value seen in an RTCP report block.
46struct ChannelStatistics : public RtcpStatistics {
47 ChannelStatistics() : rtcp(), max_jitter(0) {}
48
49 RtcpStatistics rtcp;
50 uint32_t max_jitter;
51};
52
53// Statistics callback, called at each generation of a new RTCP report block.
54class StatisticsProxy : public RtcpStatisticsCallback {
55 public:
56 StatisticsProxy(uint32_t ssrc)
57 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
58 ssrc_(ssrc) {}
59 virtual ~StatisticsProxy() {}
60
61 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
62 uint32_t ssrc) OVERRIDE {
63 if (ssrc != ssrc_)
64 return;
65
66 CriticalSectionScoped cs(stats_lock_.get());
67 stats_.rtcp = statistics;
68 if (statistics.jitter > stats_.max_jitter) {
69 stats_.max_jitter = statistics.jitter;
70 }
71 }
72
73 void ResetStatistics() {
74 CriticalSectionScoped cs(stats_lock_.get());
75 stats_ = ChannelStatistics();
76 }
77
78 ChannelStatistics GetStats() {
79 CriticalSectionScoped cs(stats_lock_.get());
80 return stats_;
81 }
82
83 private:
84 // StatisticsUpdated calls are triggered from threads in the RTP module,
85 // while GetStats calls can be triggered from the public voice engine API,
86 // hence synchronization is needed.
87 scoped_ptr<CriticalSectionWrapper> stats_lock_;
88 const uint32_t ssrc_;
89 ChannelStatistics stats_;
90};
91
pbos@webrtc.org6141e132013-04-09 10:09:10 +000092int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000093Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000094 uint8_t payloadType,
95 uint32_t timeStamp,
96 const uint8_t* payloadData,
97 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000098 const RTPFragmentationHeader* fragmentation)
99{
100 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
101 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
102 " payloadSize=%u, fragmentation=0x%x)",
103 frameType, payloadType, timeStamp, payloadSize, fragmentation);
104
105 if (_includeAudioLevelIndication)
106 {
107 // Store current audio level in the RTP/RTCP module.
108 // The level will be used in combination with voice-activity state
109 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000110 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000111 }
112
113 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
114 // packetization.
115 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000116 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000117 payloadType,
118 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000119 // Leaving the time when this frame was
120 // received from the capture device as
121 // undefined for voice for now.
122 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000123 payloadData,
124 payloadSize,
125 fragmentation) == -1)
126 {
127 _engineStatisticsPtr->SetLastError(
128 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
129 "Channel::SendData() failed to send data to RTP/RTCP module");
130 return -1;
131 }
132
133 _lastLocalTimeStamp = timeStamp;
134 _lastPayloadType = payloadType;
135
136 return 0;
137}
138
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000139int32_t
140Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000141{
142 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
143 "Channel::InFrameType(frameType=%d)", frameType);
144
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000145 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000146 // 1 indicates speech
147 _sendFrameType = (frameType == 1) ? 1 : 0;
148 return 0;
149}
150
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000151int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000152Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000153{
154 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
155 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
156
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000157 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 if (_rxVadObserverPtr)
159 {
160 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
161 }
162
163 return 0;
164}
165
166int
167Channel::SendPacket(int channel, const void *data, int len)
168{
169 channel = VoEChannelId(channel);
170 assert(channel == _channelId);
171
172 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
173 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
174
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000175 CriticalSectionScoped cs(&_callbackCritSect);
176
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 if (_transportPtr == NULL)
178 {
179 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
180 "Channel::SendPacket() failed to send RTP packet due to"
181 " invalid transport object");
182 return -1;
183 }
184
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000185 uint8_t* bufferToSendPtr = (uint8_t*)data;
186 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187
188 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000189 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000190 {
191 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
192 VoEId(_instanceId,_channelId),
193 "Channel::SendPacket() RTP dump to output file failed");
194 }
195
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000196 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
197 bufferLength);
198 if (n < 0) {
199 std::string transport_name =
200 _externalTransport ? "external transport" : "WebRtc sockets";
201 WEBRTC_TRACE(kTraceError, kTraceVoice,
202 VoEId(_instanceId,_channelId),
203 "Channel::SendPacket() RTP transmission using %s failed",
204 transport_name.c_str());
205 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000207 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000208}
209
210int
211Channel::SendRTCPPacket(int channel, const void *data, int len)
212{
213 channel = VoEChannelId(channel);
214 assert(channel == _channelId);
215
216 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
217 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
218
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000219 CriticalSectionScoped cs(&_callbackCritSect);
220 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000221 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000222 WEBRTC_TRACE(kTraceError, kTraceVoice,
223 VoEId(_instanceId,_channelId),
224 "Channel::SendRTCPPacket() failed to send RTCP packet"
225 " due to invalid transport object");
226 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 }
228
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000229 uint8_t* bufferToSendPtr = (uint8_t*)data;
230 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000231
232 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000233 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 {
235 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
236 VoEId(_instanceId,_channelId),
237 "Channel::SendPacket() RTCP dump to output file failed");
238 }
239
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000240 int n = _transportPtr->SendRTCPPacket(channel,
241 bufferToSendPtr,
242 bufferLength);
243 if (n < 0) {
244 std::string transport_name =
245 _externalTransport ? "external transport" : "WebRtc sockets";
246 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
247 VoEId(_instanceId,_channelId),
248 "Channel::SendRTCPPacket() transmission using %s failed",
249 transport_name.c_str());
250 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000251 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000252 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253}
254
255void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000256Channel::OnPlayTelephoneEvent(int32_t id,
257 uint8_t event,
258 uint16_t lengthMs,
259 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000260{
261 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
262 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000263 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000264
265 if (!_playOutbandDtmfEvent || (event > 15))
266 {
267 // Ignore callback since feedback is disabled or event is not a
268 // Dtmf tone event.
269 return;
270 }
271
272 assert(_outputMixerPtr != NULL);
273
274 // Start playing out the Dtmf tone (if playout is enabled).
275 // Reduce length of tone with 80ms to the reduce risk of echo.
276 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
277}
278
279void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000280Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000281{
282 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
283 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000284 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000285
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000286 // Update ssrc so that NTP for AV sync can be updated.
287 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000288}
289
pbos@webrtc.org92135212013-05-14 08:31:39 +0000290void Channel::OnIncomingCSRCChanged(int32_t id,
291 uint32_t CSRC,
292 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000293{
294 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
295 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
296 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000297}
298
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000299void Channel::ResetStatistics(uint32_t ssrc) {
300 StreamStatistician* statistician =
301 rtp_receive_statistics_->GetStatistician(ssrc);
302 if (statistician) {
303 statistician->ResetStatistics();
304 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000305 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000306}
307
niklase@google.com470e71d2011-07-07 08:21:25 +0000308void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000309Channel::OnApplicationDataReceived(int32_t id,
310 uint8_t subType,
311 uint32_t name,
312 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000313 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000314{
315 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
316 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
317 " name=%u, length=%u)",
318 id, subType, name, length);
319
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000320 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000321 assert(channel == _channelId);
322
323 if (_rtcpObserver)
324 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000325 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000326
327 if (_rtcpObserverPtr)
328 {
329 _rtcpObserverPtr->OnApplicationDataReceived(channel,
330 subType,
331 name,
332 data,
333 length);
334 }
335 }
336}
337
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000338int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000339Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000340 int32_t id,
341 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000342 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000343 int frequency,
344 uint8_t channels,
345 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000346{
347 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
348 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
349 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
350 id, payloadType, payloadName, frequency, channels, rate);
351
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000352 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000353
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000354 CodecInst receiveCodec = {0};
355 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000356
357 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000358 receiveCodec.plfreq = frequency;
359 receiveCodec.channels = channels;
360 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000361 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000362
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000363 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000364 receiveCodec.pacsize = dummyCodec.pacsize;
365
366 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000367 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000368 {
369 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000370 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000371 "Channel::OnInitializeDecoder() invalid codec ("
372 "pt=%d, name=%s) received - 1", payloadType, payloadName);
373 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
374 return -1;
375 }
376
377 return 0;
378}
379
380void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000381Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000382{
383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
384 "Channel::OnPacketTimeout(id=%d)", id);
385
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000386 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000387 if (_voiceEngineObserverPtr)
388 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000389 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000390 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000391 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000392 assert(channel == _channelId);
393 // Ensure that next OnReceivedPacket() callback will trigger
394 // a VE_PACKET_RECEIPT_RESTARTED callback.
395 _rtpPacketTimedOut = true;
396 // Deliver callback to the observer
397 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
398 VoEId(_instanceId,_channelId),
399 "Channel::OnPacketTimeout() => "
400 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
401 _voiceEngineObserverPtr->CallbackOnError(channel,
402 VE_RECEIVE_PACKET_TIMEOUT);
403 }
404 }
405}
406
407void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000408Channel::OnReceivedPacket(int32_t id,
409 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000410{
411 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
412 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
413 id, packetType);
414
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000415 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000416
417 // Notify only for the case when we have restarted an RTP session.
418 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
419 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000420 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000421 if (_voiceEngineObserverPtr)
422 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000423 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 assert(channel == _channelId);
425 // Reset timeout mechanism
426 _rtpPacketTimedOut = false;
427 // Deliver callback to the observer
428 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
429 VoEId(_instanceId,_channelId),
430 "Channel::OnPacketTimeout() =>"
431 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
432 _voiceEngineObserverPtr->CallbackOnError(
433 channel,
434 VE_PACKET_RECEIPT_RESTARTED);
435 }
436 }
437}
438
439void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000440Channel::OnPeriodicDeadOrAlive(int32_t id,
441 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000442{
443 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
444 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
445
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000446 {
447 CriticalSectionScoped cs(&_callbackCritSect);
448 if (!_connectionObserver)
449 return;
450 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000451
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000452 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000453 assert(channel == _channelId);
454
455 // Use Alive as default to limit risk of false Dead detections
456 bool isAlive(true);
457
458 // Always mark the connection as Dead when the module reports kRtpDead
459 if (kRtpDead == alive)
460 {
461 isAlive = false;
462 }
463
464 // It is possible that the connection is alive even if no RTP packet has
465 // been received for a long time since the other side might use VAD/DTX
466 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000467 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 {
469 // Detect Alive for all NetEQ states except for the case when we are
470 // in PLC_CNG state.
471 // PLC_CNG <=> background noise only due to long expand or error.
472 // Note that, the case where the other side stops sending during CNG
473 // state will be detected as Alive. Dead is is not set until after
474 // missing RTCP packets for at least twelve seconds (handled
475 // internally by the RTP/RTCP module).
476 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
477 }
478
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 // Send callback to the registered observer
480 if (_connectionObserver)
481 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000482 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000483 if (_connectionObserverPtr)
484 {
485 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
486 }
487 }
488}
489
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000490int32_t
491Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000492 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 const WebRtcRTPHeader* rtpHeader)
494{
495 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
496 "Channel::OnReceivedPayloadData(payloadSize=%d,"
497 " payloadType=%u, audioChannel=%u)",
498 payloadSize,
499 rtpHeader->header.payloadType,
500 rtpHeader->type.Audio.channel);
501
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000502 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 {
504 // Avoid inserting into NetEQ when we are not playing. Count the
505 // packet as discarded.
506 WEBRTC_TRACE(kTraceStream, kTraceVoice,
507 VoEId(_instanceId, _channelId),
508 "received packet is discarded since playing is not"
509 " activated");
510 _numberOfDiscardedPackets++;
511 return 0;
512 }
513
514 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000515 if (audio_coding_->IncomingPacket(payloadData,
516 payloadSize,
517 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 {
519 _engineStatisticsPtr->SetLastError(
520 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
521 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
522 return -1;
523 }
524
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000525 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000526 UpdatePacketDelay(rtpHeader->header.timestamp,
527 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000528
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000529 uint16_t round_trip_time = 0;
530 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
531 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000532
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000533 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000534 round_trip_time);
535 if (!nack_list.empty()) {
536 // Can't use nack_list.data() since it's not supported by all
537 // compilers.
538 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000539 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 return 0;
541}
542
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000543bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
544 int rtp_packet_length) {
545 RTPHeader header;
546 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
547 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
548 "IncomingPacket invalid RTP header");
549 return false;
550 }
551 header.payload_type_frequency =
552 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
553 if (header.payload_type_frequency < 0)
554 return false;
555 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
556}
557
pbos@webrtc.org92135212013-05-14 08:31:39 +0000558int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000559{
560 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
561 "Channel::GetAudioFrame(id=%d)", id);
562
563 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000564 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
565 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 {
567 WEBRTC_TRACE(kTraceError, kTraceVoice,
568 VoEId(_instanceId,_channelId),
569 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000570 // In all likelihood, the audio in this frame is garbage. We return an
571 // error so that the audio mixer module doesn't add it to the mix. As
572 // a result, it won't be played out and the actions skipped here are
573 // irrelevant.
574 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000575 }
576
577 if (_RxVadDetection)
578 {
579 UpdateRxVadDetection(audioFrame);
580 }
581
582 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000583 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000585 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000587 ChannelState::State state = channel_state_.Get();
588
589 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000590 int err = rx_audioproc_->ProcessStream(&audioFrame);
591 if (err) {
592 LOG(LS_ERROR) << "ProcessStream() error: " << err;
593 assert(false);
594 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000595 }
596
wu@webrtc.org63420662013-10-17 18:28:55 +0000597 float output_gain = 1.0f;
598 float left_pan = 1.0f;
599 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000600 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000601 CriticalSectionScoped cs(&volume_settings_critsect_);
602 output_gain = _outputGain;
603 left_pan = _panLeft;
604 right_pan= _panRight;
605 }
606
607 // Output volume scaling
608 if (output_gain < 0.99f || output_gain > 1.01f)
609 {
610 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000611 }
612
613 // Scale left and/or right channel(s) if stereo and master balance is
614 // active
615
wu@webrtc.org63420662013-10-17 18:28:55 +0000616 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000618 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000619 {
620 // Emulate stereo mode since panning is active.
621 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000622 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000623 }
624 // For true stereo mode (when we are receiving a stereo signal), no
625 // action is needed.
626
627 // Do the panning operation (the audio frame contains stereo at this
628 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000629 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630 }
631
632 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000633 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000635 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 }
637
niklase@google.com470e71d2011-07-07 08:21:25 +0000638 // External media
639 if (_outputExternalMedia)
640 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000641 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000642 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 if (_outputExternalMediaCallbackPtr)
644 {
645 _outputExternalMediaCallbackPtr->Process(
646 _channelId,
647 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000648 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000649 audioFrame.samples_per_channel_,
650 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 isStereo);
652 }
653 }
654
655 // Record playout if enabled
656 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000657 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
659 if (_outputFileRecording && _outputFileRecorderPtr)
660 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000661 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000662 }
663 }
664
665 // Measure audio level (0-9)
666 _outputAudioLevel.ComputeLevel(audioFrame);
667
wu@webrtc.org82c4b852014-05-20 22:55:01 +0000668 audioFrame.ntp_time_ms_ = ntp_estimator_->Estimate(audioFrame.timestamp_);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000669
670 if (!first_frame_arrived_) {
671 first_frame_arrived_ = true;
672 capture_start_rtp_time_stamp_ = audioFrame.timestamp_;
673 } else {
674 // |ntp_time_ms_| won't be valid until at least 2 RTCP SRs are received.
675 if (audioFrame.ntp_time_ms_ > 0) {
676 // Compute |capture_start_ntp_time_ms_| so that
677 // |capture_start_ntp_time_ms_| + |elapsed_time_ms| == |ntp_time_ms_|
678 CriticalSectionScoped lock(ts_stats_lock_.get());
679 uint32_t elapsed_time_ms =
680 (audioFrame.timestamp_ - capture_start_rtp_time_stamp_) /
681 (audioFrame.sample_rate_hz_ * 1000);
682 capture_start_ntp_time_ms_ = audioFrame.ntp_time_ms_ - elapsed_time_ms;
683 }
684 }
685
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 return 0;
687}
688
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000689int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000690Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000691{
692 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
693 "Channel::NeededFrequency(id=%d)", id);
694
695 int highestNeeded = 0;
696
697 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000698 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000699
700 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000701 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000702 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000703 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000704 }
705 else
706 {
707 highestNeeded = receiveFrequency;
708 }
709
710 // Special case, if we're playing a file on the playout side
711 // we take that frequency into consideration as well
712 // This is not needed on sending side, since the codec will
713 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000714 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000716 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000717 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 {
719 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
720 {
721 highestNeeded=_outputFilePlayerPtr->Frequency();
722 }
723 }
724 }
725
726 return(highestNeeded);
727}
728
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000729int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000730Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000731 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000732 uint32_t instanceId,
733 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000734{
735 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
736 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
737 channelId, instanceId);
738
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000739 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000740 if (channel == NULL)
741 {
742 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
743 VoEId(instanceId,channelId),
744 "Channel::CreateChannel() unable to allocate memory for"
745 " channel");
746 return -1;
747 }
748 return 0;
749}
750
751void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000752Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000753{
754 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
755 "Channel::PlayNotification(id=%d, durationMs=%d)",
756 id, durationMs);
757
758 // Not implement yet
759}
760
761void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000762Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000763{
764 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
765 "Channel::RecordNotification(id=%d, durationMs=%d)",
766 id, durationMs);
767
768 // Not implement yet
769}
770
771void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000772Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000773{
774 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
775 "Channel::PlayFileEnded(id=%d)", id);
776
777 if (id == _inputFilePlayerId)
778 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000779 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000780 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
781 VoEId(_instanceId,_channelId),
782 "Channel::PlayFileEnded() => input file player module is"
783 " shutdown");
784 }
785 else if (id == _outputFilePlayerId)
786 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000787 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000788 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
789 VoEId(_instanceId,_channelId),
790 "Channel::PlayFileEnded() => output file player module is"
791 " shutdown");
792 }
793}
794
795void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000796Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000797{
798 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
799 "Channel::RecordFileEnded(id=%d)", id);
800
801 assert(id == _outputFileRecorderId);
802
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000803 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000804
805 _outputFileRecording = false;
806 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
807 VoEId(_instanceId,_channelId),
808 "Channel::RecordFileEnded() => output file recorder module is"
809 " shutdown");
810}
811
pbos@webrtc.org92135212013-05-14 08:31:39 +0000812Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000813 uint32_t instanceId,
814 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
816 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000817 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000818 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000819 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000820 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000821 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000822 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000823 rtp_receive_statistics_(ReceiveStatistics::Create(
824 Clock::GetRealTimeClock())),
825 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
826 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
827 this, this, rtp_payload_registry_.get())),
828 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000829 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000830 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000831 _rtpDumpIn(*RtpDump::CreateRtpDump()),
832 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000833 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000834 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000835 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000836 _inputFilePlayerPtr(NULL),
837 _outputFilePlayerPtr(NULL),
838 _outputFileRecorderPtr(NULL),
839 // Avoid conflict with other channels by adding 1024 - 1026,
840 // won't use as much as 1024 channels.
841 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
842 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
843 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000845 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
846 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000847 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000848 _inputExternalMediaCallbackPtr(NULL),
849 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000850 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
851 _sendTelephoneEventPayloadType(106),
wu@webrtc.org82c4b852014-05-20 22:55:01 +0000852 ntp_estimator_(new RemoteNtpTimeEstimator(Clock::GetRealTimeClock())),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000853 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000854 playout_timestamp_rtp_(0),
855 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000856 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000857 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000858 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000859 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
860 first_frame_arrived_(false),
861 capture_start_rtp_time_stamp_(0),
862 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000863 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000864 _outputMixerPtr(NULL),
865 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000866 _moduleProcessThreadPtr(NULL),
867 _audioDeviceModulePtr(NULL),
868 _voiceEngineObserverPtr(NULL),
869 _callbackCritSectPtr(NULL),
870 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000871 _rxVadObserverPtr(NULL),
872 _oldVadDecision(-1),
873 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000875 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000876 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000878 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 _mute(false),
880 _panLeft(1.0f),
881 _panRight(1.0f),
882 _outputGain(1.0f),
883 _playOutbandDtmfEvent(false),
884 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000885 _lastLocalTimeStamp(0),
886 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000887 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000888 _rtpPacketTimedOut(false),
889 _rtpPacketTimeOutIsEnabled(false),
890 _rtpTimeOutSeconds(0),
891 _connectionObserver(false),
892 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000893 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000894 vie_network_(NULL),
895 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000896 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000897 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000898 _previousTimestamp(0),
899 _recPacketDelayMs(20),
900 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000901 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000902 _rxNsIsEnabled(false),
903 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000904{
905 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
906 "Channel::Channel() - ctor");
907 _inbandDtmfQueue.ResetDtmf();
908 _inbandDtmfGenerator.Init();
909 _outputAudioLevel.Clear();
910
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000911 RtpRtcp::Configuration configuration;
912 configuration.id = VoEModuleId(instanceId, channelId);
913 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000914 configuration.outgoing_transport = this;
915 configuration.rtcp_feedback = this;
916 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000917 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000918
919 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000920
921 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
922 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
923 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000924
925 Config audioproc_config;
926 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
927 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000928}
929
930Channel::~Channel()
931{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000932 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
934 "Channel::~Channel() - dtor");
935
936 if (_outputExternalMedia)
937 {
938 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
939 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000940 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000941 {
942 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
943 }
944 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000945 StopPlayout();
946
947 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000948 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 if (_inputFilePlayerPtr)
950 {
951 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
952 _inputFilePlayerPtr->StopPlayingFile();
953 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
954 _inputFilePlayerPtr = NULL;
955 }
956 if (_outputFilePlayerPtr)
957 {
958 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
959 _outputFilePlayerPtr->StopPlayingFile();
960 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
961 _outputFilePlayerPtr = NULL;
962 }
963 if (_outputFileRecorderPtr)
964 {
965 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
966 _outputFileRecorderPtr->StopRecording();
967 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
968 _outputFileRecorderPtr = NULL;
969 }
970 }
971
972 // The order to safely shutdown modules in a channel is:
973 // 1. De-register callbacks in modules
974 // 2. De-register modules in process thread
975 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000976 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000977 {
978 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
979 VoEId(_instanceId,_channelId),
980 "~Channel() failed to de-register transport callback"
981 " (Audio coding module)");
982 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000983 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000984 {
985 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
986 VoEId(_instanceId,_channelId),
987 "~Channel() failed to de-register VAD callback"
988 " (Audio coding module)");
989 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000991 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000992 {
993 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
994 VoEId(_instanceId,_channelId),
995 "~Channel() failed to deregister RTP/RTCP module");
996 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000997 // End of modules shutdown
998
999 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001000 if (vie_network_) {
1001 vie_network_->Release();
1002 vie_network_ = NULL;
1003 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001004 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1005 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001007 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001008 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001009}
1010
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001011int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001012Channel::Init()
1013{
1014 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1015 "Channel::Init()");
1016
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001017 channel_state_.Reset();
1018
niklase@google.com470e71d2011-07-07 08:21:25 +00001019 // --- Initial sanity
1020
1021 if ((_engineStatisticsPtr == NULL) ||
1022 (_moduleProcessThreadPtr == NULL))
1023 {
1024 WEBRTC_TRACE(kTraceError, kTraceVoice,
1025 VoEId(_instanceId,_channelId),
1026 "Channel::Init() must call SetEngineInformation() first");
1027 return -1;
1028 }
1029
1030 // --- Add modules to process thread (for periodic schedulation)
1031
1032 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001033 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001035 if (processThreadFail)
1036 {
1037 _engineStatisticsPtr->SetLastError(
1038 VE_CANNOT_INIT_CHANNEL, kTraceError,
1039 "Channel::Init() modules not registered");
1040 return -1;
1041 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001042 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001043
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001044 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001045#ifdef WEBRTC_CODEC_AVT
1046 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001047 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001048#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001049 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001050 {
1051 _engineStatisticsPtr->SetLastError(
1052 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1053 "Channel::Init() unable to initialize the ACM - 1");
1054 return -1;
1055 }
1056
1057 // --- RTP/RTCP module initialization
1058
1059 // Ensure that RTCP is enabled by default for the created channel.
1060 // Note that, the module will keep generating RTCP until it is explicitly
1061 // disabled by the user.
1062 // After StopListen (when no sockets exists), RTCP packets will no longer
1063 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001064 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1065 // RTCP is enabled by default.
1066 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001067 {
1068 _engineStatisticsPtr->SetLastError(
1069 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1070 "Channel::Init() RTP/RTCP module not initialized");
1071 return -1;
1072 }
1073
1074 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001075 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001076 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1077 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001078
1079 if (fail)
1080 {
1081 _engineStatisticsPtr->SetLastError(
1082 VE_CANNOT_INIT_CHANNEL, kTraceError,
1083 "Channel::Init() callbacks not registered");
1084 return -1;
1085 }
1086
1087 // --- Register all supported codecs to the receiving side of the
1088 // RTP/RTCP module
1089
1090 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001091 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001092
1093 for (int idx = 0; idx < nSupportedCodecs; idx++)
1094 {
1095 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001096 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001097 (rtp_receiver_->RegisterReceivePayload(
1098 codec.plname,
1099 codec.pltype,
1100 codec.plfreq,
1101 codec.channels,
1102 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001103 {
1104 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1105 VoEId(_instanceId,_channelId),
1106 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1107 "to RTP/RTCP receiver",
1108 codec.plname, codec.pltype, codec.plfreq,
1109 codec.channels, codec.rate);
1110 }
1111 else
1112 {
1113 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1114 VoEId(_instanceId,_channelId),
1115 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1116 "the RTP/RTCP receiver",
1117 codec.plname, codec.pltype, codec.plfreq,
1118 codec.channels, codec.rate);
1119 }
1120
1121 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001122 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001123 {
1124 SetSendCodec(codec);
1125 }
1126
1127 // Register default PT for outband 'telephone-event'
1128 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1129 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001130 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001131 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 {
1133 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1134 VoEId(_instanceId,_channelId),
1135 "Channel::Init() failed to register outband "
1136 "'telephone-event' (%d/%d) correctly",
1137 codec.pltype, codec.plfreq);
1138 }
1139 }
1140
1141 if (!STR_CASE_CMP(codec.plname, "CN"))
1142 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001143 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1144 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001145 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001146 {
1147 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1148 VoEId(_instanceId,_channelId),
1149 "Channel::Init() failed to register CN (%d/%d) "
1150 "correctly - 1",
1151 codec.pltype, codec.plfreq);
1152 }
1153 }
1154#ifdef WEBRTC_CODEC_RED
1155 // Register RED to the receiving side of the ACM.
1156 // We will not receive an OnInitializeDecoder() callback for RED.
1157 if (!STR_CASE_CMP(codec.plname, "RED"))
1158 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001159 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001160 {
1161 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1162 VoEId(_instanceId,_channelId),
1163 "Channel::Init() failed to register RED (%d/%d) "
1164 "correctly",
1165 codec.pltype, codec.plfreq);
1166 }
1167 }
1168#endif
1169 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001170
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001171 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1172 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1173 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001175 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1176 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1177 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001178 }
1179
1180 return 0;
1181}
1182
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001183int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001184Channel::SetEngineInformation(Statistics& engineStatistics,
1185 OutputMixer& outputMixer,
1186 voe::TransmitMixer& transmitMixer,
1187 ProcessThread& moduleProcessThread,
1188 AudioDeviceModule& audioDeviceModule,
1189 VoiceEngineObserver* voiceEngineObserver,
1190 CriticalSectionWrapper* callbackCritSect)
1191{
1192 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1193 "Channel::SetEngineInformation()");
1194 _engineStatisticsPtr = &engineStatistics;
1195 _outputMixerPtr = &outputMixer;
1196 _transmitMixerPtr = &transmitMixer,
1197 _moduleProcessThreadPtr = &moduleProcessThread;
1198 _audioDeviceModulePtr = &audioDeviceModule;
1199 _voiceEngineObserverPtr = voiceEngineObserver;
1200 _callbackCritSectPtr = callbackCritSect;
1201 return 0;
1202}
1203
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001204int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001205Channel::UpdateLocalTimeStamp()
1206{
1207
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001208 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 return 0;
1210}
1211
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001212int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001213Channel::StartPlayout()
1214{
1215 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1216 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001217 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001218 {
1219 return 0;
1220 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001221
1222 if (!_externalMixing) {
1223 // Add participant as candidates for mixing.
1224 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1225 {
1226 _engineStatisticsPtr->SetLastError(
1227 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1228 "StartPlayout() failed to add participant to mixer");
1229 return -1;
1230 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001231 }
1232
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001233 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001234 if (RegisterFilePlayingToMixer() != 0)
1235 return -1;
1236
niklase@google.com470e71d2011-07-07 08:21:25 +00001237 return 0;
1238}
1239
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001240int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001241Channel::StopPlayout()
1242{
1243 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1244 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001245 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 {
1247 return 0;
1248 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001249
1250 if (!_externalMixing) {
1251 // Remove participant as candidates for mixing
1252 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1253 {
1254 _engineStatisticsPtr->SetLastError(
1255 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1256 "StopPlayout() failed to remove participant from mixer");
1257 return -1;
1258 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001259 }
1260
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001261 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001262 _outputAudioLevel.Clear();
1263
1264 return 0;
1265}
1266
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001267int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001268Channel::StartSend()
1269{
1270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1271 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001272 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001273 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001274 if (send_sequence_number_)
1275 SetInitSequenceNumber(send_sequence_number_);
1276
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001277 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001279 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001281 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001282
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001283 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 {
1285 _engineStatisticsPtr->SetLastError(
1286 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1287 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001288 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001289 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001290 return -1;
1291 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001292
niklase@google.com470e71d2011-07-07 08:21:25 +00001293 return 0;
1294}
1295
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001296int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001297Channel::StopSend()
1298{
1299 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1300 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001301 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001303 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001304 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001305 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001306
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001307 // Store the sequence number to be able to pick up the same sequence for
1308 // the next StartSend(). This is needed for restarting device, otherwise
1309 // it might cause libSRTP to complain about packets being replayed.
1310 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1311 // CL is landed. See issue
1312 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1313 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1314
niklase@google.com470e71d2011-07-07 08:21:25 +00001315 // Reset sending SSRC and sequence number and triggers direct transmission
1316 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001317 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1318 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001319 {
1320 _engineStatisticsPtr->SetLastError(
1321 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1322 "StartSend() RTP/RTCP failed to stop sending");
1323 }
1324
niklase@google.com470e71d2011-07-07 08:21:25 +00001325 return 0;
1326}
1327
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001328int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001329Channel::StartReceiving()
1330{
1331 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1332 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001333 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001334 {
1335 return 0;
1336 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001337 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001338 _numberOfDiscardedPackets = 0;
1339 return 0;
1340}
1341
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001342int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001343Channel::StopReceiving()
1344{
1345 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1346 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001347 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001348 {
1349 return 0;
1350 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001351
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001352 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001353 return 0;
1354}
1355
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001356int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001357Channel::SetNetEQPlayoutMode(NetEqModes mode)
1358{
1359 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1360 "Channel::SetNetEQPlayoutMode()");
1361 AudioPlayoutMode playoutMode(voice);
1362 switch (mode)
1363 {
1364 case kNetEqDefault:
1365 playoutMode = voice;
1366 break;
1367 case kNetEqStreaming:
1368 playoutMode = streaming;
1369 break;
1370 case kNetEqFax:
1371 playoutMode = fax;
1372 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001373 case kNetEqOff:
1374 playoutMode = off;
1375 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001376 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001377 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001378 {
1379 _engineStatisticsPtr->SetLastError(
1380 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1381 "SetNetEQPlayoutMode() failed to set playout mode");
1382 return -1;
1383 }
1384 return 0;
1385}
1386
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001387int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001388Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1389{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001390 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001391 switch (playoutMode)
1392 {
1393 case voice:
1394 mode = kNetEqDefault;
1395 break;
1396 case streaming:
1397 mode = kNetEqStreaming;
1398 break;
1399 case fax:
1400 mode = kNetEqFax;
1401 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001402 case off:
1403 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001404 }
1405 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1406 VoEId(_instanceId,_channelId),
1407 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1408 return 0;
1409}
1410
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001411int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001412Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1413{
1414 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1415 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001416 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001417
1418 if (_voiceEngineObserverPtr)
1419 {
1420 _engineStatisticsPtr->SetLastError(
1421 VE_INVALID_OPERATION, kTraceError,
1422 "RegisterVoiceEngineObserver() observer already enabled");
1423 return -1;
1424 }
1425 _voiceEngineObserverPtr = &observer;
1426 return 0;
1427}
1428
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001429int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001430Channel::DeRegisterVoiceEngineObserver()
1431{
1432 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1433 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001434 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001435
1436 if (!_voiceEngineObserverPtr)
1437 {
1438 _engineStatisticsPtr->SetLastError(
1439 VE_INVALID_OPERATION, kTraceWarning,
1440 "DeRegisterVoiceEngineObserver() observer already disabled");
1441 return 0;
1442 }
1443 _voiceEngineObserverPtr = NULL;
1444 return 0;
1445}
1446
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001447int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001448Channel::GetSendCodec(CodecInst& codec)
1449{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001450 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001451}
1452
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001453int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001454Channel::GetRecCodec(CodecInst& codec)
1455{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001456 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001457}
1458
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001459int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001460Channel::SetSendCodec(const CodecInst& codec)
1461{
1462 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1463 "Channel::SetSendCodec()");
1464
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001465 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001466 {
1467 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1468 "SetSendCodec() failed to register codec to ACM");
1469 return -1;
1470 }
1471
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001472 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001473 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001474 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1475 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001476 {
1477 WEBRTC_TRACE(
1478 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1479 "SetSendCodec() failed to register codec to"
1480 " RTP/RTCP module");
1481 return -1;
1482 }
1483 }
1484
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001485 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001486 {
1487 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "SetSendCodec() failed to set audio packet size");
1489 return -1;
1490 }
1491
1492 return 0;
1493}
1494
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001495int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001496Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1497{
1498 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1499 "Channel::SetVADStatus(mode=%d)", mode);
1500 // To disable VAD, DTX must be disabled too
1501 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001502 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001503 {
1504 _engineStatisticsPtr->SetLastError(
1505 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1506 "SetVADStatus() failed to set VAD");
1507 return -1;
1508 }
1509 return 0;
1510}
1511
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001512int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001513Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1514{
1515 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1516 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001517 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001518 {
1519 _engineStatisticsPtr->SetLastError(
1520 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1521 "GetVADStatus() failed to get VAD status");
1522 return -1;
1523 }
1524 disabledDTX = !disabledDTX;
1525 return 0;
1526}
1527
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001528int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001529Channel::SetRecPayloadType(const CodecInst& codec)
1530{
1531 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1532 "Channel::SetRecPayloadType()");
1533
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001534 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001535 {
1536 _engineStatisticsPtr->SetLastError(
1537 VE_ALREADY_PLAYING, kTraceError,
1538 "SetRecPayloadType() unable to set PT while playing");
1539 return -1;
1540 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001541 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001542 {
1543 _engineStatisticsPtr->SetLastError(
1544 VE_ALREADY_LISTENING, kTraceError,
1545 "SetRecPayloadType() unable to set PT while listening");
1546 return -1;
1547 }
1548
1549 if (codec.pltype == -1)
1550 {
1551 // De-register the selected codec (RTP/RTCP module and ACM)
1552
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001553 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001554 CodecInst rxCodec = codec;
1555
1556 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001557 rtp_payload_registry_->ReceivePayloadType(
1558 rxCodec.plname,
1559 rxCodec.plfreq,
1560 rxCodec.channels,
1561 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1562 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001563 rxCodec.pltype = pltype;
1564
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001565 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 {
1567 _engineStatisticsPtr->SetLastError(
1568 VE_RTP_RTCP_MODULE_ERROR,
1569 kTraceError,
1570 "SetRecPayloadType() RTP/RTCP-module deregistration "
1571 "failed");
1572 return -1;
1573 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001574 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001575 {
1576 _engineStatisticsPtr->SetLastError(
1577 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1578 "SetRecPayloadType() ACM deregistration failed - 1");
1579 return -1;
1580 }
1581 return 0;
1582 }
1583
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001584 if (rtp_receiver_->RegisterReceivePayload(
1585 codec.plname,
1586 codec.pltype,
1587 codec.plfreq,
1588 codec.channels,
1589 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001590 {
1591 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001592 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1593 if (rtp_receiver_->RegisterReceivePayload(
1594 codec.plname,
1595 codec.pltype,
1596 codec.plfreq,
1597 codec.channels,
1598 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001599 {
1600 _engineStatisticsPtr->SetLastError(
1601 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1602 "SetRecPayloadType() RTP/RTCP-module registration failed");
1603 return -1;
1604 }
1605 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001606 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001607 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001608 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1609 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001610 {
1611 _engineStatisticsPtr->SetLastError(
1612 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1613 "SetRecPayloadType() ACM registration failed - 1");
1614 return -1;
1615 }
1616 }
1617 return 0;
1618}
1619
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001620int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001621Channel::GetRecPayloadType(CodecInst& codec)
1622{
1623 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1624 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001625 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001626 if (rtp_payload_registry_->ReceivePayloadType(
1627 codec.plname,
1628 codec.plfreq,
1629 codec.channels,
1630 (codec.rate < 0) ? 0 : codec.rate,
1631 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001632 {
1633 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001634 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001635 "GetRecPayloadType() failed to retrieve RX payload type");
1636 return -1;
1637 }
1638 codec.pltype = payloadType;
1639 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1640 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1641 return 0;
1642}
1643
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001644int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001645Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1646{
1647 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1648 "Channel::SetSendCNPayloadType()");
1649
1650 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001651 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001652 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001653 if (frequency == kFreq32000Hz)
1654 samplingFreqHz = 32000;
1655 else if (frequency == kFreq16000Hz)
1656 samplingFreqHz = 16000;
1657
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001658 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001659 {
1660 _engineStatisticsPtr->SetLastError(
1661 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1662 "SetSendCNPayloadType() failed to retrieve default CN codec "
1663 "settings");
1664 return -1;
1665 }
1666
1667 // Modify the payload type (must be set to dynamic range)
1668 codec.pltype = type;
1669
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001670 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001671 {
1672 _engineStatisticsPtr->SetLastError(
1673 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1674 "SetSendCNPayloadType() failed to register CN to ACM");
1675 return -1;
1676 }
1677
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001678 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001679 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001680 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1681 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001682 {
1683 _engineStatisticsPtr->SetLastError(
1684 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1685 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1686 "module");
1687 return -1;
1688 }
1689 }
1690 return 0;
1691}
1692
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001693int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001694{
1695 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1696 "Channel::RegisterExternalTransport()");
1697
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001698 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001699
niklase@google.com470e71d2011-07-07 08:21:25 +00001700 if (_externalTransport)
1701 {
1702 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1703 kTraceError,
1704 "RegisterExternalTransport() external transport already enabled");
1705 return -1;
1706 }
1707 _externalTransport = true;
1708 _transportPtr = &transport;
1709 return 0;
1710}
1711
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001712int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001713Channel::DeRegisterExternalTransport()
1714{
1715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1716 "Channel::DeRegisterExternalTransport()");
1717
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001718 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001719
niklase@google.com470e71d2011-07-07 08:21:25 +00001720 if (!_transportPtr)
1721 {
1722 _engineStatisticsPtr->SetLastError(
1723 VE_INVALID_OPERATION, kTraceWarning,
1724 "DeRegisterExternalTransport() external transport already "
1725 "disabled");
1726 return 0;
1727 }
1728 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001729 _transportPtr = NULL;
1730 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1731 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001732 return 0;
1733}
1734
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001735int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1736 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001737 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1738 "Channel::ReceivedRTPPacket()");
1739
1740 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001741 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001742
1743 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001744 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1745 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001746 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1747 VoEId(_instanceId,_channelId),
1748 "Channel::SendPacket() RTP dump to input file failed");
1749 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001750 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001751 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001752 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1753 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1754 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001755 return -1;
1756 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001757 header.payload_type_frequency =
1758 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001759 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001760 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001761 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001762 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001763 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001764 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001765
1766 // Forward any packets to ViE bandwidth estimator, if enabled.
1767 {
1768 CriticalSectionScoped cs(&_callbackCritSect);
1769 if (vie_network_) {
1770 int64_t arrival_time_ms;
1771 if (packet_time.timestamp != -1) {
1772 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1773 } else {
1774 arrival_time_ms = TickTime::MillisecondTimestamp();
1775 }
1776 int payload_length = length - header.headerLength;
1777 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1778 payload_length, header);
1779 }
1780 }
1781
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001782 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001783}
1784
1785bool Channel::ReceivePacket(const uint8_t* packet,
1786 int packet_length,
1787 const RTPHeader& header,
1788 bool in_order) {
1789 if (rtp_payload_registry_->IsEncapsulated(header)) {
1790 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001791 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001792 const uint8_t* payload = packet + header.headerLength;
1793 int payload_length = packet_length - header.headerLength;
1794 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001795 PayloadUnion payload_specific;
1796 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001797 &payload_specific)) {
1798 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001799 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001800 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1801 payload_specific, in_order);
1802}
1803
1804bool Channel::HandleEncapsulation(const uint8_t* packet,
1805 int packet_length,
1806 const RTPHeader& header) {
1807 if (!rtp_payload_registry_->IsRtx(header))
1808 return false;
1809
1810 // Remove the RTX header and parse the original RTP header.
1811 if (packet_length < header.headerLength)
1812 return false;
1813 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1814 return false;
1815 if (restored_packet_in_use_) {
1816 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1817 "Multiple RTX headers detected, dropping packet");
1818 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001819 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001820 uint8_t* restored_packet_ptr = restored_packet_;
1821 if (!rtp_payload_registry_->RestoreOriginalPacket(
1822 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1823 header)) {
1824 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1825 "Incoming RTX packet: invalid RTP header");
1826 return false;
1827 }
1828 restored_packet_in_use_ = true;
1829 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1830 restored_packet_in_use_ = false;
1831 return ret;
1832}
1833
1834bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1835 StreamStatistician* statistician =
1836 rtp_receive_statistics_->GetStatistician(header.ssrc);
1837 if (!statistician)
1838 return false;
1839 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001840}
1841
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001842bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1843 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001844 // Retransmissions are handled separately if RTX is enabled.
1845 if (rtp_payload_registry_->RtxEnabled())
1846 return false;
1847 StreamStatistician* statistician =
1848 rtp_receive_statistics_->GetStatistician(header.ssrc);
1849 if (!statistician)
1850 return false;
1851 // Check if this is a retransmission.
1852 uint16_t min_rtt = 0;
1853 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001854 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001855 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001856}
1857
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001858int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001859 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1860 "Channel::ReceivedRTCPPacket()");
1861 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001862 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001863
1864 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001865 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1866 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001867 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1868 VoEId(_instanceId,_channelId),
1869 "Channel::SendPacket() RTCP dump to input file failed");
1870 }
1871
1872 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001873 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1874 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001875 _engineStatisticsPtr->SetLastError(
1876 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1877 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1878 }
wu@webrtc.org82c4b852014-05-20 22:55:01 +00001879
1880 ntp_estimator_->UpdateRtcpTimestamp(rtp_receiver_->SSRC(),
1881 _rtpRtcpModule.get());
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001882 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001883}
1884
niklase@google.com470e71d2011-07-07 08:21:25 +00001885int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001886 bool loop,
1887 FileFormats format,
1888 int startPosition,
1889 float volumeScaling,
1890 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001891 const CodecInst* codecInst)
1892{
1893 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1894 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1895 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1896 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1897 startPosition, stopPosition);
1898
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001899 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001900 {
1901 _engineStatisticsPtr->SetLastError(
1902 VE_ALREADY_PLAYING, kTraceError,
1903 "StartPlayingFileLocally() is already playing");
1904 return -1;
1905 }
1906
niklase@google.com470e71d2011-07-07 08:21:25 +00001907 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001908 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001909
1910 if (_outputFilePlayerPtr)
1911 {
1912 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1913 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1914 _outputFilePlayerPtr = NULL;
1915 }
1916
1917 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1918 _outputFilePlayerId, (const FileFormats)format);
1919
1920 if (_outputFilePlayerPtr == NULL)
1921 {
1922 _engineStatisticsPtr->SetLastError(
1923 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001924 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001925 return -1;
1926 }
1927
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001928 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001929
1930 if (_outputFilePlayerPtr->StartPlayingFile(
1931 fileName,
1932 loop,
1933 startPosition,
1934 volumeScaling,
1935 notificationTime,
1936 stopPosition,
1937 (const CodecInst*)codecInst) != 0)
1938 {
1939 _engineStatisticsPtr->SetLastError(
1940 VE_BAD_FILE, kTraceError,
1941 "StartPlayingFile() failed to start file playout");
1942 _outputFilePlayerPtr->StopPlayingFile();
1943 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1944 _outputFilePlayerPtr = NULL;
1945 return -1;
1946 }
1947 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001948 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001949 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001950
1951 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001952 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001953
1954 return 0;
1955}
1956
1957int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001958 FileFormats format,
1959 int startPosition,
1960 float volumeScaling,
1961 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001962 const CodecInst* codecInst)
1963{
1964 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1965 "Channel::StartPlayingFileLocally(format=%d,"
1966 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1967 format, volumeScaling, startPosition, stopPosition);
1968
1969 if(stream == NULL)
1970 {
1971 _engineStatisticsPtr->SetLastError(
1972 VE_BAD_FILE, kTraceError,
1973 "StartPlayingFileLocally() NULL as input stream");
1974 return -1;
1975 }
1976
1977
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001978 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001979 {
1980 _engineStatisticsPtr->SetLastError(
1981 VE_ALREADY_PLAYING, kTraceError,
1982 "StartPlayingFileLocally() is already playing");
1983 return -1;
1984 }
1985
niklase@google.com470e71d2011-07-07 08:21:25 +00001986 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001987 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001988
1989 // Destroy the old instance
1990 if (_outputFilePlayerPtr)
1991 {
1992 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1993 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1994 _outputFilePlayerPtr = NULL;
1995 }
1996
1997 // Create the instance
1998 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1999 _outputFilePlayerId,
2000 (const FileFormats)format);
2001
2002 if (_outputFilePlayerPtr == NULL)
2003 {
2004 _engineStatisticsPtr->SetLastError(
2005 VE_INVALID_ARGUMENT, kTraceError,
2006 "StartPlayingFileLocally() filePlayer format isnot correct");
2007 return -1;
2008 }
2009
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002010 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002011
2012 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2013 volumeScaling,
2014 notificationTime,
2015 stopPosition, codecInst) != 0)
2016 {
2017 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2018 "StartPlayingFile() failed to "
2019 "start file playout");
2020 _outputFilePlayerPtr->StopPlayingFile();
2021 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2022 _outputFilePlayerPtr = NULL;
2023 return -1;
2024 }
2025 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002026 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002027 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002028
2029 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002030 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002031
niklase@google.com470e71d2011-07-07 08:21:25 +00002032 return 0;
2033}
2034
2035int Channel::StopPlayingFileLocally()
2036{
2037 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2038 "Channel::StopPlayingFileLocally()");
2039
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002040 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002041 {
2042 _engineStatisticsPtr->SetLastError(
2043 VE_INVALID_OPERATION, kTraceWarning,
2044 "StopPlayingFileLocally() isnot playing");
2045 return 0;
2046 }
2047
niklase@google.com470e71d2011-07-07 08:21:25 +00002048 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002049 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002050
2051 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2052 {
2053 _engineStatisticsPtr->SetLastError(
2054 VE_STOP_RECORDING_FAILED, kTraceError,
2055 "StopPlayingFile() could not stop playing");
2056 return -1;
2057 }
2058 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2059 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2060 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002061 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002062 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002063 // _fileCritSect cannot be taken while calling
2064 // SetAnonymousMixibilityStatus. Refer to comments in
2065 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002066 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2067 {
2068 _engineStatisticsPtr->SetLastError(
2069 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002070 "StopPlayingFile() failed to stop participant from playing as"
2071 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002072 return -1;
2073 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002074
2075 return 0;
2076}
2077
2078int Channel::IsPlayingFileLocally() const
2079{
2080 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2081 "Channel::IsPlayingFileLocally()");
2082
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002083 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002084}
2085
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002086int Channel::RegisterFilePlayingToMixer()
2087{
2088 // Return success for not registering for file playing to mixer if:
2089 // 1. playing file before playout is started on that channel.
2090 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002091 if (!channel_state_.Get().playing ||
2092 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002093 {
2094 return 0;
2095 }
2096
2097 // |_fileCritSect| cannot be taken while calling
2098 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2099 // frames can be pulled by the mixer. Since the frames are generated from
2100 // the file, _fileCritSect will be taken. This would result in a deadlock.
2101 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2102 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002103 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002104 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002105 _engineStatisticsPtr->SetLastError(
2106 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2107 "StartPlayingFile() failed to add participant as file to mixer");
2108 _outputFilePlayerPtr->StopPlayingFile();
2109 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2110 _outputFilePlayerPtr = NULL;
2111 return -1;
2112 }
2113
2114 return 0;
2115}
2116
niklase@google.com470e71d2011-07-07 08:21:25 +00002117int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002118 bool loop,
2119 FileFormats format,
2120 int startPosition,
2121 float volumeScaling,
2122 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002123 const CodecInst* codecInst)
2124{
2125 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2126 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2127 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2128 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2129 startPosition, stopPosition);
2130
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002131 CriticalSectionScoped cs(&_fileCritSect);
2132
2133 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002134 {
2135 _engineStatisticsPtr->SetLastError(
2136 VE_ALREADY_PLAYING, kTraceWarning,
2137 "StartPlayingFileAsMicrophone() filePlayer is playing");
2138 return 0;
2139 }
2140
niklase@google.com470e71d2011-07-07 08:21:25 +00002141 // Destroy the old instance
2142 if (_inputFilePlayerPtr)
2143 {
2144 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2145 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2146 _inputFilePlayerPtr = NULL;
2147 }
2148
2149 // Create the instance
2150 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2151 _inputFilePlayerId, (const FileFormats)format);
2152
2153 if (_inputFilePlayerPtr == NULL)
2154 {
2155 _engineStatisticsPtr->SetLastError(
2156 VE_INVALID_ARGUMENT, kTraceError,
2157 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2158 return -1;
2159 }
2160
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002161 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002162
2163 if (_inputFilePlayerPtr->StartPlayingFile(
2164 fileName,
2165 loop,
2166 startPosition,
2167 volumeScaling,
2168 notificationTime,
2169 stopPosition,
2170 (const CodecInst*)codecInst) != 0)
2171 {
2172 _engineStatisticsPtr->SetLastError(
2173 VE_BAD_FILE, kTraceError,
2174 "StartPlayingFile() failed to start file playout");
2175 _inputFilePlayerPtr->StopPlayingFile();
2176 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2177 _inputFilePlayerPtr = NULL;
2178 return -1;
2179 }
2180 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002181 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002182
2183 return 0;
2184}
2185
2186int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002187 FileFormats format,
2188 int startPosition,
2189 float volumeScaling,
2190 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002191 const CodecInst* codecInst)
2192{
2193 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2194 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2195 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2196 format, volumeScaling, startPosition, stopPosition);
2197
2198 if(stream == NULL)
2199 {
2200 _engineStatisticsPtr->SetLastError(
2201 VE_BAD_FILE, kTraceError,
2202 "StartPlayingFileAsMicrophone NULL as input stream");
2203 return -1;
2204 }
2205
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002206 CriticalSectionScoped cs(&_fileCritSect);
2207
2208 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002209 {
2210 _engineStatisticsPtr->SetLastError(
2211 VE_ALREADY_PLAYING, kTraceWarning,
2212 "StartPlayingFileAsMicrophone() is playing");
2213 return 0;
2214 }
2215
niklase@google.com470e71d2011-07-07 08:21:25 +00002216 // Destroy the old instance
2217 if (_inputFilePlayerPtr)
2218 {
2219 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2220 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2221 _inputFilePlayerPtr = NULL;
2222 }
2223
2224 // Create the instance
2225 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2226 _inputFilePlayerId, (const FileFormats)format);
2227
2228 if (_inputFilePlayerPtr == NULL)
2229 {
2230 _engineStatisticsPtr->SetLastError(
2231 VE_INVALID_ARGUMENT, kTraceError,
2232 "StartPlayingInputFile() filePlayer format isnot correct");
2233 return -1;
2234 }
2235
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002236 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002237
2238 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2239 volumeScaling, notificationTime,
2240 stopPosition, codecInst) != 0)
2241 {
2242 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2243 "StartPlayingFile() failed to start "
2244 "file playout");
2245 _inputFilePlayerPtr->StopPlayingFile();
2246 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2247 _inputFilePlayerPtr = NULL;
2248 return -1;
2249 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002250
niklase@google.com470e71d2011-07-07 08:21:25 +00002251 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002252 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002253
2254 return 0;
2255}
2256
2257int Channel::StopPlayingFileAsMicrophone()
2258{
2259 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2260 "Channel::StopPlayingFileAsMicrophone()");
2261
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002262 CriticalSectionScoped cs(&_fileCritSect);
2263
2264 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002265 {
2266 _engineStatisticsPtr->SetLastError(
2267 VE_INVALID_OPERATION, kTraceWarning,
2268 "StopPlayingFileAsMicrophone() isnot playing");
2269 return 0;
2270 }
2271
niklase@google.com470e71d2011-07-07 08:21:25 +00002272 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2273 {
2274 _engineStatisticsPtr->SetLastError(
2275 VE_STOP_RECORDING_FAILED, kTraceError,
2276 "StopPlayingFile() could not stop playing");
2277 return -1;
2278 }
2279 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2280 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2281 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002282 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002283
2284 return 0;
2285}
2286
2287int Channel::IsPlayingFileAsMicrophone() const
2288{
2289 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2290 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002291 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002292}
2293
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002294int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002295 const CodecInst* codecInst)
2296{
2297 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2298 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2299
2300 if (_outputFileRecording)
2301 {
2302 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2303 "StartRecordingPlayout() is already recording");
2304 return 0;
2305 }
2306
2307 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002308 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002309 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2310
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002311 if ((codecInst != NULL) &&
2312 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002313 {
2314 _engineStatisticsPtr->SetLastError(
2315 VE_BAD_ARGUMENT, kTraceError,
2316 "StartRecordingPlayout() invalid compression");
2317 return(-1);
2318 }
2319 if(codecInst == NULL)
2320 {
2321 format = kFileFormatPcm16kHzFile;
2322 codecInst=&dummyCodec;
2323 }
2324 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2325 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2326 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2327 {
2328 format = kFileFormatWavFile;
2329 }
2330 else
2331 {
2332 format = kFileFormatCompressedFile;
2333 }
2334
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002335 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002336
2337 // Destroy the old instance
2338 if (_outputFileRecorderPtr)
2339 {
2340 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2341 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2342 _outputFileRecorderPtr = NULL;
2343 }
2344
2345 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2346 _outputFileRecorderId, (const FileFormats)format);
2347 if (_outputFileRecorderPtr == NULL)
2348 {
2349 _engineStatisticsPtr->SetLastError(
2350 VE_INVALID_ARGUMENT, kTraceError,
2351 "StartRecordingPlayout() fileRecorder format isnot correct");
2352 return -1;
2353 }
2354
2355 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2356 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2357 {
2358 _engineStatisticsPtr->SetLastError(
2359 VE_BAD_FILE, kTraceError,
2360 "StartRecordingAudioFile() failed to start file recording");
2361 _outputFileRecorderPtr->StopRecording();
2362 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2363 _outputFileRecorderPtr = NULL;
2364 return -1;
2365 }
2366 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2367 _outputFileRecording = true;
2368
2369 return 0;
2370}
2371
2372int Channel::StartRecordingPlayout(OutStream* stream,
2373 const CodecInst* codecInst)
2374{
2375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2376 "Channel::StartRecordingPlayout()");
2377
2378 if (_outputFileRecording)
2379 {
2380 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2381 "StartRecordingPlayout() is already recording");
2382 return 0;
2383 }
2384
2385 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002386 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002387 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2388
2389 if (codecInst != NULL && codecInst->channels != 1)
2390 {
2391 _engineStatisticsPtr->SetLastError(
2392 VE_BAD_ARGUMENT, kTraceError,
2393 "StartRecordingPlayout() invalid compression");
2394 return(-1);
2395 }
2396 if(codecInst == NULL)
2397 {
2398 format = kFileFormatPcm16kHzFile;
2399 codecInst=&dummyCodec;
2400 }
2401 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2402 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2403 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2404 {
2405 format = kFileFormatWavFile;
2406 }
2407 else
2408 {
2409 format = kFileFormatCompressedFile;
2410 }
2411
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002412 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002413
2414 // Destroy the old instance
2415 if (_outputFileRecorderPtr)
2416 {
2417 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2418 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2419 _outputFileRecorderPtr = NULL;
2420 }
2421
2422 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2423 _outputFileRecorderId, (const FileFormats)format);
2424 if (_outputFileRecorderPtr == NULL)
2425 {
2426 _engineStatisticsPtr->SetLastError(
2427 VE_INVALID_ARGUMENT, kTraceError,
2428 "StartRecordingPlayout() fileRecorder format isnot correct");
2429 return -1;
2430 }
2431
2432 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2433 notificationTime) != 0)
2434 {
2435 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2436 "StartRecordingPlayout() failed to "
2437 "start file recording");
2438 _outputFileRecorderPtr->StopRecording();
2439 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2440 _outputFileRecorderPtr = NULL;
2441 return -1;
2442 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002443
niklase@google.com470e71d2011-07-07 08:21:25 +00002444 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2445 _outputFileRecording = true;
2446
2447 return 0;
2448}
2449
2450int Channel::StopRecordingPlayout()
2451{
2452 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2453 "Channel::StopRecordingPlayout()");
2454
2455 if (!_outputFileRecording)
2456 {
2457 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2458 "StopRecordingPlayout() isnot recording");
2459 return -1;
2460 }
2461
2462
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002463 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002464
2465 if (_outputFileRecorderPtr->StopRecording() != 0)
2466 {
2467 _engineStatisticsPtr->SetLastError(
2468 VE_STOP_RECORDING_FAILED, kTraceError,
2469 "StopRecording() could not stop recording");
2470 return(-1);
2471 }
2472 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2473 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2474 _outputFileRecorderPtr = NULL;
2475 _outputFileRecording = false;
2476
2477 return 0;
2478}
2479
2480void
2481Channel::SetMixWithMicStatus(bool mix)
2482{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002483 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002484 _mixFileWithMicrophone=mix;
2485}
2486
2487int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002488Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002489{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002490 int8_t currentLevel = _outputAudioLevel.Level();
2491 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002492 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2493 VoEId(_instanceId,_channelId),
2494 "GetSpeechOutputLevel() => level=%u", level);
2495 return 0;
2496}
2497
2498int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002499Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002500{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002501 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2502 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002503 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2504 VoEId(_instanceId,_channelId),
2505 "GetSpeechOutputLevelFullRange() => level=%u", level);
2506 return 0;
2507}
2508
2509int
2510Channel::SetMute(bool enable)
2511{
wu@webrtc.org63420662013-10-17 18:28:55 +00002512 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002513 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2514 "Channel::SetMute(enable=%d)", enable);
2515 _mute = enable;
2516 return 0;
2517}
2518
2519bool
2520Channel::Mute() const
2521{
wu@webrtc.org63420662013-10-17 18:28:55 +00002522 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002523 return _mute;
2524}
2525
2526int
2527Channel::SetOutputVolumePan(float left, float right)
2528{
wu@webrtc.org63420662013-10-17 18:28:55 +00002529 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2531 "Channel::SetOutputVolumePan()");
2532 _panLeft = left;
2533 _panRight = right;
2534 return 0;
2535}
2536
2537int
2538Channel::GetOutputVolumePan(float& left, float& right) const
2539{
wu@webrtc.org63420662013-10-17 18:28:55 +00002540 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002541 left = _panLeft;
2542 right = _panRight;
2543 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2544 VoEId(_instanceId,_channelId),
2545 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2546 return 0;
2547}
2548
2549int
2550Channel::SetChannelOutputVolumeScaling(float scaling)
2551{
wu@webrtc.org63420662013-10-17 18:28:55 +00002552 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002553 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2554 "Channel::SetChannelOutputVolumeScaling()");
2555 _outputGain = scaling;
2556 return 0;
2557}
2558
2559int
2560Channel::GetChannelOutputVolumeScaling(float& scaling) const
2561{
wu@webrtc.org63420662013-10-17 18:28:55 +00002562 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002563 scaling = _outputGain;
2564 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2565 VoEId(_instanceId,_channelId),
2566 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2567 return 0;
2568}
2569
niklase@google.com470e71d2011-07-07 08:21:25 +00002570int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002571 int lengthMs, int attenuationDb,
2572 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002573{
2574 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2575 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2576 playDtmfEvent);
2577
2578 _playOutbandDtmfEvent = playDtmfEvent;
2579
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002580 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002581 attenuationDb) != 0)
2582 {
2583 _engineStatisticsPtr->SetLastError(
2584 VE_SEND_DTMF_FAILED,
2585 kTraceWarning,
2586 "SendTelephoneEventOutband() failed to send event");
2587 return -1;
2588 }
2589 return 0;
2590}
2591
2592int Channel::SendTelephoneEventInband(unsigned char eventCode,
2593 int lengthMs,
2594 int attenuationDb,
2595 bool playDtmfEvent)
2596{
2597 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2598 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2599 playDtmfEvent);
2600
2601 _playInbandDtmfEvent = playDtmfEvent;
2602 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2603
2604 return 0;
2605}
2606
2607int
2608Channel::SetDtmfPlayoutStatus(bool enable)
2609{
2610 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2611 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002612 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002613 {
2614 _engineStatisticsPtr->SetLastError(
2615 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2616 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2617 return -1;
2618 }
2619 return 0;
2620}
2621
2622bool
2623Channel::DtmfPlayoutStatus() const
2624{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002625 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002626}
2627
2628int
2629Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2630{
2631 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2632 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002633 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002634 {
2635 _engineStatisticsPtr->SetLastError(
2636 VE_INVALID_ARGUMENT, kTraceError,
2637 "SetSendTelephoneEventPayloadType() invalid type");
2638 return -1;
2639 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002640 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002641 codec.plfreq = 8000;
2642 codec.pltype = type;
2643 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002644 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002645 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002646 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2647 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2648 _engineStatisticsPtr->SetLastError(
2649 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2650 "SetSendTelephoneEventPayloadType() failed to register send"
2651 "payload type");
2652 return -1;
2653 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002654 }
2655 _sendTelephoneEventPayloadType = type;
2656 return 0;
2657}
2658
2659int
2660Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2661{
2662 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2663 "Channel::GetSendTelephoneEventPayloadType()");
2664 type = _sendTelephoneEventPayloadType;
2665 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2666 VoEId(_instanceId,_channelId),
2667 "GetSendTelephoneEventPayloadType() => type=%u", type);
2668 return 0;
2669}
2670
niklase@google.com470e71d2011-07-07 08:21:25 +00002671int
2672Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2673{
2674 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2675 "Channel::UpdateRxVadDetection()");
2676
2677 int vadDecision = 1;
2678
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002679 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002680
2681 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2682 {
2683 OnRxVadDetected(vadDecision);
2684 _oldVadDecision = vadDecision;
2685 }
2686
2687 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2688 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2689 vadDecision);
2690 return 0;
2691}
2692
2693int
2694Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2695{
2696 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2697 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002698 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002699
2700 if (_rxVadObserverPtr)
2701 {
2702 _engineStatisticsPtr->SetLastError(
2703 VE_INVALID_OPERATION, kTraceError,
2704 "RegisterRxVadObserver() observer already enabled");
2705 return -1;
2706 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002707 _rxVadObserverPtr = &observer;
2708 _RxVadDetection = true;
2709 return 0;
2710}
2711
2712int
2713Channel::DeRegisterRxVadObserver()
2714{
2715 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2716 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002717 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002718
2719 if (!_rxVadObserverPtr)
2720 {
2721 _engineStatisticsPtr->SetLastError(
2722 VE_INVALID_OPERATION, kTraceWarning,
2723 "DeRegisterRxVadObserver() observer already disabled");
2724 return 0;
2725 }
2726 _rxVadObserverPtr = NULL;
2727 _RxVadDetection = false;
2728 return 0;
2729}
2730
2731int
2732Channel::VoiceActivityIndicator(int &activity)
2733{
2734 activity = _sendFrameType;
2735
2736 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002737 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002738 return 0;
2739}
2740
2741#ifdef WEBRTC_VOICE_ENGINE_AGC
2742
2743int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002744Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002745{
2746 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2747 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2748 (int)enable, (int)mode);
2749
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002750 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002751 switch (mode)
2752 {
2753 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002754 break;
2755 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002756 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002757 break;
2758 case kAgcFixedDigital:
2759 agcMode = GainControl::kFixedDigital;
2760 break;
2761 case kAgcAdaptiveDigital:
2762 agcMode =GainControl::kAdaptiveDigital;
2763 break;
2764 default:
2765 _engineStatisticsPtr->SetLastError(
2766 VE_INVALID_ARGUMENT, kTraceError,
2767 "SetRxAgcStatus() invalid Agc mode");
2768 return -1;
2769 }
2770
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002771 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002772 {
2773 _engineStatisticsPtr->SetLastError(
2774 VE_APM_ERROR, kTraceError,
2775 "SetRxAgcStatus() failed to set Agc mode");
2776 return -1;
2777 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002778 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002779 {
2780 _engineStatisticsPtr->SetLastError(
2781 VE_APM_ERROR, kTraceError,
2782 "SetRxAgcStatus() failed to set Agc state");
2783 return -1;
2784 }
2785
2786 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002787 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002788
2789 return 0;
2790}
2791
2792int
2793Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2794{
2795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2796 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2797
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002798 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002799 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002800 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002801
2802 enabled = enable;
2803
2804 switch (agcMode)
2805 {
2806 case GainControl::kFixedDigital:
2807 mode = kAgcFixedDigital;
2808 break;
2809 case GainControl::kAdaptiveDigital:
2810 mode = kAgcAdaptiveDigital;
2811 break;
2812 default:
2813 _engineStatisticsPtr->SetLastError(
2814 VE_APM_ERROR, kTraceError,
2815 "GetRxAgcStatus() invalid Agc mode");
2816 return -1;
2817 }
2818
2819 return 0;
2820}
2821
2822int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002823Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002824{
2825 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2826 "Channel::SetRxAgcConfig()");
2827
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002828 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002829 config.targetLeveldBOv) != 0)
2830 {
2831 _engineStatisticsPtr->SetLastError(
2832 VE_APM_ERROR, kTraceError,
2833 "SetRxAgcConfig() failed to set target peak |level|"
2834 "(or envelope) of the Agc");
2835 return -1;
2836 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002837 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002838 config.digitalCompressionGaindB) != 0)
2839 {
2840 _engineStatisticsPtr->SetLastError(
2841 VE_APM_ERROR, kTraceError,
2842 "SetRxAgcConfig() failed to set the range in |gain| the"
2843 " digital compression stage may apply");
2844 return -1;
2845 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002846 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002847 config.limiterEnable) != 0)
2848 {
2849 _engineStatisticsPtr->SetLastError(
2850 VE_APM_ERROR, kTraceError,
2851 "SetRxAgcConfig() failed to set hard limiter to the signal");
2852 return -1;
2853 }
2854
2855 return 0;
2856}
2857
2858int
2859Channel::GetRxAgcConfig(AgcConfig& config)
2860{
2861 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2862 "Channel::GetRxAgcConfig(config=%?)");
2863
2864 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002865 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002866 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002867 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002868 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002869 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002870
2871 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2872 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2873 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2874 " limiterEnable=%d",
2875 config.targetLeveldBOv,
2876 config.digitalCompressionGaindB,
2877 config.limiterEnable);
2878
2879 return 0;
2880}
2881
2882#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2883
2884#ifdef WEBRTC_VOICE_ENGINE_NR
2885
2886int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002887Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002888{
2889 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2890 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2891 (int)enable, (int)mode);
2892
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002893 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002894 switch (mode)
2895 {
2896
2897 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002898 break;
2899 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002900 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 break;
2902 case kNsConference:
2903 nsLevel = NoiseSuppression::kHigh;
2904 break;
2905 case kNsLowSuppression:
2906 nsLevel = NoiseSuppression::kLow;
2907 break;
2908 case kNsModerateSuppression:
2909 nsLevel = NoiseSuppression::kModerate;
2910 break;
2911 case kNsHighSuppression:
2912 nsLevel = NoiseSuppression::kHigh;
2913 break;
2914 case kNsVeryHighSuppression:
2915 nsLevel = NoiseSuppression::kVeryHigh;
2916 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002917 }
2918
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002919 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002920 != 0)
2921 {
2922 _engineStatisticsPtr->SetLastError(
2923 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002924 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002925 return -1;
2926 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002927 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002928 {
2929 _engineStatisticsPtr->SetLastError(
2930 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002931 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002932 return -1;
2933 }
2934
2935 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002936 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002937
2938 return 0;
2939}
2940
2941int
2942Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2943{
2944 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2945 "Channel::GetRxNsStatus(enable=?, mode=?)");
2946
2947 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002948 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002949 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002950 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002951
2952 enabled = enable;
2953
2954 switch (ncLevel)
2955 {
2956 case NoiseSuppression::kLow:
2957 mode = kNsLowSuppression;
2958 break;
2959 case NoiseSuppression::kModerate:
2960 mode = kNsModerateSuppression;
2961 break;
2962 case NoiseSuppression::kHigh:
2963 mode = kNsHighSuppression;
2964 break;
2965 case NoiseSuppression::kVeryHigh:
2966 mode = kNsVeryHighSuppression;
2967 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002968 }
2969
2970 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2971 VoEId(_instanceId,_channelId),
2972 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2973 return 0;
2974}
2975
2976#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2977
2978int
niklase@google.com470e71d2011-07-07 08:21:25 +00002979Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
2980{
2981 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2982 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002983 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002984
2985 if (_rtcpObserverPtr)
2986 {
2987 _engineStatisticsPtr->SetLastError(
2988 VE_INVALID_OPERATION, kTraceError,
2989 "RegisterRTCPObserver() observer already enabled");
2990 return -1;
2991 }
2992
2993 _rtcpObserverPtr = &observer;
2994 _rtcpObserver = true;
2995
2996 return 0;
2997}
2998
2999int
3000Channel::DeRegisterRTCPObserver()
3001{
3002 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3003 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003004 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003005
3006 if (!_rtcpObserverPtr)
3007 {
3008 _engineStatisticsPtr->SetLastError(
3009 VE_INVALID_OPERATION, kTraceWarning,
3010 "DeRegisterRTCPObserver() observer already disabled");
3011 return 0;
3012 }
3013
3014 _rtcpObserver = false;
3015 _rtcpObserverPtr = NULL;
3016
3017 return 0;
3018}
3019
3020int
3021Channel::SetLocalSSRC(unsigned int ssrc)
3022{
3023 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3024 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003025 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003026 {
3027 _engineStatisticsPtr->SetLastError(
3028 VE_ALREADY_SENDING, kTraceError,
3029 "SetLocalSSRC() already sending");
3030 return -1;
3031 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003032 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003033 {
3034 _engineStatisticsPtr->SetLastError(
3035 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3036 "SetLocalSSRC() failed to set SSRC");
3037 return -1;
3038 }
3039 return 0;
3040}
3041
3042int
3043Channel::GetLocalSSRC(unsigned int& ssrc)
3044{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003045 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003046 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3047 VoEId(_instanceId,_channelId),
3048 "GetLocalSSRC() => ssrc=%lu", ssrc);
3049 return 0;
3050}
3051
3052int
3053Channel::GetRemoteSSRC(unsigned int& ssrc)
3054{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003055 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003056 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3057 VoEId(_instanceId,_channelId),
3058 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3059 return 0;
3060}
3061
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003062int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003063 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003064 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003065}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003066
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003067int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3068 unsigned char id) {
3069 rtp_header_parser_->DeregisterRtpHeaderExtension(
3070 kRtpExtensionAudioLevel);
3071 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3072 kRtpExtensionAudioLevel, id)) {
3073 return -1;
3074 }
3075 return 0;
3076}
3077
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003078int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3079 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3080}
3081
3082int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3083 rtp_header_parser_->DeregisterRtpHeaderExtension(
3084 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003085 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3086 kRtpExtensionAbsoluteSendTime, id)) {
3087 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003088 }
3089 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003090}
3091
3092int
3093Channel::SetRTCPStatus(bool enable)
3094{
3095 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3096 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003097 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003098 kRtcpCompound : kRtcpOff) != 0)
3099 {
3100 _engineStatisticsPtr->SetLastError(
3101 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3102 "SetRTCPStatus() failed to set RTCP status");
3103 return -1;
3104 }
3105 return 0;
3106}
3107
3108int
3109Channel::GetRTCPStatus(bool& enabled)
3110{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003111 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003112 enabled = (method != kRtcpOff);
3113 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3114 VoEId(_instanceId,_channelId),
3115 "GetRTCPStatus() => enabled=%d", enabled);
3116 return 0;
3117}
3118
3119int
3120Channel::SetRTCP_CNAME(const char cName[256])
3121{
3122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3123 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003124 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003125 {
3126 _engineStatisticsPtr->SetLastError(
3127 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3128 "SetRTCP_CNAME() failed to set RTCP CNAME");
3129 return -1;
3130 }
3131 return 0;
3132}
3133
3134int
3135Channel::GetRTCP_CNAME(char cName[256])
3136{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003137 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003138 {
3139 _engineStatisticsPtr->SetLastError(
3140 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3141 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3142 return -1;
3143 }
3144 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3145 VoEId(_instanceId, _channelId),
3146 "GetRTCP_CNAME() => cName=%s", cName);
3147 return 0;
3148}
3149
3150int
3151Channel::GetRemoteRTCP_CNAME(char cName[256])
3152{
3153 if (cName == NULL)
3154 {
3155 _engineStatisticsPtr->SetLastError(
3156 VE_INVALID_ARGUMENT, kTraceError,
3157 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3158 return -1;
3159 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003160 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003161 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003162 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003163 {
3164 _engineStatisticsPtr->SetLastError(
3165 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3166 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3167 return -1;
3168 }
3169 strcpy(cName, cname);
3170 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3171 VoEId(_instanceId, _channelId),
3172 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3173 return 0;
3174}
3175
3176int
3177Channel::GetRemoteRTCPData(
3178 unsigned int& NTPHigh,
3179 unsigned int& NTPLow,
3180 unsigned int& timestamp,
3181 unsigned int& playoutTimestamp,
3182 unsigned int* jitter,
3183 unsigned short* fractionLost)
3184{
3185 // --- Information from sender info in received Sender Reports
3186
3187 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003188 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003189 {
3190 _engineStatisticsPtr->SetLastError(
3191 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003192 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003193 "side");
3194 return -1;
3195 }
3196
3197 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3198 // and octet count)
3199 NTPHigh = senderInfo.NTPseconds;
3200 NTPLow = senderInfo.NTPfraction;
3201 timestamp = senderInfo.RTPtimeStamp;
3202
3203 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3204 VoEId(_instanceId, _channelId),
3205 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3206 "timestamp=%lu",
3207 NTPHigh, NTPLow, timestamp);
3208
3209 // --- Locally derived information
3210
3211 // This value is updated on each incoming RTCP packet (0 when no packet
3212 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003213 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003214
3215 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3216 VoEId(_instanceId, _channelId),
3217 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003218 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003219
3220 if (NULL != jitter || NULL != fractionLost)
3221 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003222 // Get all RTCP receiver report blocks that have been received on this
3223 // channel. If we receive RTP packets from a remote source we know the
3224 // remote SSRC and use the report block from him.
3225 // Otherwise use the first report block.
3226 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003227 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003228 remote_stats.empty()) {
3229 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3230 VoEId(_instanceId, _channelId),
3231 "GetRemoteRTCPData() failed to measure statistics due"
3232 " to lack of received RTP and/or RTCP packets");
3233 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003234 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003235
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003236 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003237 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3238 for (; it != remote_stats.end(); ++it) {
3239 if (it->remoteSSRC == remoteSSRC)
3240 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003241 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003242
3243 if (it == remote_stats.end()) {
3244 // If we have not received any RTCP packets from this SSRC it probably
3245 // means that we have not received any RTP packets.
3246 // Use the first received report block instead.
3247 it = remote_stats.begin();
3248 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003249 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003250
xians@webrtc.org79af7342012-01-31 12:22:14 +00003251 if (jitter) {
3252 *jitter = it->jitter;
3253 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3254 VoEId(_instanceId, _channelId),
3255 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3256 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003257
xians@webrtc.org79af7342012-01-31 12:22:14 +00003258 if (fractionLost) {
3259 *fractionLost = it->fractionLost;
3260 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3261 VoEId(_instanceId, _channelId),
3262 "GetRemoteRTCPData() => fractionLost = %lu",
3263 *fractionLost);
3264 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 }
3266 return 0;
3267}
3268
3269int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003270Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003271 unsigned int name,
3272 const char* data,
3273 unsigned short dataLengthInBytes)
3274{
3275 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3276 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003277 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003278 {
3279 _engineStatisticsPtr->SetLastError(
3280 VE_NOT_SENDING, kTraceError,
3281 "SendApplicationDefinedRTCPPacket() not sending");
3282 return -1;
3283 }
3284 if (NULL == data)
3285 {
3286 _engineStatisticsPtr->SetLastError(
3287 VE_INVALID_ARGUMENT, kTraceError,
3288 "SendApplicationDefinedRTCPPacket() invalid data value");
3289 return -1;
3290 }
3291 if (dataLengthInBytes % 4 != 0)
3292 {
3293 _engineStatisticsPtr->SetLastError(
3294 VE_INVALID_ARGUMENT, kTraceError,
3295 "SendApplicationDefinedRTCPPacket() invalid length value");
3296 return -1;
3297 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003298 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003299 if (status == kRtcpOff)
3300 {
3301 _engineStatisticsPtr->SetLastError(
3302 VE_RTCP_ERROR, kTraceError,
3303 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3304 return -1;
3305 }
3306
3307 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003308 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003309 subType,
3310 name,
3311 (const unsigned char*) data,
3312 dataLengthInBytes) != 0)
3313 {
3314 _engineStatisticsPtr->SetLastError(
3315 VE_SEND_ERROR, kTraceError,
3316 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3317 return -1;
3318 }
3319 return 0;
3320}
3321
3322int
3323Channel::GetRTPStatistics(
3324 unsigned int& averageJitterMs,
3325 unsigned int& maxJitterMs,
3326 unsigned int& discardedPackets)
3327{
niklase@google.com470e71d2011-07-07 08:21:25 +00003328 // The jitter statistics is updated for each received RTP packet and is
3329 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003330 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3331 // If RTCP is off, there is no timed thread in the RTCP module regularly
3332 // generating new stats, trigger the update manually here instead.
3333 StreamStatistician* statistician =
3334 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3335 if (statistician) {
3336 // Don't use returned statistics, use data from proxy instead so that
3337 // max jitter can be fetched atomically.
3338 RtcpStatistics s;
3339 statistician->GetStatistics(&s, true);
3340 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003341 }
3342
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003343 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003344 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003345 if (playoutFrequency > 0) {
3346 // Scale RTP statistics given the current playout frequency
3347 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3348 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003349 }
3350
3351 discardedPackets = _numberOfDiscardedPackets;
3352
3353 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3354 VoEId(_instanceId, _channelId),
3355 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003356 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003357 averageJitterMs, maxJitterMs, discardedPackets);
3358 return 0;
3359}
3360
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003361int Channel::GetRemoteRTCPReportBlocks(
3362 std::vector<ReportBlock>* report_blocks) {
3363 if (report_blocks == NULL) {
3364 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3365 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3366 return -1;
3367 }
3368
3369 // Get the report blocks from the latest received RTCP Sender or Receiver
3370 // Report. Each element in the vector contains the sender's SSRC and a
3371 // report block according to RFC 3550.
3372 std::vector<RTCPReportBlock> rtcp_report_blocks;
3373 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3374 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3375 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3376 return -1;
3377 }
3378
3379 if (rtcp_report_blocks.empty())
3380 return 0;
3381
3382 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3383 for (; it != rtcp_report_blocks.end(); ++it) {
3384 ReportBlock report_block;
3385 report_block.sender_SSRC = it->remoteSSRC;
3386 report_block.source_SSRC = it->sourceSSRC;
3387 report_block.fraction_lost = it->fractionLost;
3388 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3389 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3390 report_block.interarrival_jitter = it->jitter;
3391 report_block.last_SR_timestamp = it->lastSR;
3392 report_block.delay_since_last_SR = it->delaySinceLastSR;
3393 report_blocks->push_back(report_block);
3394 }
3395 return 0;
3396}
3397
niklase@google.com470e71d2011-07-07 08:21:25 +00003398int
3399Channel::GetRTPStatistics(CallStatistics& stats)
3400{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003401 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003402
3403 // The jitter statistics is updated for each received RTP packet and is
3404 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003405 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003406 StreamStatistician* statistician =
3407 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3408 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003409 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3410 _engineStatisticsPtr->SetLastError(
3411 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3412 "GetRTPStatistics() failed to read RTP statistics from the "
3413 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003414 }
3415
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003416 stats.fractionLost = statistics.fraction_lost;
3417 stats.cumulativeLost = statistics.cumulative_lost;
3418 stats.extendedMax = statistics.extended_max_sequence_number;
3419 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003420
3421 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3422 VoEId(_instanceId, _channelId),
3423 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003424 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003425 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3426 stats.jitterSamples);
3427
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003428 // --- RTT
niklase@google.com470e71d2011-07-07 08:21:25 +00003429
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003430 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003431 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003432 if (method == kRtcpOff)
3433 {
3434 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3435 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003436 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003437 "measurements cannot be retrieved");
3438 } else
3439 {
3440 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003441 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003442 if (remoteSSRC > 0)
3443 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003444 uint16_t avgRTT(0);
3445 uint16_t maxRTT(0);
3446 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003447
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003448 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003449 != 0)
3450 {
3451 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3452 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003453 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003454 "the RTP/RTCP module");
3455 }
3456 } else
3457 {
3458 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3459 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003460 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003461 "RTP packets have been received yet");
3462 }
3463 }
3464
3465 stats.rttMs = static_cast<int> (RTT);
3466
3467 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3468 VoEId(_instanceId, _channelId),
3469 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3470
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003471 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003472
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003473 uint32_t bytesSent(0);
3474 uint32_t packetsSent(0);
3475 uint32_t bytesReceived(0);
3476 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003477
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003478 if (statistician) {
3479 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3480 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003481
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003482 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003483 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003484 {
3485 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3486 VoEId(_instanceId, _channelId),
3487 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003488 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003489 }
3490
3491 stats.bytesSent = bytesSent;
3492 stats.packetsSent = packetsSent;
3493 stats.bytesReceived = bytesReceived;
3494 stats.packetsReceived = packetsReceived;
3495
3496 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3497 VoEId(_instanceId, _channelId),
3498 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003499 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003500 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3501 stats.packetsReceived);
3502
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003503 // --- Timestamps
3504 {
3505 CriticalSectionScoped lock(ts_stats_lock_.get());
3506 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3507 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003508 return 0;
3509}
3510
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003511int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3512 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3513 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003514
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003515 if (enable) {
3516 if (redPayloadtype < 0 || redPayloadtype > 127) {
3517 _engineStatisticsPtr->SetLastError(
3518 VE_PLTYPE_ERROR, kTraceError,
3519 "SetFECStatus() invalid RED payload type");
3520 return -1;
3521 }
3522
3523 if (SetRedPayloadType(redPayloadtype) < 0) {
3524 _engineStatisticsPtr->SetLastError(
3525 VE_CODEC_ERROR, kTraceError,
3526 "SetSecondarySendCodec() Failed to register RED ACM");
3527 return -1;
3528 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003529 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003530
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003531 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003532 _engineStatisticsPtr->SetLastError(
3533 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3534 "SetFECStatus() failed to set FEC state in the ACM");
3535 return -1;
3536 }
3537 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003538}
3539
3540int
3541Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
3542{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003543 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003544 if (enabled)
3545 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003546 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003547 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003548 {
3549 _engineStatisticsPtr->SetLastError(
3550 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3551 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
3552 "module");
3553 return -1;
3554 }
3555 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3556 VoEId(_instanceId, _channelId),
3557 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
3558 enabled, redPayloadtype);
3559 return 0;
3560 }
3561 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3562 VoEId(_instanceId, _channelId),
3563 "GetFECStatus() => enabled=%d", enabled);
3564 return 0;
3565}
3566
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003567void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3568 // None of these functions can fail.
3569 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003570 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3571 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003572 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003573 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003574 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003575 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003576}
3577
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003578// Called when we are missing one or more packets.
3579int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003580 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3581}
3582
niklase@google.com470e71d2011-07-07 08:21:25 +00003583int
niklase@google.com470e71d2011-07-07 08:21:25 +00003584Channel::StartRTPDump(const char fileNameUTF8[1024],
3585 RTPDirections direction)
3586{
3587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3588 "Channel::StartRTPDump()");
3589 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3590 {
3591 _engineStatisticsPtr->SetLastError(
3592 VE_INVALID_ARGUMENT, kTraceError,
3593 "StartRTPDump() invalid RTP direction");
3594 return -1;
3595 }
3596 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3597 &_rtpDumpIn : &_rtpDumpOut;
3598 if (rtpDumpPtr == NULL)
3599 {
3600 assert(false);
3601 return -1;
3602 }
3603 if (rtpDumpPtr->IsActive())
3604 {
3605 rtpDumpPtr->Stop();
3606 }
3607 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3608 {
3609 _engineStatisticsPtr->SetLastError(
3610 VE_BAD_FILE, kTraceError,
3611 "StartRTPDump() failed to create file");
3612 return -1;
3613 }
3614 return 0;
3615}
3616
3617int
3618Channel::StopRTPDump(RTPDirections direction)
3619{
3620 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3621 "Channel::StopRTPDump()");
3622 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3623 {
3624 _engineStatisticsPtr->SetLastError(
3625 VE_INVALID_ARGUMENT, kTraceError,
3626 "StopRTPDump() invalid RTP direction");
3627 return -1;
3628 }
3629 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3630 &_rtpDumpIn : &_rtpDumpOut;
3631 if (rtpDumpPtr == NULL)
3632 {
3633 assert(false);
3634 return -1;
3635 }
3636 if (!rtpDumpPtr->IsActive())
3637 {
3638 return 0;
3639 }
3640 return rtpDumpPtr->Stop();
3641}
3642
3643bool
3644Channel::RTPDumpIsActive(RTPDirections direction)
3645{
3646 if ((direction != kRtpIncoming) &&
3647 (direction != kRtpOutgoing))
3648 {
3649 _engineStatisticsPtr->SetLastError(
3650 VE_INVALID_ARGUMENT, kTraceError,
3651 "RTPDumpIsActive() invalid RTP direction");
3652 return false;
3653 }
3654 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3655 &_rtpDumpIn : &_rtpDumpOut;
3656 return rtpDumpPtr->IsActive();
3657}
3658
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003659void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3660 int video_channel) {
3661 CriticalSectionScoped cs(&_callbackCritSect);
3662 if (vie_network_) {
3663 vie_network_->Release();
3664 vie_network_ = NULL;
3665 }
3666 video_channel_ = -1;
3667
3668 if (vie_network != NULL && video_channel != -1) {
3669 vie_network_ = vie_network;
3670 video_channel_ = video_channel;
3671 }
3672}
3673
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003674uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003675Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003676{
3677 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003678 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003679 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003680 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003681 return 0;
3682}
3683
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003684void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003685 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003686 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003687 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003688 CodecInst codec;
3689 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003690
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003691 if (!mono_recording_audio_.get()) {
3692 // Temporary space for DownConvertToCodecFormat.
3693 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003694 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003695 DownConvertToCodecFormat(audio_data,
3696 number_of_frames,
3697 number_of_channels,
3698 sample_rate,
3699 codec.channels,
3700 codec.plfreq,
3701 mono_recording_audio_.get(),
3702 &input_resampler_,
3703 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003704}
3705
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003706uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003707Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003708{
3709 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3710 "Channel::PrepareEncodeAndSend()");
3711
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003712 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003713 {
3714 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3715 "Channel::PrepareEncodeAndSend() invalid audio frame");
3716 return -1;
3717 }
3718
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003719 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003720 {
3721 MixOrReplaceAudioWithFile(mixingFrequency);
3722 }
3723
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003724 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3725 if (is_muted) {
3726 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003727 }
3728
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003729 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003730 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003731 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003732 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003733 if (_inputExternalMediaCallbackPtr)
3734 {
3735 _inputExternalMediaCallbackPtr->Process(
3736 _channelId,
3737 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003738 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003739 _audioFrame.samples_per_channel_,
3740 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003741 isStereo);
3742 }
3743 }
3744
3745 InsertInbandDtmfTone();
3746
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003747 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003748 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003749 if (is_muted) {
3750 rms_level_.ProcessMuted(length);
3751 } else {
3752 rms_level_.Process(_audioFrame.data_, length);
3753 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003754 }
3755
niklase@google.com470e71d2011-07-07 08:21:25 +00003756 return 0;
3757}
3758
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003759uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003760Channel::EncodeAndSend()
3761{
3762 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3763 "Channel::EncodeAndSend()");
3764
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003765 assert(_audioFrame.num_channels_ <= 2);
3766 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003767 {
3768 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3769 "Channel::EncodeAndSend() invalid audio frame");
3770 return -1;
3771 }
3772
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003773 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003774
3775 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3776
3777 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003778 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003779 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003780 {
3781 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3782 "Channel::EncodeAndSend() ACM encoding failed");
3783 return -1;
3784 }
3785
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003786 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003787
3788 // --- Encode if complete frame is ready
3789
3790 // This call will trigger AudioPacketizationCallback::SendData if encoding
3791 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003792 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003793}
3794
3795int Channel::RegisterExternalMediaProcessing(
3796 ProcessingTypes type,
3797 VoEMediaProcess& processObject)
3798{
3799 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3800 "Channel::RegisterExternalMediaProcessing()");
3801
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003802 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003803
3804 if (kPlaybackPerChannel == type)
3805 {
3806 if (_outputExternalMediaCallbackPtr)
3807 {
3808 _engineStatisticsPtr->SetLastError(
3809 VE_INVALID_OPERATION, kTraceError,
3810 "Channel::RegisterExternalMediaProcessing() "
3811 "output external media already enabled");
3812 return -1;
3813 }
3814 _outputExternalMediaCallbackPtr = &processObject;
3815 _outputExternalMedia = true;
3816 }
3817 else if (kRecordingPerChannel == type)
3818 {
3819 if (_inputExternalMediaCallbackPtr)
3820 {
3821 _engineStatisticsPtr->SetLastError(
3822 VE_INVALID_OPERATION, kTraceError,
3823 "Channel::RegisterExternalMediaProcessing() "
3824 "output external media already enabled");
3825 return -1;
3826 }
3827 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003828 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003829 }
3830 return 0;
3831}
3832
3833int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3834{
3835 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3836 "Channel::DeRegisterExternalMediaProcessing()");
3837
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003838 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003839
3840 if (kPlaybackPerChannel == type)
3841 {
3842 if (!_outputExternalMediaCallbackPtr)
3843 {
3844 _engineStatisticsPtr->SetLastError(
3845 VE_INVALID_OPERATION, kTraceWarning,
3846 "Channel::DeRegisterExternalMediaProcessing() "
3847 "output external media already disabled");
3848 return 0;
3849 }
3850 _outputExternalMedia = false;
3851 _outputExternalMediaCallbackPtr = NULL;
3852 }
3853 else if (kRecordingPerChannel == type)
3854 {
3855 if (!_inputExternalMediaCallbackPtr)
3856 {
3857 _engineStatisticsPtr->SetLastError(
3858 VE_INVALID_OPERATION, kTraceWarning,
3859 "Channel::DeRegisterExternalMediaProcessing() "
3860 "input external media already disabled");
3861 return 0;
3862 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003863 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003864 _inputExternalMediaCallbackPtr = NULL;
3865 }
3866
3867 return 0;
3868}
3869
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003870int Channel::SetExternalMixing(bool enabled) {
3871 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3872 "Channel::SetExternalMixing(enabled=%d)", enabled);
3873
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003874 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003875 {
3876 _engineStatisticsPtr->SetLastError(
3877 VE_INVALID_OPERATION, kTraceError,
3878 "Channel::SetExternalMixing() "
3879 "external mixing cannot be changed while playing.");
3880 return -1;
3881 }
3882
3883 _externalMixing = enabled;
3884
3885 return 0;
3886}
3887
niklase@google.com470e71d2011-07-07 08:21:25 +00003888int
niklase@google.com470e71d2011-07-07 08:21:25 +00003889Channel::GetNetworkStatistics(NetworkStatistics& stats)
3890{
3891 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3892 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003893 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003894 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003895 if (return_value >= 0) {
3896 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3897 }
3898 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003899}
3900
wu@webrtc.org24301a62013-12-13 19:17:43 +00003901void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3902 audio_coding_->GetDecodingCallStatistics(stats);
3903}
3904
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003905bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3906 int* playout_buffer_delay_ms) const {
3907 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003908 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003909 "Channel::GetDelayEstimate() no valid estimate.");
3910 return false;
3911 }
3912 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3913 _recPacketDelayMs;
3914 *playout_buffer_delay_ms = playout_delay_ms_;
3915 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3916 "Channel::GetDelayEstimate()");
3917 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003918}
3919
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003920int Channel::SetInitialPlayoutDelay(int delay_ms)
3921{
3922 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3923 "Channel::SetInitialPlayoutDelay()");
3924 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3925 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3926 {
3927 _engineStatisticsPtr->SetLastError(
3928 VE_INVALID_ARGUMENT, kTraceError,
3929 "SetInitialPlayoutDelay() invalid min delay");
3930 return -1;
3931 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003932 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003933 {
3934 _engineStatisticsPtr->SetLastError(
3935 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3936 "SetInitialPlayoutDelay() failed to set min playout delay");
3937 return -1;
3938 }
3939 return 0;
3940}
3941
3942
niklase@google.com470e71d2011-07-07 08:21:25 +00003943int
3944Channel::SetMinimumPlayoutDelay(int delayMs)
3945{
3946 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3947 "Channel::SetMinimumPlayoutDelay()");
3948 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3949 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3950 {
3951 _engineStatisticsPtr->SetLastError(
3952 VE_INVALID_ARGUMENT, kTraceError,
3953 "SetMinimumPlayoutDelay() invalid min delay");
3954 return -1;
3955 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003956 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003957 {
3958 _engineStatisticsPtr->SetLastError(
3959 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3960 "SetMinimumPlayoutDelay() failed to set min playout delay");
3961 return -1;
3962 }
3963 return 0;
3964}
3965
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3967 uint32_t playout_timestamp = 0;
3968
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003969 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003970 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3971 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3972 " timestamp from the ACM");
3973 _engineStatisticsPtr->SetLastError(
3974 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3975 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
3976 return;
3977 }
3978
3979 uint16_t delay_ms = 0;
3980 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3981 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3982 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3983 " delay from the ADM");
3984 _engineStatisticsPtr->SetLastError(
3985 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3986 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3987 return;
3988 }
3989
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003990 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003991 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003992 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003993 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3994 playout_frequency = 8000;
3995 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3996 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00003997 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003998 }
3999
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004000 jitter_buffer_playout_timestamp_ = playout_timestamp;
4001
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004002 // Remove the playout delay.
4003 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4004
4005 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4006 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4007 playout_timestamp);
4008
4009 if (rtcp) {
4010 playout_timestamp_rtcp_ = playout_timestamp;
4011 } else {
4012 playout_timestamp_rtp_ = playout_timestamp;
4013 }
4014 playout_delay_ms_ = delay_ms;
4015}
4016
4017int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4018 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4019 "Channel::GetPlayoutTimestamp()");
4020 if (playout_timestamp_rtp_ == 0) {
4021 _engineStatisticsPtr->SetLastError(
4022 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4023 "GetPlayoutTimestamp() failed to retrieve timestamp");
4024 return -1;
4025 }
4026 timestamp = playout_timestamp_rtp_;
4027 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4028 VoEId(_instanceId,_channelId),
4029 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4030 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004031}
4032
4033int
4034Channel::SetInitTimestamp(unsigned int timestamp)
4035{
4036 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4037 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004038 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004039 {
4040 _engineStatisticsPtr->SetLastError(
4041 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4042 return -1;
4043 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004044 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004045 {
4046 _engineStatisticsPtr->SetLastError(
4047 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4048 "SetInitTimestamp() failed to set timestamp");
4049 return -1;
4050 }
4051 return 0;
4052}
4053
4054int
4055Channel::SetInitSequenceNumber(short sequenceNumber)
4056{
4057 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4058 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004059 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004060 {
4061 _engineStatisticsPtr->SetLastError(
4062 VE_SENDING, kTraceError,
4063 "SetInitSequenceNumber() already sending");
4064 return -1;
4065 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004066 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004067 {
4068 _engineStatisticsPtr->SetLastError(
4069 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4070 "SetInitSequenceNumber() failed to set sequence number");
4071 return -1;
4072 }
4073 return 0;
4074}
4075
4076int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004077Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004078{
4079 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4080 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004081 *rtpRtcpModule = _rtpRtcpModule.get();
4082 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004083 return 0;
4084}
4085
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004086// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4087// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004088int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004089Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004090{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004091 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004092 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004093
4094 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004095 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004096
4097 if (_inputFilePlayerPtr == NULL)
4098 {
4099 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4100 VoEId(_instanceId, _channelId),
4101 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4102 " doesnt exist");
4103 return -1;
4104 }
4105
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004106 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004107 fileSamples,
4108 mixingFrequency) == -1)
4109 {
4110 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4111 VoEId(_instanceId, _channelId),
4112 "Channel::MixOrReplaceAudioWithFile() file mixing "
4113 "failed");
4114 return -1;
4115 }
4116 if (fileSamples == 0)
4117 {
4118 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4119 VoEId(_instanceId, _channelId),
4120 "Channel::MixOrReplaceAudioWithFile() file is ended");
4121 return 0;
4122 }
4123 }
4124
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004125 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004126
4127 if (_mixFileWithMicrophone)
4128 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004129 // Currently file stream is always mono.
4130 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004131 MixWithSat(_audioFrame.data_,
4132 _audioFrame.num_channels_,
4133 fileBuffer.get(),
4134 1,
4135 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004136 }
4137 else
4138 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004139 // Replace ACM audio with file.
4140 // Currently file stream is always mono.
4141 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004142 _audioFrame.UpdateFrame(_channelId,
4143 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004144 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004145 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004146 mixingFrequency,
4147 AudioFrame::kNormalSpeech,
4148 AudioFrame::kVadUnknown,
4149 1);
4150
4151 }
4152 return 0;
4153}
4154
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004155int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004156Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004157 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004158{
4159 assert(mixingFrequency <= 32000);
4160
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004161 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004162 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004163
4164 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004165 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004166
4167 if (_outputFilePlayerPtr == NULL)
4168 {
4169 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4170 VoEId(_instanceId, _channelId),
4171 "Channel::MixAudioWithFile() file mixing failed");
4172 return -1;
4173 }
4174
4175 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004176 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004177 fileSamples,
4178 mixingFrequency) == -1)
4179 {
4180 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4181 VoEId(_instanceId, _channelId),
4182 "Channel::MixAudioWithFile() file mixing failed");
4183 return -1;
4184 }
4185 }
4186
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004187 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004188 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004189 // Currently file stream is always mono.
4190 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004191 MixWithSat(audioFrame.data_,
4192 audioFrame.num_channels_,
4193 fileBuffer.get(),
4194 1,
4195 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004196 }
4197 else
4198 {
4199 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004200 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004201 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004202 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004203 return -1;
4204 }
4205
4206 return 0;
4207}
4208
4209int
4210Channel::InsertInbandDtmfTone()
4211{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004212 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004213 if (_inbandDtmfQueue.PendingDtmf() &&
4214 !_inbandDtmfGenerator.IsAddingTone() &&
4215 _inbandDtmfGenerator.DelaySinceLastTone() >
4216 kMinTelephoneEventSeparationMs)
4217 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004218 int8_t eventCode(0);
4219 uint16_t lengthMs(0);
4220 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004221
4222 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4223 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4224 if (_playInbandDtmfEvent)
4225 {
4226 // Add tone to output mixer using a reduced length to minimize
4227 // risk of echo.
4228 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4229 attenuationDb);
4230 }
4231 }
4232
4233 if (_inbandDtmfGenerator.IsAddingTone())
4234 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004235 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004236 _inbandDtmfGenerator.GetSampleRate(frequency);
4237
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004238 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004239 {
4240 // Update sample rate of Dtmf tone since the mixing frequency
4241 // has changed.
4242 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004243 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004244 // Reset the tone to be added taking the new sample rate into
4245 // account.
4246 _inbandDtmfGenerator.ResetTone();
4247 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004248
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004249 int16_t toneBuffer[320];
4250 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004251 // Get 10ms tone segment and set time since last tone to zero
4252 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4253 {
4254 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4255 VoEId(_instanceId, _channelId),
4256 "Channel::EncodeAndSend() inserting Dtmf failed");
4257 return -1;
4258 }
4259
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004260 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004261 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004262 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004263 sample++)
4264 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004265 for (int channel = 0;
4266 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004267 channel++)
4268 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004269 const int index = sample * _audioFrame.num_channels_ + channel;
4270 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004271 }
4272 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004273
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004274 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004275 } else
4276 {
4277 // Add 10ms to "delay-since-last-tone" counter
4278 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4279 }
4280 return 0;
4281}
4282
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004283int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004284Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4285{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004286 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004287 if (_transportPtr == NULL)
4288 {
4289 return -1;
4290 }
4291 if (!RTCP)
4292 {
4293 return _transportPtr->SendPacket(_channelId, data, len);
4294 }
4295 else
4296 {
4297 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4298 }
4299}
4300
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004301// Called for incoming RTP packets after successful RTP header parsing.
4302void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4303 uint16_t sequence_number) {
4304 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4305 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4306 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004307
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004308 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004309 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004310
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004311 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004312 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004313 return;
4314 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004315
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004316 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004317 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004318
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004319 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4320 // Even though the actual sampling rate for G.722 audio is
4321 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4322 // 8,000 Hz because that value was erroneously assigned in
4323 // RFC 1890 and must remain unchanged for backward compatibility.
4324 rtp_receive_frequency = 8000;
4325 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4326 // We are resampling Opus internally to 32,000 Hz until all our
4327 // DSP routines can operate at 48,000 Hz, but the RTP clock
4328 // rate for the Opus payload format is standardized to 48,000 Hz,
4329 // because that is the maximum supported decoding sampling rate.
4330 rtp_receive_frequency = 48000;
4331 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004332
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004333 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4334 // every incoming packet.
4335 uint32_t timestamp_diff_ms = (rtp_timestamp -
4336 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004337 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4338 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4339 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4340 // timestamp, the resulting difference is negative, but is set to zero.
4341 // This can happen when a network glitch causes a packet to arrive late,
4342 // and during long comfort noise periods with clock drift.
4343 timestamp_diff_ms = 0;
4344 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004345
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004346 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4347 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004348
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004349 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004350
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004351 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004352
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004353 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4354 _recPacketDelayMs = packet_delay_ms;
4355 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004356
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004357 if (_average_jitter_buffer_delay_us == 0) {
4358 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4359 return;
4360 }
4361
4362 // Filter average delay value using exponential filter (alpha is
4363 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4364 // risk of rounding error) and compensate for it in GetDelayEstimate()
4365 // later.
4366 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4367 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004368}
4369
4370void
4371Channel::RegisterReceiveCodecsToRTPModule()
4372{
4373 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4374 "Channel::RegisterReceiveCodecsToRTPModule()");
4375
4376
4377 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004378 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004379
4380 for (int idx = 0; idx < nSupportedCodecs; idx++)
4381 {
4382 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004383 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004384 (rtp_receiver_->RegisterReceivePayload(
4385 codec.plname,
4386 codec.pltype,
4387 codec.plfreq,
4388 codec.channels,
4389 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004390 {
4391 WEBRTC_TRACE(
4392 kTraceWarning,
4393 kTraceVoice,
4394 VoEId(_instanceId, _channelId),
4395 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4396 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4397 codec.plname, codec.pltype, codec.plfreq,
4398 codec.channels, codec.rate);
4399 }
4400 else
4401 {
4402 WEBRTC_TRACE(
4403 kTraceInfo,
4404 kTraceVoice,
4405 VoEId(_instanceId, _channelId),
4406 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004407 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004408 "receiver",
4409 codec.plname, codec.pltype, codec.plfreq,
4410 codec.channels, codec.rate);
4411 }
4412 }
4413}
4414
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004415int Channel::SetSecondarySendCodec(const CodecInst& codec,
4416 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004417 // Sanity check for payload type.
4418 if (red_payload_type < 0 || red_payload_type > 127) {
4419 _engineStatisticsPtr->SetLastError(
4420 VE_PLTYPE_ERROR, kTraceError,
4421 "SetRedPayloadType() invalid RED payload type");
4422 return -1;
4423 }
4424
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004425 if (SetRedPayloadType(red_payload_type) < 0) {
4426 _engineStatisticsPtr->SetLastError(
4427 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4428 "SetSecondarySendCodec() Failed to register RED ACM");
4429 return -1;
4430 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004431 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004432 _engineStatisticsPtr->SetLastError(
4433 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4434 "SetSecondarySendCodec() Failed to register secondary send codec in "
4435 "ACM");
4436 return -1;
4437 }
4438
4439 return 0;
4440}
4441
4442void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004443 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004444}
4445
4446int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004447 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004448 _engineStatisticsPtr->SetLastError(
4449 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4450 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4451 return -1;
4452 }
4453 return 0;
4454}
4455
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004456// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004457int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004458 CodecInst codec;
4459 bool found_red = false;
4460
4461 // Get default RED settings from the ACM database
4462 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4463 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004464 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004465 if (!STR_CASE_CMP(codec.plname, "RED")) {
4466 found_red = true;
4467 break;
4468 }
4469 }
4470
4471 if (!found_red) {
4472 _engineStatisticsPtr->SetLastError(
4473 VE_CODEC_ERROR, kTraceError,
4474 "SetRedPayloadType() RED is not supported");
4475 return -1;
4476 }
4477
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004478 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004479 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004480 _engineStatisticsPtr->SetLastError(
4481 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4482 "SetRedPayloadType() RED registration in ACM module failed");
4483 return -1;
4484 }
4485
4486 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4487 _engineStatisticsPtr->SetLastError(
4488 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4489 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4490 return -1;
4491 }
4492 return 0;
4493}
4494
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004495int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4496 unsigned char id) {
4497 int error = 0;
4498 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4499 if (enable) {
4500 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4501 }
4502 return error;
4503}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004504} // namespace voe
4505} // namespace webrtc