blob: 365d4cadeb2e8a6ddeb2d7159b8e35c35bb7bb04 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +000016#include "webrtc/modules/interface/module_common_types.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000017#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
19#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
20#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000021#include "webrtc/modules/utility/interface/audio_frame_operations.h"
22#include "webrtc/modules/utility/interface/process_thread.h"
23#include "webrtc/modules/utility/interface/rtp_dump.h"
24#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
25#include "webrtc/system_wrappers/interface/logging.h"
26#include "webrtc/system_wrappers/interface/trace.h"
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +000027#include "webrtc/video_engine/include/vie_network.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000028#include "webrtc/voice_engine/include/voe_base.h"
29#include "webrtc/voice_engine/include/voe_external_media.h"
30#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
31#include "webrtc/voice_engine/output_mixer.h"
32#include "webrtc/voice_engine/statistics.h"
33#include "webrtc/voice_engine/transmit_mixer.h"
34#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000035
36#if defined(_WIN32)
37#include <Qos.h>
38#endif
39
andrew@webrtc.org50419b02012-11-14 19:07:54 +000040namespace webrtc {
41namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000042
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000043// Extend the default RTCP statistics struct with max_jitter, defined as the
44// maximum jitter value seen in an RTCP report block.
45struct ChannelStatistics : public RtcpStatistics {
46 ChannelStatistics() : rtcp(), max_jitter(0) {}
47
48 RtcpStatistics rtcp;
49 uint32_t max_jitter;
50};
51
52// Statistics callback, called at each generation of a new RTCP report block.
53class StatisticsProxy : public RtcpStatisticsCallback {
54 public:
55 StatisticsProxy(uint32_t ssrc)
56 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
57 ssrc_(ssrc) {}
58 virtual ~StatisticsProxy() {}
59
60 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
61 uint32_t ssrc) OVERRIDE {
62 if (ssrc != ssrc_)
63 return;
64
65 CriticalSectionScoped cs(stats_lock_.get());
66 stats_.rtcp = statistics;
67 if (statistics.jitter > stats_.max_jitter) {
68 stats_.max_jitter = statistics.jitter;
69 }
70 }
71
72 void ResetStatistics() {
73 CriticalSectionScoped cs(stats_lock_.get());
74 stats_ = ChannelStatistics();
75 }
76
77 ChannelStatistics GetStats() {
78 CriticalSectionScoped cs(stats_lock_.get());
79 return stats_;
80 }
81
82 private:
83 // StatisticsUpdated calls are triggered from threads in the RTP module,
84 // while GetStats calls can be triggered from the public voice engine API,
85 // hence synchronization is needed.
86 scoped_ptr<CriticalSectionWrapper> stats_lock_;
87 const uint32_t ssrc_;
88 ChannelStatistics stats_;
89};
90
pbos@webrtc.org6141e132013-04-09 10:09:10 +000091int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000092Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000093 uint8_t payloadType,
94 uint32_t timeStamp,
95 const uint8_t* payloadData,
96 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000097 const RTPFragmentationHeader* fragmentation)
98{
99 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
100 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
101 " payloadSize=%u, fragmentation=0x%x)",
102 frameType, payloadType, timeStamp, payloadSize, fragmentation);
103
104 if (_includeAudioLevelIndication)
105 {
106 // Store current audio level in the RTP/RTCP module.
107 // The level will be used in combination with voice-activity state
108 // (frameType) to add an RTP header extension
andrew@webrtc.org382c0c22014-05-05 18:22:21 +0000109 _rtpRtcpModule->SetAudioLevel(rms_level_.RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000110 }
111
112 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
113 // packetization.
114 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000115 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000116 payloadType,
117 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000118 // Leaving the time when this frame was
119 // received from the capture device as
120 // undefined for voice for now.
121 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000122 payloadData,
123 payloadSize,
124 fragmentation) == -1)
125 {
126 _engineStatisticsPtr->SetLastError(
127 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
128 "Channel::SendData() failed to send data to RTP/RTCP module");
129 return -1;
130 }
131
132 _lastLocalTimeStamp = timeStamp;
133 _lastPayloadType = payloadType;
134
135 return 0;
136}
137
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000138int32_t
139Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000140{
141 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
142 "Channel::InFrameType(frameType=%d)", frameType);
143
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000144 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 // 1 indicates speech
146 _sendFrameType = (frameType == 1) ? 1 : 0;
147 return 0;
148}
149
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000150int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000151Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000152{
153 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
154 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
155
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000156 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 if (_rxVadObserverPtr)
158 {
159 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
160 }
161
162 return 0;
163}
164
165int
166Channel::SendPacket(int channel, const void *data, int len)
167{
168 channel = VoEChannelId(channel);
169 assert(channel == _channelId);
170
171 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
172 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
173
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000174 CriticalSectionScoped cs(&_callbackCritSect);
175
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 if (_transportPtr == NULL)
177 {
178 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
179 "Channel::SendPacket() failed to send RTP packet due to"
180 " invalid transport object");
181 return -1;
182 }
183
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000184 uint8_t* bufferToSendPtr = (uint8_t*)data;
185 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000186
187 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000188 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000189 {
190 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
191 VoEId(_instanceId,_channelId),
192 "Channel::SendPacket() RTP dump to output file failed");
193 }
194
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000195 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
196 bufferLength);
197 if (n < 0) {
198 std::string transport_name =
199 _externalTransport ? "external transport" : "WebRtc sockets";
200 WEBRTC_TRACE(kTraceError, kTraceVoice,
201 VoEId(_instanceId,_channelId),
202 "Channel::SendPacket() RTP transmission using %s failed",
203 transport_name.c_str());
204 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000206 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000207}
208
209int
210Channel::SendRTCPPacket(int channel, const void *data, int len)
211{
212 channel = VoEChannelId(channel);
213 assert(channel == _channelId);
214
215 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
216 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
217
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000218 CriticalSectionScoped cs(&_callbackCritSect);
219 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000221 WEBRTC_TRACE(kTraceError, kTraceVoice,
222 VoEId(_instanceId,_channelId),
223 "Channel::SendRTCPPacket() failed to send RTCP packet"
224 " due to invalid transport object");
225 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000226 }
227
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000228 uint8_t* bufferToSendPtr = (uint8_t*)data;
229 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
231 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000232 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 {
234 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
235 VoEId(_instanceId,_channelId),
236 "Channel::SendPacket() RTCP dump to output file failed");
237 }
238
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000239 int n = _transportPtr->SendRTCPPacket(channel,
240 bufferToSendPtr,
241 bufferLength);
242 if (n < 0) {
243 std::string transport_name =
244 _externalTransport ? "external transport" : "WebRtc sockets";
245 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
246 VoEId(_instanceId,_channelId),
247 "Channel::SendRTCPPacket() transmission using %s failed",
248 transport_name.c_str());
249 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000250 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000251 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252}
253
254void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000255Channel::OnPlayTelephoneEvent(int32_t id,
256 uint8_t event,
257 uint16_t lengthMs,
258 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000259{
260 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
261 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000262 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000263
264 if (!_playOutbandDtmfEvent || (event > 15))
265 {
266 // Ignore callback since feedback is disabled or event is not a
267 // Dtmf tone event.
268 return;
269 }
270
271 assert(_outputMixerPtr != NULL);
272
273 // Start playing out the Dtmf tone (if playout is enabled).
274 // Reduce length of tone with 80ms to the reduce risk of echo.
275 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
276}
277
278void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000279Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000280{
281 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
282 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000283 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000284
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000285 // Update ssrc so that NTP for AV sync can be updated.
286 _rtpRtcpModule->SetRemoteSSRC(ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000287}
288
pbos@webrtc.org92135212013-05-14 08:31:39 +0000289void Channel::OnIncomingCSRCChanged(int32_t id,
290 uint32_t CSRC,
291 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000292{
293 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
294 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
295 id, CSRC, added);
niklase@google.com470e71d2011-07-07 08:21:25 +0000296}
297
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000298void Channel::ResetStatistics(uint32_t ssrc) {
299 StreamStatistician* statistician =
300 rtp_receive_statistics_->GetStatistician(ssrc);
301 if (statistician) {
302 statistician->ResetStatistics();
303 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000304 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000305}
306
niklase@google.com470e71d2011-07-07 08:21:25 +0000307void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000308Channel::OnApplicationDataReceived(int32_t id,
309 uint8_t subType,
310 uint32_t name,
311 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000312 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000313{
314 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
315 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
316 " name=%u, length=%u)",
317 id, subType, name, length);
318
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000319 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000320 assert(channel == _channelId);
321
322 if (_rtcpObserver)
323 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000324 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000325
326 if (_rtcpObserverPtr)
327 {
328 _rtcpObserverPtr->OnApplicationDataReceived(channel,
329 subType,
330 name,
331 data,
332 length);
333 }
334 }
335}
336
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000337int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000338Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000339 int32_t id,
340 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000341 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000342 int frequency,
343 uint8_t channels,
344 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000345{
346 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
347 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
348 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
349 id, payloadType, payloadName, frequency, channels, rate);
350
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000351 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000352
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000353 CodecInst receiveCodec = {0};
354 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000355
356 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000357 receiveCodec.plfreq = frequency;
358 receiveCodec.channels = channels;
359 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000360 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000361
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000362 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000363 receiveCodec.pacsize = dummyCodec.pacsize;
364
365 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000366 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 {
368 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000369 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 "Channel::OnInitializeDecoder() invalid codec ("
371 "pt=%d, name=%s) received - 1", payloadType, payloadName);
372 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
373 return -1;
374 }
375
376 return 0;
377}
378
379void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000380Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000381{
382 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
383 "Channel::OnPacketTimeout(id=%d)", id);
384
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000385 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000386 if (_voiceEngineObserverPtr)
387 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000388 if (channel_state_.Get().receiving || _externalTransport)
niklase@google.com470e71d2011-07-07 08:21:25 +0000389 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000390 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000391 assert(channel == _channelId);
392 // Ensure that next OnReceivedPacket() callback will trigger
393 // a VE_PACKET_RECEIPT_RESTARTED callback.
394 _rtpPacketTimedOut = true;
395 // Deliver callback to the observer
396 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
397 VoEId(_instanceId,_channelId),
398 "Channel::OnPacketTimeout() => "
399 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
400 _voiceEngineObserverPtr->CallbackOnError(channel,
401 VE_RECEIVE_PACKET_TIMEOUT);
402 }
403 }
404}
405
406void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000407Channel::OnReceivedPacket(int32_t id,
408 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000409{
410 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
411 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
412 id, packetType);
413
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000414 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
416 // Notify only for the case when we have restarted an RTP session.
417 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
418 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000419 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000420 if (_voiceEngineObserverPtr)
421 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000422 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000423 assert(channel == _channelId);
424 // Reset timeout mechanism
425 _rtpPacketTimedOut = false;
426 // Deliver callback to the observer
427 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
428 VoEId(_instanceId,_channelId),
429 "Channel::OnPacketTimeout() =>"
430 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
431 _voiceEngineObserverPtr->CallbackOnError(
432 channel,
433 VE_PACKET_RECEIPT_RESTARTED);
434 }
435 }
436}
437
438void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000439Channel::OnPeriodicDeadOrAlive(int32_t id,
440 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000441{
442 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
443 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
444
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000445 {
446 CriticalSectionScoped cs(&_callbackCritSect);
447 if (!_connectionObserver)
448 return;
449 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000450
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000451 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000452 assert(channel == _channelId);
453
454 // Use Alive as default to limit risk of false Dead detections
455 bool isAlive(true);
456
457 // Always mark the connection as Dead when the module reports kRtpDead
458 if (kRtpDead == alive)
459 {
460 isAlive = false;
461 }
462
463 // It is possible that the connection is alive even if no RTP packet has
464 // been received for a long time since the other side might use VAD/DTX
465 // and a low SID-packet update rate.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000466 if ((kRtpNoRtp == alive) && channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 {
468 // Detect Alive for all NetEQ states except for the case when we are
469 // in PLC_CNG state.
470 // PLC_CNG <=> background noise only due to long expand or error.
471 // Note that, the case where the other side stops sending during CNG
472 // state will be detected as Alive. Dead is is not set until after
473 // missing RTCP packets for at least twelve seconds (handled
474 // internally by the RTP/RTCP module).
475 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
476 }
477
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 // Send callback to the registered observer
479 if (_connectionObserver)
480 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000481 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000482 if (_connectionObserverPtr)
483 {
484 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
485 }
486 }
487}
488
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000489int32_t
490Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000491 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 const WebRtcRTPHeader* rtpHeader)
493{
494 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
495 "Channel::OnReceivedPayloadData(payloadSize=%d,"
496 " payloadType=%u, audioChannel=%u)",
497 payloadSize,
498 rtpHeader->header.payloadType,
499 rtpHeader->type.Audio.channel);
500
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000501 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000502 {
503 // Avoid inserting into NetEQ when we are not playing. Count the
504 // packet as discarded.
505 WEBRTC_TRACE(kTraceStream, kTraceVoice,
506 VoEId(_instanceId, _channelId),
507 "received packet is discarded since playing is not"
508 " activated");
509 _numberOfDiscardedPackets++;
510 return 0;
511 }
512
513 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000514 if (audio_coding_->IncomingPacket(payloadData,
515 payloadSize,
516 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000517 {
518 _engineStatisticsPtr->SetLastError(
519 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
520 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
521 return -1;
522 }
523
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000524 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 UpdatePacketDelay(rtpHeader->header.timestamp,
526 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000527
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000528 uint16_t round_trip_time = 0;
529 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
530 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000531
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000532 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000533 round_trip_time);
534 if (!nack_list.empty()) {
535 // Can't use nack_list.data() since it's not supported by all
536 // compilers.
537 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000538 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 return 0;
540}
541
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000542bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
543 int rtp_packet_length) {
544 RTPHeader header;
545 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
546 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
547 "IncomingPacket invalid RTP header");
548 return false;
549 }
550 header.payload_type_frequency =
551 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
552 if (header.payload_type_frequency < 0)
553 return false;
554 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
555}
556
pbos@webrtc.org92135212013-05-14 08:31:39 +0000557int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000558{
559 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
560 "Channel::GetAudioFrame(id=%d)", id);
561
562 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000563 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
564 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 {
566 WEBRTC_TRACE(kTraceError, kTraceVoice,
567 VoEId(_instanceId,_channelId),
568 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000569 // In all likelihood, the audio in this frame is garbage. We return an
570 // error so that the audio mixer module doesn't add it to the mix. As
571 // a result, it won't be played out and the actions skipped here are
572 // irrelevant.
573 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000574 }
575
576 if (_RxVadDetection)
577 {
578 UpdateRxVadDetection(audioFrame);
579 }
580
581 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000582 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000584 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000585
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000586 ChannelState::State state = channel_state_.Get();
587
588 if (state.rx_apm_is_enabled) {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000589 int err = rx_audioproc_->ProcessStream(&audioFrame);
590 if (err) {
591 LOG(LS_ERROR) << "ProcessStream() error: " << err;
592 assert(false);
593 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000594 }
595
wu@webrtc.org63420662013-10-17 18:28:55 +0000596 float output_gain = 1.0f;
597 float left_pan = 1.0f;
598 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000599 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000600 CriticalSectionScoped cs(&volume_settings_critsect_);
601 output_gain = _outputGain;
602 left_pan = _panLeft;
603 right_pan= _panRight;
604 }
605
606 // Output volume scaling
607 if (output_gain < 0.99f || output_gain > 1.01f)
608 {
609 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000610 }
611
612 // Scale left and/or right channel(s) if stereo and master balance is
613 // active
614
wu@webrtc.org63420662013-10-17 18:28:55 +0000615 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000617 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 {
619 // Emulate stereo mode since panning is active.
620 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000621 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000622 }
623 // For true stereo mode (when we are receiving a stereo signal), no
624 // action is needed.
625
626 // Do the panning operation (the audio frame contains stereo at this
627 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000628 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 }
630
631 // Mix decoded PCM output with file if file mixing is enabled
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000632 if (state.output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000634 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 }
636
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 // External media
638 if (_outputExternalMedia)
639 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000640 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000641 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 if (_outputExternalMediaCallbackPtr)
643 {
644 _outputExternalMediaCallbackPtr->Process(
645 _channelId,
646 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000647 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000648 audioFrame.samples_per_channel_,
649 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000650 isStereo);
651 }
652 }
653
654 // Record playout if enabled
655 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000656 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000657
658 if (_outputFileRecording && _outputFileRecorderPtr)
659 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000660 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 }
662 }
663
664 // Measure audio level (0-9)
665 _outputAudioLevel.ComputeLevel(audioFrame);
666
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000667 // TODO(wu): Calculate capture NTP time based on RTP timestamp and RTCP SR.
668 audioFrame.ntp_time_ms_ = 0;
669
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),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000852 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000853 playout_timestamp_rtp_(0),
854 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000855 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000856 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000857 send_sequence_number_(0),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000858 ts_stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
859 first_frame_arrived_(false),
860 capture_start_rtp_time_stamp_(0),
861 capture_start_ntp_time_ms_(-1),
xians@google.com22963ab2011-08-03 12:40:23 +0000862 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000863 _outputMixerPtr(NULL),
864 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000865 _moduleProcessThreadPtr(NULL),
866 _audioDeviceModulePtr(NULL),
867 _voiceEngineObserverPtr(NULL),
868 _callbackCritSectPtr(NULL),
869 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000870 _rxVadObserverPtr(NULL),
871 _oldVadDecision(-1),
872 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000873 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000874 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000875 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000876 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000877 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000878 _mute(false),
879 _panLeft(1.0f),
880 _panRight(1.0f),
881 _outputGain(1.0f),
882 _playOutbandDtmfEvent(false),
883 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 _lastLocalTimeStamp(0),
885 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000886 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000887 _rtpPacketTimedOut(false),
888 _rtpPacketTimeOutIsEnabled(false),
889 _rtpTimeOutSeconds(0),
890 _connectionObserver(false),
891 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000892 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000893 vie_network_(NULL),
894 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000895 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000896 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000897 _previousTimestamp(0),
898 _recPacketDelayMs(20),
899 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000900 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000901 _rxNsIsEnabled(false),
902 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000903{
904 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
905 "Channel::Channel() - ctor");
906 _inbandDtmfQueue.ResetDtmf();
907 _inbandDtmfGenerator.Init();
908 _outputAudioLevel.Clear();
909
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000910 RtpRtcp::Configuration configuration;
911 configuration.id = VoEModuleId(instanceId, channelId);
912 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000913 configuration.outgoing_transport = this;
914 configuration.rtcp_feedback = this;
915 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000916 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000917
918 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000919
920 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
921 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
922 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000923
924 Config audioproc_config;
925 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
926 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000927}
928
929Channel::~Channel()
930{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000931 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
933 "Channel::~Channel() - dtor");
934
935 if (_outputExternalMedia)
936 {
937 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
938 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000939 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 {
941 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
942 }
943 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000944 StopPlayout();
945
946 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000947 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 if (_inputFilePlayerPtr)
949 {
950 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
951 _inputFilePlayerPtr->StopPlayingFile();
952 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
953 _inputFilePlayerPtr = NULL;
954 }
955 if (_outputFilePlayerPtr)
956 {
957 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
958 _outputFilePlayerPtr->StopPlayingFile();
959 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
960 _outputFilePlayerPtr = NULL;
961 }
962 if (_outputFileRecorderPtr)
963 {
964 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
965 _outputFileRecorderPtr->StopRecording();
966 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
967 _outputFileRecorderPtr = NULL;
968 }
969 }
970
971 // The order to safely shutdown modules in a channel is:
972 // 1. De-register callbacks in modules
973 // 2. De-register modules in process thread
974 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000975 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000976 {
977 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
978 VoEId(_instanceId,_channelId),
979 "~Channel() failed to de-register transport callback"
980 " (Audio coding module)");
981 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000982 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 {
984 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
985 VoEId(_instanceId,_channelId),
986 "~Channel() failed to de-register VAD callback"
987 " (Audio coding module)");
988 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000989 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000990 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000991 {
992 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
993 VoEId(_instanceId,_channelId),
994 "~Channel() failed to deregister RTP/RTCP module");
995 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 // End of modules shutdown
997
998 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000999 if (vie_network_) {
1000 vie_network_->Release();
1001 vie_network_ = NULL;
1002 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1004 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001006 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001007 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001008}
1009
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001010int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001011Channel::Init()
1012{
1013 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1014 "Channel::Init()");
1015
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001016 channel_state_.Reset();
1017
niklase@google.com470e71d2011-07-07 08:21:25 +00001018 // --- Initial sanity
1019
1020 if ((_engineStatisticsPtr == NULL) ||
1021 (_moduleProcessThreadPtr == NULL))
1022 {
1023 WEBRTC_TRACE(kTraceError, kTraceVoice,
1024 VoEId(_instanceId,_channelId),
1025 "Channel::Init() must call SetEngineInformation() first");
1026 return -1;
1027 }
1028
1029 // --- Add modules to process thread (for periodic schedulation)
1030
1031 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001032 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001033 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001034 if (processThreadFail)
1035 {
1036 _engineStatisticsPtr->SetLastError(
1037 VE_CANNOT_INIT_CHANNEL, kTraceError,
1038 "Channel::Init() modules not registered");
1039 return -1;
1040 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001041 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001042
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001043 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001044#ifdef WEBRTC_CODEC_AVT
1045 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001046 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001047#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001048 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001049 {
1050 _engineStatisticsPtr->SetLastError(
1051 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1052 "Channel::Init() unable to initialize the ACM - 1");
1053 return -1;
1054 }
1055
1056 // --- RTP/RTCP module initialization
1057
1058 // Ensure that RTCP is enabled by default for the created channel.
1059 // Note that, the module will keep generating RTCP until it is explicitly
1060 // disabled by the user.
1061 // After StopListen (when no sockets exists), RTCP packets will no longer
1062 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001063 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1064 // RTCP is enabled by default.
1065 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001066 {
1067 _engineStatisticsPtr->SetLastError(
1068 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1069 "Channel::Init() RTP/RTCP module not initialized");
1070 return -1;
1071 }
1072
1073 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001075 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1076 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001077
1078 if (fail)
1079 {
1080 _engineStatisticsPtr->SetLastError(
1081 VE_CANNOT_INIT_CHANNEL, kTraceError,
1082 "Channel::Init() callbacks not registered");
1083 return -1;
1084 }
1085
1086 // --- Register all supported codecs to the receiving side of the
1087 // RTP/RTCP module
1088
1089 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001090 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001091
1092 for (int idx = 0; idx < nSupportedCodecs; idx++)
1093 {
1094 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001095 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001096 (rtp_receiver_->RegisterReceivePayload(
1097 codec.plname,
1098 codec.pltype,
1099 codec.plfreq,
1100 codec.channels,
1101 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001102 {
1103 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1104 VoEId(_instanceId,_channelId),
1105 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1106 "to RTP/RTCP receiver",
1107 codec.plname, codec.pltype, codec.plfreq,
1108 codec.channels, codec.rate);
1109 }
1110 else
1111 {
1112 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1113 VoEId(_instanceId,_channelId),
1114 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1115 "the RTP/RTCP receiver",
1116 codec.plname, codec.pltype, codec.plfreq,
1117 codec.channels, codec.rate);
1118 }
1119
1120 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001121 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
1123 SetSendCodec(codec);
1124 }
1125
1126 // Register default PT for outband 'telephone-event'
1127 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1128 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001129 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001130 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 {
1132 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1133 VoEId(_instanceId,_channelId),
1134 "Channel::Init() failed to register outband "
1135 "'telephone-event' (%d/%d) correctly",
1136 codec.pltype, codec.plfreq);
1137 }
1138 }
1139
1140 if (!STR_CASE_CMP(codec.plname, "CN"))
1141 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001142 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1143 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001144 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 {
1146 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1147 VoEId(_instanceId,_channelId),
1148 "Channel::Init() failed to register CN (%d/%d) "
1149 "correctly - 1",
1150 codec.pltype, codec.plfreq);
1151 }
1152 }
1153#ifdef WEBRTC_CODEC_RED
1154 // Register RED to the receiving side of the ACM.
1155 // We will not receive an OnInitializeDecoder() callback for RED.
1156 if (!STR_CASE_CMP(codec.plname, "RED"))
1157 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001158 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001159 {
1160 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1161 VoEId(_instanceId,_channelId),
1162 "Channel::Init() failed to register RED (%d/%d) "
1163 "correctly",
1164 codec.pltype, codec.plfreq);
1165 }
1166 }
1167#endif
1168 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001169
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001170 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1171 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1172 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001173 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001174 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1175 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1176 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001177 }
1178
1179 return 0;
1180}
1181
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001182int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001183Channel::SetEngineInformation(Statistics& engineStatistics,
1184 OutputMixer& outputMixer,
1185 voe::TransmitMixer& transmitMixer,
1186 ProcessThread& moduleProcessThread,
1187 AudioDeviceModule& audioDeviceModule,
1188 VoiceEngineObserver* voiceEngineObserver,
1189 CriticalSectionWrapper* callbackCritSect)
1190{
1191 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1192 "Channel::SetEngineInformation()");
1193 _engineStatisticsPtr = &engineStatistics;
1194 _outputMixerPtr = &outputMixer;
1195 _transmitMixerPtr = &transmitMixer,
1196 _moduleProcessThreadPtr = &moduleProcessThread;
1197 _audioDeviceModulePtr = &audioDeviceModule;
1198 _voiceEngineObserverPtr = voiceEngineObserver;
1199 _callbackCritSectPtr = callbackCritSect;
1200 return 0;
1201}
1202
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001203int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001204Channel::UpdateLocalTimeStamp()
1205{
1206
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001207 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001208 return 0;
1209}
1210
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001211int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001212Channel::StartPlayout()
1213{
1214 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1215 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001216 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001217 {
1218 return 0;
1219 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001220
1221 if (!_externalMixing) {
1222 // Add participant as candidates for mixing.
1223 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1224 {
1225 _engineStatisticsPtr->SetLastError(
1226 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1227 "StartPlayout() failed to add participant to mixer");
1228 return -1;
1229 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 }
1231
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001232 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001233 if (RegisterFilePlayingToMixer() != 0)
1234 return -1;
1235
niklase@google.com470e71d2011-07-07 08:21:25 +00001236 return 0;
1237}
1238
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001239int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001240Channel::StopPlayout()
1241{
1242 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1243 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001244 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001245 {
1246 return 0;
1247 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001248
1249 if (!_externalMixing) {
1250 // Remove participant as candidates for mixing
1251 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1252 {
1253 _engineStatisticsPtr->SetLastError(
1254 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1255 "StopPlayout() failed to remove participant from mixer");
1256 return -1;
1257 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 }
1259
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001260 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 _outputAudioLevel.Clear();
1262
1263 return 0;
1264}
1265
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001266int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001267Channel::StartSend()
1268{
1269 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1270 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001271 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001272 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001273 if (send_sequence_number_)
1274 SetInitSequenceNumber(send_sequence_number_);
1275
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001276 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001277 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001278 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001279 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001280 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001281
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001282 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 {
1284 _engineStatisticsPtr->SetLastError(
1285 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1286 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001287 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001288 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001289 return -1;
1290 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001291
niklase@google.com470e71d2011-07-07 08:21:25 +00001292 return 0;
1293}
1294
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001295int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001296Channel::StopSend()
1297{
1298 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1299 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001300 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001302 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001303 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001304 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001305
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001306 // Store the sequence number to be able to pick up the same sequence for
1307 // the next StartSend(). This is needed for restarting device, otherwise
1308 // it might cause libSRTP to complain about packets being replayed.
1309 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1310 // CL is landed. See issue
1311 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1312 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1313
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 // Reset sending SSRC and sequence number and triggers direct transmission
1315 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001316 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1317 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 {
1319 _engineStatisticsPtr->SetLastError(
1320 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1321 "StartSend() RTP/RTCP failed to stop sending");
1322 }
1323
niklase@google.com470e71d2011-07-07 08:21:25 +00001324 return 0;
1325}
1326
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001327int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001328Channel::StartReceiving()
1329{
1330 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1331 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001332 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001333 {
1334 return 0;
1335 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001336 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001337 _numberOfDiscardedPackets = 0;
1338 return 0;
1339}
1340
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001341int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001342Channel::StopReceiving()
1343{
1344 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1345 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001346 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001347 {
1348 return 0;
1349 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001350
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001351 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 return 0;
1353}
1354
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001355int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001356Channel::SetNetEQPlayoutMode(NetEqModes mode)
1357{
1358 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1359 "Channel::SetNetEQPlayoutMode()");
1360 AudioPlayoutMode playoutMode(voice);
1361 switch (mode)
1362 {
1363 case kNetEqDefault:
1364 playoutMode = voice;
1365 break;
1366 case kNetEqStreaming:
1367 playoutMode = streaming;
1368 break;
1369 case kNetEqFax:
1370 playoutMode = fax;
1371 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001372 case kNetEqOff:
1373 playoutMode = off;
1374 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001375 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001376 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001377 {
1378 _engineStatisticsPtr->SetLastError(
1379 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1380 "SetNetEQPlayoutMode() failed to set playout mode");
1381 return -1;
1382 }
1383 return 0;
1384}
1385
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001386int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001387Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1388{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001389 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 switch (playoutMode)
1391 {
1392 case voice:
1393 mode = kNetEqDefault;
1394 break;
1395 case streaming:
1396 mode = kNetEqStreaming;
1397 break;
1398 case fax:
1399 mode = kNetEqFax;
1400 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001401 case off:
1402 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 }
1404 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1405 VoEId(_instanceId,_channelId),
1406 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1407 return 0;
1408}
1409
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001410int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001411Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1412{
1413 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1414 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001415 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001416
1417 if (_voiceEngineObserverPtr)
1418 {
1419 _engineStatisticsPtr->SetLastError(
1420 VE_INVALID_OPERATION, kTraceError,
1421 "RegisterVoiceEngineObserver() observer already enabled");
1422 return -1;
1423 }
1424 _voiceEngineObserverPtr = &observer;
1425 return 0;
1426}
1427
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001428int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001429Channel::DeRegisterVoiceEngineObserver()
1430{
1431 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1432 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001433 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001434
1435 if (!_voiceEngineObserverPtr)
1436 {
1437 _engineStatisticsPtr->SetLastError(
1438 VE_INVALID_OPERATION, kTraceWarning,
1439 "DeRegisterVoiceEngineObserver() observer already disabled");
1440 return 0;
1441 }
1442 _voiceEngineObserverPtr = NULL;
1443 return 0;
1444}
1445
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001446int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001447Channel::GetSendCodec(CodecInst& codec)
1448{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001449 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001450}
1451
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001452int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001453Channel::GetRecCodec(CodecInst& codec)
1454{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001455 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001456}
1457
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001458int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001459Channel::SetSendCodec(const CodecInst& codec)
1460{
1461 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1462 "Channel::SetSendCodec()");
1463
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001464 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001465 {
1466 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1467 "SetSendCodec() failed to register codec to ACM");
1468 return -1;
1469 }
1470
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001471 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001472 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001473 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1474 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001475 {
1476 WEBRTC_TRACE(
1477 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1478 "SetSendCodec() failed to register codec to"
1479 " RTP/RTCP module");
1480 return -1;
1481 }
1482 }
1483
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001484 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001485 {
1486 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1487 "SetSendCodec() failed to set audio packet size");
1488 return -1;
1489 }
1490
1491 return 0;
1492}
1493
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001494int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001495Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1496{
1497 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1498 "Channel::SetVADStatus(mode=%d)", mode);
1499 // To disable VAD, DTX must be disabled too
1500 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001501 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001502 {
1503 _engineStatisticsPtr->SetLastError(
1504 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1505 "SetVADStatus() failed to set VAD");
1506 return -1;
1507 }
1508 return 0;
1509}
1510
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001511int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001512Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1513{
1514 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1515 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001516 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001517 {
1518 _engineStatisticsPtr->SetLastError(
1519 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1520 "GetVADStatus() failed to get VAD status");
1521 return -1;
1522 }
1523 disabledDTX = !disabledDTX;
1524 return 0;
1525}
1526
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001527int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001528Channel::SetRecPayloadType(const CodecInst& codec)
1529{
1530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1531 "Channel::SetRecPayloadType()");
1532
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001533 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001534 {
1535 _engineStatisticsPtr->SetLastError(
1536 VE_ALREADY_PLAYING, kTraceError,
1537 "SetRecPayloadType() unable to set PT while playing");
1538 return -1;
1539 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001540 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001541 {
1542 _engineStatisticsPtr->SetLastError(
1543 VE_ALREADY_LISTENING, kTraceError,
1544 "SetRecPayloadType() unable to set PT while listening");
1545 return -1;
1546 }
1547
1548 if (codec.pltype == -1)
1549 {
1550 // De-register the selected codec (RTP/RTCP module and ACM)
1551
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001552 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001553 CodecInst rxCodec = codec;
1554
1555 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001556 rtp_payload_registry_->ReceivePayloadType(
1557 rxCodec.plname,
1558 rxCodec.plfreq,
1559 rxCodec.channels,
1560 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1561 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001562 rxCodec.pltype = pltype;
1563
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001564 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001565 {
1566 _engineStatisticsPtr->SetLastError(
1567 VE_RTP_RTCP_MODULE_ERROR,
1568 kTraceError,
1569 "SetRecPayloadType() RTP/RTCP-module deregistration "
1570 "failed");
1571 return -1;
1572 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001573 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001574 {
1575 _engineStatisticsPtr->SetLastError(
1576 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1577 "SetRecPayloadType() ACM deregistration failed - 1");
1578 return -1;
1579 }
1580 return 0;
1581 }
1582
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001583 if (rtp_receiver_->RegisterReceivePayload(
1584 codec.plname,
1585 codec.pltype,
1586 codec.plfreq,
1587 codec.channels,
1588 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001589 {
1590 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001591 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1592 if (rtp_receiver_->RegisterReceivePayload(
1593 codec.plname,
1594 codec.pltype,
1595 codec.plfreq,
1596 codec.channels,
1597 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001598 {
1599 _engineStatisticsPtr->SetLastError(
1600 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1601 "SetRecPayloadType() RTP/RTCP-module registration failed");
1602 return -1;
1603 }
1604 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001605 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001607 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1608 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001609 {
1610 _engineStatisticsPtr->SetLastError(
1611 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1612 "SetRecPayloadType() ACM registration failed - 1");
1613 return -1;
1614 }
1615 }
1616 return 0;
1617}
1618
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001619int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001620Channel::GetRecPayloadType(CodecInst& codec)
1621{
1622 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1623 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001624 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001625 if (rtp_payload_registry_->ReceivePayloadType(
1626 codec.plname,
1627 codec.plfreq,
1628 codec.channels,
1629 (codec.rate < 0) ? 0 : codec.rate,
1630 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001631 {
1632 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001633 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001634 "GetRecPayloadType() failed to retrieve RX payload type");
1635 return -1;
1636 }
1637 codec.pltype = payloadType;
1638 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1639 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1640 return 0;
1641}
1642
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001643int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001644Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1645{
1646 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1647 "Channel::SetSendCNPayloadType()");
1648
1649 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001650 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001651 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001652 if (frequency == kFreq32000Hz)
1653 samplingFreqHz = 32000;
1654 else if (frequency == kFreq16000Hz)
1655 samplingFreqHz = 16000;
1656
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001657 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001658 {
1659 _engineStatisticsPtr->SetLastError(
1660 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1661 "SetSendCNPayloadType() failed to retrieve default CN codec "
1662 "settings");
1663 return -1;
1664 }
1665
1666 // Modify the payload type (must be set to dynamic range)
1667 codec.pltype = type;
1668
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001669 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001670 {
1671 _engineStatisticsPtr->SetLastError(
1672 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1673 "SetSendCNPayloadType() failed to register CN to ACM");
1674 return -1;
1675 }
1676
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001677 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001678 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001679 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1680 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001681 {
1682 _engineStatisticsPtr->SetLastError(
1683 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1684 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1685 "module");
1686 return -1;
1687 }
1688 }
1689 return 0;
1690}
1691
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001692int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001693{
1694 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1695 "Channel::RegisterExternalTransport()");
1696
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001697 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001698
niklase@google.com470e71d2011-07-07 08:21:25 +00001699 if (_externalTransport)
1700 {
1701 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1702 kTraceError,
1703 "RegisterExternalTransport() external transport already enabled");
1704 return -1;
1705 }
1706 _externalTransport = true;
1707 _transportPtr = &transport;
1708 return 0;
1709}
1710
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001711int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001712Channel::DeRegisterExternalTransport()
1713{
1714 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1715 "Channel::DeRegisterExternalTransport()");
1716
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001717 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001718
niklase@google.com470e71d2011-07-07 08:21:25 +00001719 if (!_transportPtr)
1720 {
1721 _engineStatisticsPtr->SetLastError(
1722 VE_INVALID_OPERATION, kTraceWarning,
1723 "DeRegisterExternalTransport() external transport already "
1724 "disabled");
1725 return 0;
1726 }
1727 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001728 _transportPtr = NULL;
1729 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1730 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001731 return 0;
1732}
1733
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001734int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1735 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001736 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1737 "Channel::ReceivedRTPPacket()");
1738
1739 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001740 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001741
1742 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001743 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1744 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001745 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1746 VoEId(_instanceId,_channelId),
1747 "Channel::SendPacket() RTP dump to input file failed");
1748 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001749 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001750 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001751 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1752 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1753 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001754 return -1;
1755 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001756 header.payload_type_frequency =
1757 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001758 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001759 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001760 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001761 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001762 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001763 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001764
1765 // Forward any packets to ViE bandwidth estimator, if enabled.
1766 {
1767 CriticalSectionScoped cs(&_callbackCritSect);
1768 if (vie_network_) {
1769 int64_t arrival_time_ms;
1770 if (packet_time.timestamp != -1) {
1771 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1772 } else {
1773 arrival_time_ms = TickTime::MillisecondTimestamp();
1774 }
1775 int payload_length = length - header.headerLength;
1776 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1777 payload_length, header);
1778 }
1779 }
1780
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001781 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001782}
1783
1784bool Channel::ReceivePacket(const uint8_t* packet,
1785 int packet_length,
1786 const RTPHeader& header,
1787 bool in_order) {
1788 if (rtp_payload_registry_->IsEncapsulated(header)) {
1789 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001790 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001791 const uint8_t* payload = packet + header.headerLength;
1792 int payload_length = packet_length - header.headerLength;
1793 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001794 PayloadUnion payload_specific;
1795 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001796 &payload_specific)) {
1797 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001798 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001799 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1800 payload_specific, in_order);
1801}
1802
1803bool Channel::HandleEncapsulation(const uint8_t* packet,
1804 int packet_length,
1805 const RTPHeader& header) {
1806 if (!rtp_payload_registry_->IsRtx(header))
1807 return false;
1808
1809 // Remove the RTX header and parse the original RTP header.
1810 if (packet_length < header.headerLength)
1811 return false;
1812 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1813 return false;
1814 if (restored_packet_in_use_) {
1815 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1816 "Multiple RTX headers detected, dropping packet");
1817 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001818 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001819 uint8_t* restored_packet_ptr = restored_packet_;
1820 if (!rtp_payload_registry_->RestoreOriginalPacket(
1821 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1822 header)) {
1823 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1824 "Incoming RTX packet: invalid RTP header");
1825 return false;
1826 }
1827 restored_packet_in_use_ = true;
1828 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1829 restored_packet_in_use_ = false;
1830 return ret;
1831}
1832
1833bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1834 StreamStatistician* statistician =
1835 rtp_receive_statistics_->GetStatistician(header.ssrc);
1836 if (!statistician)
1837 return false;
1838 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001839}
1840
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001841bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1842 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001843 // Retransmissions are handled separately if RTX is enabled.
1844 if (rtp_payload_registry_->RtxEnabled())
1845 return false;
1846 StreamStatistician* statistician =
1847 rtp_receive_statistics_->GetStatistician(header.ssrc);
1848 if (!statistician)
1849 return false;
1850 // Check if this is a retransmission.
1851 uint16_t min_rtt = 0;
1852 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001853 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001854 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001855}
1856
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001857int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001858 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1859 "Channel::ReceivedRTCPPacket()");
1860 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001861 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001862
1863 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001864 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1865 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001866 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1867 VoEId(_instanceId,_channelId),
1868 "Channel::SendPacket() RTCP dump to input file failed");
1869 }
1870
1871 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001872 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1873 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001874 _engineStatisticsPtr->SetLastError(
1875 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1876 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1877 }
1878 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001879}
1880
niklase@google.com470e71d2011-07-07 08:21:25 +00001881int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001882 bool loop,
1883 FileFormats format,
1884 int startPosition,
1885 float volumeScaling,
1886 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001887 const CodecInst* codecInst)
1888{
1889 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1890 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1891 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1892 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1893 startPosition, stopPosition);
1894
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001895 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001896 {
1897 _engineStatisticsPtr->SetLastError(
1898 VE_ALREADY_PLAYING, kTraceError,
1899 "StartPlayingFileLocally() is already playing");
1900 return -1;
1901 }
1902
niklase@google.com470e71d2011-07-07 08:21:25 +00001903 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001904 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001905
1906 if (_outputFilePlayerPtr)
1907 {
1908 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1909 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1910 _outputFilePlayerPtr = NULL;
1911 }
1912
1913 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1914 _outputFilePlayerId, (const FileFormats)format);
1915
1916 if (_outputFilePlayerPtr == NULL)
1917 {
1918 _engineStatisticsPtr->SetLastError(
1919 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001920 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001921 return -1;
1922 }
1923
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001924 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001925
1926 if (_outputFilePlayerPtr->StartPlayingFile(
1927 fileName,
1928 loop,
1929 startPosition,
1930 volumeScaling,
1931 notificationTime,
1932 stopPosition,
1933 (const CodecInst*)codecInst) != 0)
1934 {
1935 _engineStatisticsPtr->SetLastError(
1936 VE_BAD_FILE, kTraceError,
1937 "StartPlayingFile() failed to start file playout");
1938 _outputFilePlayerPtr->StopPlayingFile();
1939 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1940 _outputFilePlayerPtr = NULL;
1941 return -1;
1942 }
1943 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001944 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001945 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001946
1947 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001948 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001949
1950 return 0;
1951}
1952
1953int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001954 FileFormats format,
1955 int startPosition,
1956 float volumeScaling,
1957 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001958 const CodecInst* codecInst)
1959{
1960 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1961 "Channel::StartPlayingFileLocally(format=%d,"
1962 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1963 format, volumeScaling, startPosition, stopPosition);
1964
1965 if(stream == NULL)
1966 {
1967 _engineStatisticsPtr->SetLastError(
1968 VE_BAD_FILE, kTraceError,
1969 "StartPlayingFileLocally() NULL as input stream");
1970 return -1;
1971 }
1972
1973
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001974 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001975 {
1976 _engineStatisticsPtr->SetLastError(
1977 VE_ALREADY_PLAYING, kTraceError,
1978 "StartPlayingFileLocally() is already playing");
1979 return -1;
1980 }
1981
niklase@google.com470e71d2011-07-07 08:21:25 +00001982 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001983 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001984
1985 // Destroy the old instance
1986 if (_outputFilePlayerPtr)
1987 {
1988 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1989 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1990 _outputFilePlayerPtr = NULL;
1991 }
1992
1993 // Create the instance
1994 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1995 _outputFilePlayerId,
1996 (const FileFormats)format);
1997
1998 if (_outputFilePlayerPtr == NULL)
1999 {
2000 _engineStatisticsPtr->SetLastError(
2001 VE_INVALID_ARGUMENT, kTraceError,
2002 "StartPlayingFileLocally() filePlayer format isnot correct");
2003 return -1;
2004 }
2005
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002006 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002007
2008 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2009 volumeScaling,
2010 notificationTime,
2011 stopPosition, codecInst) != 0)
2012 {
2013 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2014 "StartPlayingFile() failed to "
2015 "start file playout");
2016 _outputFilePlayerPtr->StopPlayingFile();
2017 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2018 _outputFilePlayerPtr = NULL;
2019 return -1;
2020 }
2021 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002022 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002023 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002024
2025 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002026 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002027
niklase@google.com470e71d2011-07-07 08:21:25 +00002028 return 0;
2029}
2030
2031int Channel::StopPlayingFileLocally()
2032{
2033 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2034 "Channel::StopPlayingFileLocally()");
2035
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002036 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002037 {
2038 _engineStatisticsPtr->SetLastError(
2039 VE_INVALID_OPERATION, kTraceWarning,
2040 "StopPlayingFileLocally() isnot playing");
2041 return 0;
2042 }
2043
niklase@google.com470e71d2011-07-07 08:21:25 +00002044 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002045 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002046
2047 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2048 {
2049 _engineStatisticsPtr->SetLastError(
2050 VE_STOP_RECORDING_FAILED, kTraceError,
2051 "StopPlayingFile() could not stop playing");
2052 return -1;
2053 }
2054 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2055 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2056 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002057 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002058 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002059 // _fileCritSect cannot be taken while calling
2060 // SetAnonymousMixibilityStatus. Refer to comments in
2061 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002062 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2063 {
2064 _engineStatisticsPtr->SetLastError(
2065 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002066 "StopPlayingFile() failed to stop participant from playing as"
2067 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002068 return -1;
2069 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002070
2071 return 0;
2072}
2073
2074int Channel::IsPlayingFileLocally() const
2075{
2076 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2077 "Channel::IsPlayingFileLocally()");
2078
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002079 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002080}
2081
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002082int Channel::RegisterFilePlayingToMixer()
2083{
2084 // Return success for not registering for file playing to mixer if:
2085 // 1. playing file before playout is started on that channel.
2086 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002087 if (!channel_state_.Get().playing ||
2088 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002089 {
2090 return 0;
2091 }
2092
2093 // |_fileCritSect| cannot be taken while calling
2094 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2095 // frames can be pulled by the mixer. Since the frames are generated from
2096 // the file, _fileCritSect will be taken. This would result in a deadlock.
2097 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2098 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002099 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002100 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002101 _engineStatisticsPtr->SetLastError(
2102 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2103 "StartPlayingFile() failed to add participant as file to mixer");
2104 _outputFilePlayerPtr->StopPlayingFile();
2105 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2106 _outputFilePlayerPtr = NULL;
2107 return -1;
2108 }
2109
2110 return 0;
2111}
2112
niklase@google.com470e71d2011-07-07 08:21:25 +00002113int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002114 bool loop,
2115 FileFormats format,
2116 int startPosition,
2117 float volumeScaling,
2118 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002119 const CodecInst* codecInst)
2120{
2121 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2122 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2123 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2124 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2125 startPosition, stopPosition);
2126
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002127 CriticalSectionScoped cs(&_fileCritSect);
2128
2129 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002130 {
2131 _engineStatisticsPtr->SetLastError(
2132 VE_ALREADY_PLAYING, kTraceWarning,
2133 "StartPlayingFileAsMicrophone() filePlayer is playing");
2134 return 0;
2135 }
2136
niklase@google.com470e71d2011-07-07 08:21:25 +00002137 // Destroy the old instance
2138 if (_inputFilePlayerPtr)
2139 {
2140 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2141 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2142 _inputFilePlayerPtr = NULL;
2143 }
2144
2145 // Create the instance
2146 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2147 _inputFilePlayerId, (const FileFormats)format);
2148
2149 if (_inputFilePlayerPtr == NULL)
2150 {
2151 _engineStatisticsPtr->SetLastError(
2152 VE_INVALID_ARGUMENT, kTraceError,
2153 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2154 return -1;
2155 }
2156
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002157 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002158
2159 if (_inputFilePlayerPtr->StartPlayingFile(
2160 fileName,
2161 loop,
2162 startPosition,
2163 volumeScaling,
2164 notificationTime,
2165 stopPosition,
2166 (const CodecInst*)codecInst) != 0)
2167 {
2168 _engineStatisticsPtr->SetLastError(
2169 VE_BAD_FILE, kTraceError,
2170 "StartPlayingFile() failed to start file playout");
2171 _inputFilePlayerPtr->StopPlayingFile();
2172 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2173 _inputFilePlayerPtr = NULL;
2174 return -1;
2175 }
2176 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002177 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002178
2179 return 0;
2180}
2181
2182int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002183 FileFormats format,
2184 int startPosition,
2185 float volumeScaling,
2186 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002187 const CodecInst* codecInst)
2188{
2189 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2190 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2191 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2192 format, volumeScaling, startPosition, stopPosition);
2193
2194 if(stream == NULL)
2195 {
2196 _engineStatisticsPtr->SetLastError(
2197 VE_BAD_FILE, kTraceError,
2198 "StartPlayingFileAsMicrophone NULL as input stream");
2199 return -1;
2200 }
2201
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002202 CriticalSectionScoped cs(&_fileCritSect);
2203
2204 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002205 {
2206 _engineStatisticsPtr->SetLastError(
2207 VE_ALREADY_PLAYING, kTraceWarning,
2208 "StartPlayingFileAsMicrophone() is playing");
2209 return 0;
2210 }
2211
niklase@google.com470e71d2011-07-07 08:21:25 +00002212 // Destroy the old instance
2213 if (_inputFilePlayerPtr)
2214 {
2215 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2216 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2217 _inputFilePlayerPtr = NULL;
2218 }
2219
2220 // Create the instance
2221 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2222 _inputFilePlayerId, (const FileFormats)format);
2223
2224 if (_inputFilePlayerPtr == NULL)
2225 {
2226 _engineStatisticsPtr->SetLastError(
2227 VE_INVALID_ARGUMENT, kTraceError,
2228 "StartPlayingInputFile() filePlayer format isnot correct");
2229 return -1;
2230 }
2231
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002232 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002233
2234 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2235 volumeScaling, notificationTime,
2236 stopPosition, codecInst) != 0)
2237 {
2238 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2239 "StartPlayingFile() failed to start "
2240 "file playout");
2241 _inputFilePlayerPtr->StopPlayingFile();
2242 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2243 _inputFilePlayerPtr = NULL;
2244 return -1;
2245 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002246
niklase@google.com470e71d2011-07-07 08:21:25 +00002247 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002248 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002249
2250 return 0;
2251}
2252
2253int Channel::StopPlayingFileAsMicrophone()
2254{
2255 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2256 "Channel::StopPlayingFileAsMicrophone()");
2257
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002258 CriticalSectionScoped cs(&_fileCritSect);
2259
2260 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002261 {
2262 _engineStatisticsPtr->SetLastError(
2263 VE_INVALID_OPERATION, kTraceWarning,
2264 "StopPlayingFileAsMicrophone() isnot playing");
2265 return 0;
2266 }
2267
niklase@google.com470e71d2011-07-07 08:21:25 +00002268 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2269 {
2270 _engineStatisticsPtr->SetLastError(
2271 VE_STOP_RECORDING_FAILED, kTraceError,
2272 "StopPlayingFile() could not stop playing");
2273 return -1;
2274 }
2275 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2276 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2277 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002278 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002279
2280 return 0;
2281}
2282
2283int Channel::IsPlayingFileAsMicrophone() const
2284{
2285 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2286 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002287 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002288}
2289
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002290int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002291 const CodecInst* codecInst)
2292{
2293 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2294 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2295
2296 if (_outputFileRecording)
2297 {
2298 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2299 "StartRecordingPlayout() is already recording");
2300 return 0;
2301 }
2302
2303 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002304 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002305 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2306
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002307 if ((codecInst != NULL) &&
2308 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002309 {
2310 _engineStatisticsPtr->SetLastError(
2311 VE_BAD_ARGUMENT, kTraceError,
2312 "StartRecordingPlayout() invalid compression");
2313 return(-1);
2314 }
2315 if(codecInst == NULL)
2316 {
2317 format = kFileFormatPcm16kHzFile;
2318 codecInst=&dummyCodec;
2319 }
2320 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2321 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2322 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2323 {
2324 format = kFileFormatWavFile;
2325 }
2326 else
2327 {
2328 format = kFileFormatCompressedFile;
2329 }
2330
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002331 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002332
2333 // Destroy the old instance
2334 if (_outputFileRecorderPtr)
2335 {
2336 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2337 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2338 _outputFileRecorderPtr = NULL;
2339 }
2340
2341 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2342 _outputFileRecorderId, (const FileFormats)format);
2343 if (_outputFileRecorderPtr == NULL)
2344 {
2345 _engineStatisticsPtr->SetLastError(
2346 VE_INVALID_ARGUMENT, kTraceError,
2347 "StartRecordingPlayout() fileRecorder format isnot correct");
2348 return -1;
2349 }
2350
2351 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2352 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2353 {
2354 _engineStatisticsPtr->SetLastError(
2355 VE_BAD_FILE, kTraceError,
2356 "StartRecordingAudioFile() failed to start file recording");
2357 _outputFileRecorderPtr->StopRecording();
2358 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2359 _outputFileRecorderPtr = NULL;
2360 return -1;
2361 }
2362 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2363 _outputFileRecording = true;
2364
2365 return 0;
2366}
2367
2368int Channel::StartRecordingPlayout(OutStream* stream,
2369 const CodecInst* codecInst)
2370{
2371 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2372 "Channel::StartRecordingPlayout()");
2373
2374 if (_outputFileRecording)
2375 {
2376 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2377 "StartRecordingPlayout() is already recording");
2378 return 0;
2379 }
2380
2381 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002382 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002383 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2384
2385 if (codecInst != NULL && codecInst->channels != 1)
2386 {
2387 _engineStatisticsPtr->SetLastError(
2388 VE_BAD_ARGUMENT, kTraceError,
2389 "StartRecordingPlayout() invalid compression");
2390 return(-1);
2391 }
2392 if(codecInst == NULL)
2393 {
2394 format = kFileFormatPcm16kHzFile;
2395 codecInst=&dummyCodec;
2396 }
2397 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2398 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2399 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2400 {
2401 format = kFileFormatWavFile;
2402 }
2403 else
2404 {
2405 format = kFileFormatCompressedFile;
2406 }
2407
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002408 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002409
2410 // Destroy the old instance
2411 if (_outputFileRecorderPtr)
2412 {
2413 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2414 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2415 _outputFileRecorderPtr = NULL;
2416 }
2417
2418 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2419 _outputFileRecorderId, (const FileFormats)format);
2420 if (_outputFileRecorderPtr == NULL)
2421 {
2422 _engineStatisticsPtr->SetLastError(
2423 VE_INVALID_ARGUMENT, kTraceError,
2424 "StartRecordingPlayout() fileRecorder format isnot correct");
2425 return -1;
2426 }
2427
2428 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2429 notificationTime) != 0)
2430 {
2431 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2432 "StartRecordingPlayout() failed to "
2433 "start file recording");
2434 _outputFileRecorderPtr->StopRecording();
2435 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2436 _outputFileRecorderPtr = NULL;
2437 return -1;
2438 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002439
niklase@google.com470e71d2011-07-07 08:21:25 +00002440 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2441 _outputFileRecording = true;
2442
2443 return 0;
2444}
2445
2446int Channel::StopRecordingPlayout()
2447{
2448 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2449 "Channel::StopRecordingPlayout()");
2450
2451 if (!_outputFileRecording)
2452 {
2453 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2454 "StopRecordingPlayout() isnot recording");
2455 return -1;
2456 }
2457
2458
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002459 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002460
2461 if (_outputFileRecorderPtr->StopRecording() != 0)
2462 {
2463 _engineStatisticsPtr->SetLastError(
2464 VE_STOP_RECORDING_FAILED, kTraceError,
2465 "StopRecording() could not stop recording");
2466 return(-1);
2467 }
2468 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2469 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2470 _outputFileRecorderPtr = NULL;
2471 _outputFileRecording = false;
2472
2473 return 0;
2474}
2475
2476void
2477Channel::SetMixWithMicStatus(bool mix)
2478{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002479 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002480 _mixFileWithMicrophone=mix;
2481}
2482
2483int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002484Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002485{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002486 int8_t currentLevel = _outputAudioLevel.Level();
2487 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002488 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2489 VoEId(_instanceId,_channelId),
2490 "GetSpeechOutputLevel() => level=%u", level);
2491 return 0;
2492}
2493
2494int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002495Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002496{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002497 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2498 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002499 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2500 VoEId(_instanceId,_channelId),
2501 "GetSpeechOutputLevelFullRange() => level=%u", level);
2502 return 0;
2503}
2504
2505int
2506Channel::SetMute(bool enable)
2507{
wu@webrtc.org63420662013-10-17 18:28:55 +00002508 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002509 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2510 "Channel::SetMute(enable=%d)", enable);
2511 _mute = enable;
2512 return 0;
2513}
2514
2515bool
2516Channel::Mute() const
2517{
wu@webrtc.org63420662013-10-17 18:28:55 +00002518 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002519 return _mute;
2520}
2521
2522int
2523Channel::SetOutputVolumePan(float left, float right)
2524{
wu@webrtc.org63420662013-10-17 18:28:55 +00002525 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002526 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2527 "Channel::SetOutputVolumePan()");
2528 _panLeft = left;
2529 _panRight = right;
2530 return 0;
2531}
2532
2533int
2534Channel::GetOutputVolumePan(float& left, float& right) const
2535{
wu@webrtc.org63420662013-10-17 18:28:55 +00002536 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002537 left = _panLeft;
2538 right = _panRight;
2539 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2540 VoEId(_instanceId,_channelId),
2541 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2542 return 0;
2543}
2544
2545int
2546Channel::SetChannelOutputVolumeScaling(float scaling)
2547{
wu@webrtc.org63420662013-10-17 18:28:55 +00002548 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002549 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2550 "Channel::SetChannelOutputVolumeScaling()");
2551 _outputGain = scaling;
2552 return 0;
2553}
2554
2555int
2556Channel::GetChannelOutputVolumeScaling(float& scaling) const
2557{
wu@webrtc.org63420662013-10-17 18:28:55 +00002558 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002559 scaling = _outputGain;
2560 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2561 VoEId(_instanceId,_channelId),
2562 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2563 return 0;
2564}
2565
niklase@google.com470e71d2011-07-07 08:21:25 +00002566int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002567 int lengthMs, int attenuationDb,
2568 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002569{
2570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2571 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2572 playDtmfEvent);
2573
2574 _playOutbandDtmfEvent = playDtmfEvent;
2575
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002576 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002577 attenuationDb) != 0)
2578 {
2579 _engineStatisticsPtr->SetLastError(
2580 VE_SEND_DTMF_FAILED,
2581 kTraceWarning,
2582 "SendTelephoneEventOutband() failed to send event");
2583 return -1;
2584 }
2585 return 0;
2586}
2587
2588int Channel::SendTelephoneEventInband(unsigned char eventCode,
2589 int lengthMs,
2590 int attenuationDb,
2591 bool playDtmfEvent)
2592{
2593 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2594 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2595 playDtmfEvent);
2596
2597 _playInbandDtmfEvent = playDtmfEvent;
2598 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2599
2600 return 0;
2601}
2602
2603int
2604Channel::SetDtmfPlayoutStatus(bool enable)
2605{
2606 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2607 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002608 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002609 {
2610 _engineStatisticsPtr->SetLastError(
2611 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2612 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2613 return -1;
2614 }
2615 return 0;
2616}
2617
2618bool
2619Channel::DtmfPlayoutStatus() const
2620{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002621 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002622}
2623
2624int
2625Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2626{
2627 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2628 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002629 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002630 {
2631 _engineStatisticsPtr->SetLastError(
2632 VE_INVALID_ARGUMENT, kTraceError,
2633 "SetSendTelephoneEventPayloadType() invalid type");
2634 return -1;
2635 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002636 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002637 codec.plfreq = 8000;
2638 codec.pltype = type;
2639 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002640 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002641 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002642 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2643 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2644 _engineStatisticsPtr->SetLastError(
2645 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2646 "SetSendTelephoneEventPayloadType() failed to register send"
2647 "payload type");
2648 return -1;
2649 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002650 }
2651 _sendTelephoneEventPayloadType = type;
2652 return 0;
2653}
2654
2655int
2656Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2657{
2658 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2659 "Channel::GetSendTelephoneEventPayloadType()");
2660 type = _sendTelephoneEventPayloadType;
2661 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2662 VoEId(_instanceId,_channelId),
2663 "GetSendTelephoneEventPayloadType() => type=%u", type);
2664 return 0;
2665}
2666
niklase@google.com470e71d2011-07-07 08:21:25 +00002667int
2668Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2669{
2670 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2671 "Channel::UpdateRxVadDetection()");
2672
2673 int vadDecision = 1;
2674
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002675 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002676
2677 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2678 {
2679 OnRxVadDetected(vadDecision);
2680 _oldVadDecision = vadDecision;
2681 }
2682
2683 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2684 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2685 vadDecision);
2686 return 0;
2687}
2688
2689int
2690Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2691{
2692 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2693 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002694 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002695
2696 if (_rxVadObserverPtr)
2697 {
2698 _engineStatisticsPtr->SetLastError(
2699 VE_INVALID_OPERATION, kTraceError,
2700 "RegisterRxVadObserver() observer already enabled");
2701 return -1;
2702 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002703 _rxVadObserverPtr = &observer;
2704 _RxVadDetection = true;
2705 return 0;
2706}
2707
2708int
2709Channel::DeRegisterRxVadObserver()
2710{
2711 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2712 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002713 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002714
2715 if (!_rxVadObserverPtr)
2716 {
2717 _engineStatisticsPtr->SetLastError(
2718 VE_INVALID_OPERATION, kTraceWarning,
2719 "DeRegisterRxVadObserver() observer already disabled");
2720 return 0;
2721 }
2722 _rxVadObserverPtr = NULL;
2723 _RxVadDetection = false;
2724 return 0;
2725}
2726
2727int
2728Channel::VoiceActivityIndicator(int &activity)
2729{
2730 activity = _sendFrameType;
2731
2732 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002733 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002734 return 0;
2735}
2736
2737#ifdef WEBRTC_VOICE_ENGINE_AGC
2738
2739int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002740Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002741{
2742 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2743 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2744 (int)enable, (int)mode);
2745
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002746 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002747 switch (mode)
2748 {
2749 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002750 break;
2751 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002752 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002753 break;
2754 case kAgcFixedDigital:
2755 agcMode = GainControl::kFixedDigital;
2756 break;
2757 case kAgcAdaptiveDigital:
2758 agcMode =GainControl::kAdaptiveDigital;
2759 break;
2760 default:
2761 _engineStatisticsPtr->SetLastError(
2762 VE_INVALID_ARGUMENT, kTraceError,
2763 "SetRxAgcStatus() invalid Agc mode");
2764 return -1;
2765 }
2766
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002767 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002768 {
2769 _engineStatisticsPtr->SetLastError(
2770 VE_APM_ERROR, kTraceError,
2771 "SetRxAgcStatus() failed to set Agc mode");
2772 return -1;
2773 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002774 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002775 {
2776 _engineStatisticsPtr->SetLastError(
2777 VE_APM_ERROR, kTraceError,
2778 "SetRxAgcStatus() failed to set Agc state");
2779 return -1;
2780 }
2781
2782 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002783 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002784
2785 return 0;
2786}
2787
2788int
2789Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2790{
2791 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2792 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2793
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002794 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002795 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002796 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002797
2798 enabled = enable;
2799
2800 switch (agcMode)
2801 {
2802 case GainControl::kFixedDigital:
2803 mode = kAgcFixedDigital;
2804 break;
2805 case GainControl::kAdaptiveDigital:
2806 mode = kAgcAdaptiveDigital;
2807 break;
2808 default:
2809 _engineStatisticsPtr->SetLastError(
2810 VE_APM_ERROR, kTraceError,
2811 "GetRxAgcStatus() invalid Agc mode");
2812 return -1;
2813 }
2814
2815 return 0;
2816}
2817
2818int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002819Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002820{
2821 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2822 "Channel::SetRxAgcConfig()");
2823
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002824 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002825 config.targetLeveldBOv) != 0)
2826 {
2827 _engineStatisticsPtr->SetLastError(
2828 VE_APM_ERROR, kTraceError,
2829 "SetRxAgcConfig() failed to set target peak |level|"
2830 "(or envelope) of the Agc");
2831 return -1;
2832 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002833 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002834 config.digitalCompressionGaindB) != 0)
2835 {
2836 _engineStatisticsPtr->SetLastError(
2837 VE_APM_ERROR, kTraceError,
2838 "SetRxAgcConfig() failed to set the range in |gain| the"
2839 " digital compression stage may apply");
2840 return -1;
2841 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002842 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002843 config.limiterEnable) != 0)
2844 {
2845 _engineStatisticsPtr->SetLastError(
2846 VE_APM_ERROR, kTraceError,
2847 "SetRxAgcConfig() failed to set hard limiter to the signal");
2848 return -1;
2849 }
2850
2851 return 0;
2852}
2853
2854int
2855Channel::GetRxAgcConfig(AgcConfig& config)
2856{
2857 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2858 "Channel::GetRxAgcConfig(config=%?)");
2859
2860 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002861 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002862 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002863 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002864 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002865 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002866
2867 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2868 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2869 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2870 " limiterEnable=%d",
2871 config.targetLeveldBOv,
2872 config.digitalCompressionGaindB,
2873 config.limiterEnable);
2874
2875 return 0;
2876}
2877
2878#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2879
2880#ifdef WEBRTC_VOICE_ENGINE_NR
2881
2882int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002883Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002884{
2885 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2886 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2887 (int)enable, (int)mode);
2888
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002889 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002890 switch (mode)
2891 {
2892
2893 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002894 break;
2895 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002896 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002897 break;
2898 case kNsConference:
2899 nsLevel = NoiseSuppression::kHigh;
2900 break;
2901 case kNsLowSuppression:
2902 nsLevel = NoiseSuppression::kLow;
2903 break;
2904 case kNsModerateSuppression:
2905 nsLevel = NoiseSuppression::kModerate;
2906 break;
2907 case kNsHighSuppression:
2908 nsLevel = NoiseSuppression::kHigh;
2909 break;
2910 case kNsVeryHighSuppression:
2911 nsLevel = NoiseSuppression::kVeryHigh;
2912 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002913 }
2914
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002915 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002916 != 0)
2917 {
2918 _engineStatisticsPtr->SetLastError(
2919 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002920 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002921 return -1;
2922 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002923 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002924 {
2925 _engineStatisticsPtr->SetLastError(
2926 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002927 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002928 return -1;
2929 }
2930
2931 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002932 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002933
2934 return 0;
2935}
2936
2937int
2938Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2939{
2940 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2941 "Channel::GetRxNsStatus(enable=?, mode=?)");
2942
2943 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002944 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002945 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002946 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002947
2948 enabled = enable;
2949
2950 switch (ncLevel)
2951 {
2952 case NoiseSuppression::kLow:
2953 mode = kNsLowSuppression;
2954 break;
2955 case NoiseSuppression::kModerate:
2956 mode = kNsModerateSuppression;
2957 break;
2958 case NoiseSuppression::kHigh:
2959 mode = kNsHighSuppression;
2960 break;
2961 case NoiseSuppression::kVeryHigh:
2962 mode = kNsVeryHighSuppression;
2963 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002964 }
2965
2966 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2967 VoEId(_instanceId,_channelId),
2968 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2969 return 0;
2970}
2971
2972#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2973
2974int
niklase@google.com470e71d2011-07-07 08:21:25 +00002975Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
2976{
2977 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2978 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002979 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002980
2981 if (_rtcpObserverPtr)
2982 {
2983 _engineStatisticsPtr->SetLastError(
2984 VE_INVALID_OPERATION, kTraceError,
2985 "RegisterRTCPObserver() observer already enabled");
2986 return -1;
2987 }
2988
2989 _rtcpObserverPtr = &observer;
2990 _rtcpObserver = true;
2991
2992 return 0;
2993}
2994
2995int
2996Channel::DeRegisterRTCPObserver()
2997{
2998 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2999 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003000 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003001
3002 if (!_rtcpObserverPtr)
3003 {
3004 _engineStatisticsPtr->SetLastError(
3005 VE_INVALID_OPERATION, kTraceWarning,
3006 "DeRegisterRTCPObserver() observer already disabled");
3007 return 0;
3008 }
3009
3010 _rtcpObserver = false;
3011 _rtcpObserverPtr = NULL;
3012
3013 return 0;
3014}
3015
3016int
3017Channel::SetLocalSSRC(unsigned int ssrc)
3018{
3019 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3020 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003021 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003022 {
3023 _engineStatisticsPtr->SetLastError(
3024 VE_ALREADY_SENDING, kTraceError,
3025 "SetLocalSSRC() already sending");
3026 return -1;
3027 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003028 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003029 {
3030 _engineStatisticsPtr->SetLastError(
3031 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3032 "SetLocalSSRC() failed to set SSRC");
3033 return -1;
3034 }
3035 return 0;
3036}
3037
3038int
3039Channel::GetLocalSSRC(unsigned int& ssrc)
3040{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003041 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003042 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3043 VoEId(_instanceId,_channelId),
3044 "GetLocalSSRC() => ssrc=%lu", ssrc);
3045 return 0;
3046}
3047
3048int
3049Channel::GetRemoteSSRC(unsigned int& ssrc)
3050{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003051 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003052 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3053 VoEId(_instanceId,_channelId),
3054 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3055 return 0;
3056}
3057
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003058int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003059 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003060 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003061}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003062
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003063int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3064 unsigned char id) {
3065 rtp_header_parser_->DeregisterRtpHeaderExtension(
3066 kRtpExtensionAudioLevel);
3067 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3068 kRtpExtensionAudioLevel, id)) {
3069 return -1;
3070 }
3071 return 0;
3072}
3073
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003074int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3075 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3076}
3077
3078int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3079 rtp_header_parser_->DeregisterRtpHeaderExtension(
3080 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003081 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3082 kRtpExtensionAbsoluteSendTime, id)) {
3083 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003084 }
3085 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003086}
3087
3088int
3089Channel::SetRTCPStatus(bool enable)
3090{
3091 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3092 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003093 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003094 kRtcpCompound : kRtcpOff) != 0)
3095 {
3096 _engineStatisticsPtr->SetLastError(
3097 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3098 "SetRTCPStatus() failed to set RTCP status");
3099 return -1;
3100 }
3101 return 0;
3102}
3103
3104int
3105Channel::GetRTCPStatus(bool& enabled)
3106{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003107 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003108 enabled = (method != kRtcpOff);
3109 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3110 VoEId(_instanceId,_channelId),
3111 "GetRTCPStatus() => enabled=%d", enabled);
3112 return 0;
3113}
3114
3115int
3116Channel::SetRTCP_CNAME(const char cName[256])
3117{
3118 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3119 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003120 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003121 {
3122 _engineStatisticsPtr->SetLastError(
3123 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3124 "SetRTCP_CNAME() failed to set RTCP CNAME");
3125 return -1;
3126 }
3127 return 0;
3128}
3129
3130int
3131Channel::GetRTCP_CNAME(char cName[256])
3132{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003133 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003134 {
3135 _engineStatisticsPtr->SetLastError(
3136 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3137 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3138 return -1;
3139 }
3140 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3141 VoEId(_instanceId, _channelId),
3142 "GetRTCP_CNAME() => cName=%s", cName);
3143 return 0;
3144}
3145
3146int
3147Channel::GetRemoteRTCP_CNAME(char cName[256])
3148{
3149 if (cName == NULL)
3150 {
3151 _engineStatisticsPtr->SetLastError(
3152 VE_INVALID_ARGUMENT, kTraceError,
3153 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3154 return -1;
3155 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003156 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003157 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003158 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003159 {
3160 _engineStatisticsPtr->SetLastError(
3161 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3162 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3163 return -1;
3164 }
3165 strcpy(cName, cname);
3166 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3167 VoEId(_instanceId, _channelId),
3168 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3169 return 0;
3170}
3171
3172int
3173Channel::GetRemoteRTCPData(
3174 unsigned int& NTPHigh,
3175 unsigned int& NTPLow,
3176 unsigned int& timestamp,
3177 unsigned int& playoutTimestamp,
3178 unsigned int* jitter,
3179 unsigned short* fractionLost)
3180{
3181 // --- Information from sender info in received Sender Reports
3182
3183 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003184 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003185 {
3186 _engineStatisticsPtr->SetLastError(
3187 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003188 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003189 "side");
3190 return -1;
3191 }
3192
3193 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3194 // and octet count)
3195 NTPHigh = senderInfo.NTPseconds;
3196 NTPLow = senderInfo.NTPfraction;
3197 timestamp = senderInfo.RTPtimeStamp;
3198
3199 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3200 VoEId(_instanceId, _channelId),
3201 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3202 "timestamp=%lu",
3203 NTPHigh, NTPLow, timestamp);
3204
3205 // --- Locally derived information
3206
3207 // This value is updated on each incoming RTCP packet (0 when no packet
3208 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003209 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003210
3211 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3212 VoEId(_instanceId, _channelId),
3213 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003214 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003215
3216 if (NULL != jitter || NULL != fractionLost)
3217 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003218 // Get all RTCP receiver report blocks that have been received on this
3219 // channel. If we receive RTP packets from a remote source we know the
3220 // remote SSRC and use the report block from him.
3221 // Otherwise use the first report block.
3222 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003223 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003224 remote_stats.empty()) {
3225 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3226 VoEId(_instanceId, _channelId),
3227 "GetRemoteRTCPData() failed to measure statistics due"
3228 " to lack of received RTP and/or RTCP packets");
3229 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003230 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003231
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003232 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003233 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3234 for (; it != remote_stats.end(); ++it) {
3235 if (it->remoteSSRC == remoteSSRC)
3236 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003237 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003238
3239 if (it == remote_stats.end()) {
3240 // If we have not received any RTCP packets from this SSRC it probably
3241 // means that we have not received any RTP packets.
3242 // Use the first received report block instead.
3243 it = remote_stats.begin();
3244 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003245 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003246
xians@webrtc.org79af7342012-01-31 12:22:14 +00003247 if (jitter) {
3248 *jitter = it->jitter;
3249 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3250 VoEId(_instanceId, _channelId),
3251 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3252 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003253
xians@webrtc.org79af7342012-01-31 12:22:14 +00003254 if (fractionLost) {
3255 *fractionLost = it->fractionLost;
3256 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3257 VoEId(_instanceId, _channelId),
3258 "GetRemoteRTCPData() => fractionLost = %lu",
3259 *fractionLost);
3260 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003261 }
3262 return 0;
3263}
3264
3265int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003266Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003267 unsigned int name,
3268 const char* data,
3269 unsigned short dataLengthInBytes)
3270{
3271 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3272 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003273 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003274 {
3275 _engineStatisticsPtr->SetLastError(
3276 VE_NOT_SENDING, kTraceError,
3277 "SendApplicationDefinedRTCPPacket() not sending");
3278 return -1;
3279 }
3280 if (NULL == data)
3281 {
3282 _engineStatisticsPtr->SetLastError(
3283 VE_INVALID_ARGUMENT, kTraceError,
3284 "SendApplicationDefinedRTCPPacket() invalid data value");
3285 return -1;
3286 }
3287 if (dataLengthInBytes % 4 != 0)
3288 {
3289 _engineStatisticsPtr->SetLastError(
3290 VE_INVALID_ARGUMENT, kTraceError,
3291 "SendApplicationDefinedRTCPPacket() invalid length value");
3292 return -1;
3293 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003294 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003295 if (status == kRtcpOff)
3296 {
3297 _engineStatisticsPtr->SetLastError(
3298 VE_RTCP_ERROR, kTraceError,
3299 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3300 return -1;
3301 }
3302
3303 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003304 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003305 subType,
3306 name,
3307 (const unsigned char*) data,
3308 dataLengthInBytes) != 0)
3309 {
3310 _engineStatisticsPtr->SetLastError(
3311 VE_SEND_ERROR, kTraceError,
3312 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3313 return -1;
3314 }
3315 return 0;
3316}
3317
3318int
3319Channel::GetRTPStatistics(
3320 unsigned int& averageJitterMs,
3321 unsigned int& maxJitterMs,
3322 unsigned int& discardedPackets)
3323{
niklase@google.com470e71d2011-07-07 08:21:25 +00003324 // The jitter statistics is updated for each received RTP packet and is
3325 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003326 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3327 // If RTCP is off, there is no timed thread in the RTCP module regularly
3328 // generating new stats, trigger the update manually here instead.
3329 StreamStatistician* statistician =
3330 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3331 if (statistician) {
3332 // Don't use returned statistics, use data from proxy instead so that
3333 // max jitter can be fetched atomically.
3334 RtcpStatistics s;
3335 statistician->GetStatistics(&s, true);
3336 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003337 }
3338
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003339 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003340 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003341 if (playoutFrequency > 0) {
3342 // Scale RTP statistics given the current playout frequency
3343 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3344 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003345 }
3346
3347 discardedPackets = _numberOfDiscardedPackets;
3348
3349 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3350 VoEId(_instanceId, _channelId),
3351 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003352 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003353 averageJitterMs, maxJitterMs, discardedPackets);
3354 return 0;
3355}
3356
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003357int Channel::GetRemoteRTCPReportBlocks(
3358 std::vector<ReportBlock>* report_blocks) {
3359 if (report_blocks == NULL) {
3360 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3361 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3362 return -1;
3363 }
3364
3365 // Get the report blocks from the latest received RTCP Sender or Receiver
3366 // Report. Each element in the vector contains the sender's SSRC and a
3367 // report block according to RFC 3550.
3368 std::vector<RTCPReportBlock> rtcp_report_blocks;
3369 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3370 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3371 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3372 return -1;
3373 }
3374
3375 if (rtcp_report_blocks.empty())
3376 return 0;
3377
3378 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3379 for (; it != rtcp_report_blocks.end(); ++it) {
3380 ReportBlock report_block;
3381 report_block.sender_SSRC = it->remoteSSRC;
3382 report_block.source_SSRC = it->sourceSSRC;
3383 report_block.fraction_lost = it->fractionLost;
3384 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3385 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3386 report_block.interarrival_jitter = it->jitter;
3387 report_block.last_SR_timestamp = it->lastSR;
3388 report_block.delay_since_last_SR = it->delaySinceLastSR;
3389 report_blocks->push_back(report_block);
3390 }
3391 return 0;
3392}
3393
niklase@google.com470e71d2011-07-07 08:21:25 +00003394int
3395Channel::GetRTPStatistics(CallStatistics& stats)
3396{
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003397 // --- RtcpStatistics
niklase@google.com470e71d2011-07-07 08:21:25 +00003398
3399 // The jitter statistics is updated for each received RTP packet and is
3400 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003401 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003402 StreamStatistician* statistician =
3403 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3404 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003405 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3406 _engineStatisticsPtr->SetLastError(
3407 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3408 "GetRTPStatistics() failed to read RTP statistics from the "
3409 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 }
3411
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003412 stats.fractionLost = statistics.fraction_lost;
3413 stats.cumulativeLost = statistics.cumulative_lost;
3414 stats.extendedMax = statistics.extended_max_sequence_number;
3415 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003416
3417 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3418 VoEId(_instanceId, _channelId),
3419 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003420 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003421 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3422 stats.jitterSamples);
3423
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003424 // --- RTT
niklase@google.com470e71d2011-07-07 08:21:25 +00003425
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003426 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003427 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003428 if (method == kRtcpOff)
3429 {
3430 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3431 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003432 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003433 "measurements cannot be retrieved");
3434 } else
3435 {
3436 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003437 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003438 if (remoteSSRC > 0)
3439 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003440 uint16_t avgRTT(0);
3441 uint16_t maxRTT(0);
3442 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003443
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003444 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003445 != 0)
3446 {
3447 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3448 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003449 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003450 "the RTP/RTCP module");
3451 }
3452 } else
3453 {
3454 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3455 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003456 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003457 "RTP packets have been received yet");
3458 }
3459 }
3460
3461 stats.rttMs = static_cast<int> (RTT);
3462
3463 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3464 VoEId(_instanceId, _channelId),
3465 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3466
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003467 // --- Data counters
niklase@google.com470e71d2011-07-07 08:21:25 +00003468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003469 uint32_t bytesSent(0);
3470 uint32_t packetsSent(0);
3471 uint32_t bytesReceived(0);
3472 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003473
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003474 if (statistician) {
3475 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3476 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003477
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003478 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003479 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003480 {
3481 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3482 VoEId(_instanceId, _channelId),
3483 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003484 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003485 }
3486
3487 stats.bytesSent = bytesSent;
3488 stats.packetsSent = packetsSent;
3489 stats.bytesReceived = bytesReceived;
3490 stats.packetsReceived = packetsReceived;
3491
3492 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3493 VoEId(_instanceId, _channelId),
3494 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003495 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003496 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3497 stats.packetsReceived);
3498
wu@webrtc.orgcb711f72014-05-19 17:39:11 +00003499 // --- Timestamps
3500 {
3501 CriticalSectionScoped lock(ts_stats_lock_.get());
3502 stats.capture_start_ntp_time_ms_ = capture_start_ntp_time_ms_;
3503 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003504 return 0;
3505}
3506
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003507int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3508 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3509 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003510
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003511 if (enable) {
3512 if (redPayloadtype < 0 || redPayloadtype > 127) {
3513 _engineStatisticsPtr->SetLastError(
3514 VE_PLTYPE_ERROR, kTraceError,
3515 "SetFECStatus() invalid RED payload type");
3516 return -1;
3517 }
3518
3519 if (SetRedPayloadType(redPayloadtype) < 0) {
3520 _engineStatisticsPtr->SetLastError(
3521 VE_CODEC_ERROR, kTraceError,
3522 "SetSecondarySendCodec() Failed to register RED ACM");
3523 return -1;
3524 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003525 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003526
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003527 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003528 _engineStatisticsPtr->SetLastError(
3529 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3530 "SetFECStatus() failed to set FEC state in the ACM");
3531 return -1;
3532 }
3533 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003534}
3535
3536int
3537Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
3538{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003539 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003540 if (enabled)
3541 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003542 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003543 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003544 {
3545 _engineStatisticsPtr->SetLastError(
3546 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3547 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
3548 "module");
3549 return -1;
3550 }
3551 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3552 VoEId(_instanceId, _channelId),
3553 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
3554 enabled, redPayloadtype);
3555 return 0;
3556 }
3557 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3558 VoEId(_instanceId, _channelId),
3559 "GetFECStatus() => enabled=%d", enabled);
3560 return 0;
3561}
3562
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003563void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3564 // None of these functions can fail.
3565 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003566 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3567 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003568 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003569 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003570 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003571 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003572}
3573
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003574// Called when we are missing one or more packets.
3575int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003576 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3577}
3578
niklase@google.com470e71d2011-07-07 08:21:25 +00003579int
niklase@google.com470e71d2011-07-07 08:21:25 +00003580Channel::StartRTPDump(const char fileNameUTF8[1024],
3581 RTPDirections direction)
3582{
3583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3584 "Channel::StartRTPDump()");
3585 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3586 {
3587 _engineStatisticsPtr->SetLastError(
3588 VE_INVALID_ARGUMENT, kTraceError,
3589 "StartRTPDump() invalid RTP direction");
3590 return -1;
3591 }
3592 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3593 &_rtpDumpIn : &_rtpDumpOut;
3594 if (rtpDumpPtr == NULL)
3595 {
3596 assert(false);
3597 return -1;
3598 }
3599 if (rtpDumpPtr->IsActive())
3600 {
3601 rtpDumpPtr->Stop();
3602 }
3603 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3604 {
3605 _engineStatisticsPtr->SetLastError(
3606 VE_BAD_FILE, kTraceError,
3607 "StartRTPDump() failed to create file");
3608 return -1;
3609 }
3610 return 0;
3611}
3612
3613int
3614Channel::StopRTPDump(RTPDirections direction)
3615{
3616 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3617 "Channel::StopRTPDump()");
3618 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3619 {
3620 _engineStatisticsPtr->SetLastError(
3621 VE_INVALID_ARGUMENT, kTraceError,
3622 "StopRTPDump() invalid RTP direction");
3623 return -1;
3624 }
3625 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3626 &_rtpDumpIn : &_rtpDumpOut;
3627 if (rtpDumpPtr == NULL)
3628 {
3629 assert(false);
3630 return -1;
3631 }
3632 if (!rtpDumpPtr->IsActive())
3633 {
3634 return 0;
3635 }
3636 return rtpDumpPtr->Stop();
3637}
3638
3639bool
3640Channel::RTPDumpIsActive(RTPDirections direction)
3641{
3642 if ((direction != kRtpIncoming) &&
3643 (direction != kRtpOutgoing))
3644 {
3645 _engineStatisticsPtr->SetLastError(
3646 VE_INVALID_ARGUMENT, kTraceError,
3647 "RTPDumpIsActive() invalid RTP direction");
3648 return false;
3649 }
3650 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3651 &_rtpDumpIn : &_rtpDumpOut;
3652 return rtpDumpPtr->IsActive();
3653}
3654
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003655void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3656 int video_channel) {
3657 CriticalSectionScoped cs(&_callbackCritSect);
3658 if (vie_network_) {
3659 vie_network_->Release();
3660 vie_network_ = NULL;
3661 }
3662 video_channel_ = -1;
3663
3664 if (vie_network != NULL && video_channel != -1) {
3665 vie_network_ = vie_network;
3666 video_channel_ = video_channel;
3667 }
3668}
3669
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003670uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003671Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003672{
3673 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003674 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003675 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003676 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003677 return 0;
3678}
3679
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003680void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003681 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003682 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003683 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003684 CodecInst codec;
3685 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003686
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003687 if (!mono_recording_audio_.get()) {
3688 // Temporary space for DownConvertToCodecFormat.
3689 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003690 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003691 DownConvertToCodecFormat(audio_data,
3692 number_of_frames,
3693 number_of_channels,
3694 sample_rate,
3695 codec.channels,
3696 codec.plfreq,
3697 mono_recording_audio_.get(),
3698 &input_resampler_,
3699 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003700}
3701
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003702uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003703Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003704{
3705 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3706 "Channel::PrepareEncodeAndSend()");
3707
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003708 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003709 {
3710 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3711 "Channel::PrepareEncodeAndSend() invalid audio frame");
3712 return -1;
3713 }
3714
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003715 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003716 {
3717 MixOrReplaceAudioWithFile(mixingFrequency);
3718 }
3719
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003720 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3721 if (is_muted) {
3722 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003723 }
3724
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003725 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003726 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003727 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003728 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003729 if (_inputExternalMediaCallbackPtr)
3730 {
3731 _inputExternalMediaCallbackPtr->Process(
3732 _channelId,
3733 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003734 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003735 _audioFrame.samples_per_channel_,
3736 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003737 isStereo);
3738 }
3739 }
3740
3741 InsertInbandDtmfTone();
3742
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003743 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003744 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003745 if (is_muted) {
3746 rms_level_.ProcessMuted(length);
3747 } else {
3748 rms_level_.Process(_audioFrame.data_, length);
3749 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003750 }
3751
niklase@google.com470e71d2011-07-07 08:21:25 +00003752 return 0;
3753}
3754
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003755uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003756Channel::EncodeAndSend()
3757{
3758 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3759 "Channel::EncodeAndSend()");
3760
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003761 assert(_audioFrame.num_channels_ <= 2);
3762 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003763 {
3764 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3765 "Channel::EncodeAndSend() invalid audio frame");
3766 return -1;
3767 }
3768
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003769 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003770
3771 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3772
3773 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003774 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003775 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003776 {
3777 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3778 "Channel::EncodeAndSend() ACM encoding failed");
3779 return -1;
3780 }
3781
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003782 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003783
3784 // --- Encode if complete frame is ready
3785
3786 // This call will trigger AudioPacketizationCallback::SendData if encoding
3787 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003788 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003789}
3790
3791int Channel::RegisterExternalMediaProcessing(
3792 ProcessingTypes type,
3793 VoEMediaProcess& processObject)
3794{
3795 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3796 "Channel::RegisterExternalMediaProcessing()");
3797
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003798 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003799
3800 if (kPlaybackPerChannel == type)
3801 {
3802 if (_outputExternalMediaCallbackPtr)
3803 {
3804 _engineStatisticsPtr->SetLastError(
3805 VE_INVALID_OPERATION, kTraceError,
3806 "Channel::RegisterExternalMediaProcessing() "
3807 "output external media already enabled");
3808 return -1;
3809 }
3810 _outputExternalMediaCallbackPtr = &processObject;
3811 _outputExternalMedia = true;
3812 }
3813 else if (kRecordingPerChannel == type)
3814 {
3815 if (_inputExternalMediaCallbackPtr)
3816 {
3817 _engineStatisticsPtr->SetLastError(
3818 VE_INVALID_OPERATION, kTraceError,
3819 "Channel::RegisterExternalMediaProcessing() "
3820 "output external media already enabled");
3821 return -1;
3822 }
3823 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003824 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003825 }
3826 return 0;
3827}
3828
3829int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3830{
3831 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3832 "Channel::DeRegisterExternalMediaProcessing()");
3833
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003834 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003835
3836 if (kPlaybackPerChannel == type)
3837 {
3838 if (!_outputExternalMediaCallbackPtr)
3839 {
3840 _engineStatisticsPtr->SetLastError(
3841 VE_INVALID_OPERATION, kTraceWarning,
3842 "Channel::DeRegisterExternalMediaProcessing() "
3843 "output external media already disabled");
3844 return 0;
3845 }
3846 _outputExternalMedia = false;
3847 _outputExternalMediaCallbackPtr = NULL;
3848 }
3849 else if (kRecordingPerChannel == type)
3850 {
3851 if (!_inputExternalMediaCallbackPtr)
3852 {
3853 _engineStatisticsPtr->SetLastError(
3854 VE_INVALID_OPERATION, kTraceWarning,
3855 "Channel::DeRegisterExternalMediaProcessing() "
3856 "input external media already disabled");
3857 return 0;
3858 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003859 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003860 _inputExternalMediaCallbackPtr = NULL;
3861 }
3862
3863 return 0;
3864}
3865
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003866int Channel::SetExternalMixing(bool enabled) {
3867 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3868 "Channel::SetExternalMixing(enabled=%d)", enabled);
3869
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003870 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003871 {
3872 _engineStatisticsPtr->SetLastError(
3873 VE_INVALID_OPERATION, kTraceError,
3874 "Channel::SetExternalMixing() "
3875 "external mixing cannot be changed while playing.");
3876 return -1;
3877 }
3878
3879 _externalMixing = enabled;
3880
3881 return 0;
3882}
3883
niklase@google.com470e71d2011-07-07 08:21:25 +00003884int
niklase@google.com470e71d2011-07-07 08:21:25 +00003885Channel::GetNetworkStatistics(NetworkStatistics& stats)
3886{
3887 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3888 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003889 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003890 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003891 if (return_value >= 0) {
3892 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3893 }
3894 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003895}
3896
wu@webrtc.org24301a62013-12-13 19:17:43 +00003897void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3898 audio_coding_->GetDecodingCallStatistics(stats);
3899}
3900
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003901bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3902 int* playout_buffer_delay_ms) const {
3903 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003904 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003905 "Channel::GetDelayEstimate() no valid estimate.");
3906 return false;
3907 }
3908 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3909 _recPacketDelayMs;
3910 *playout_buffer_delay_ms = playout_delay_ms_;
3911 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3912 "Channel::GetDelayEstimate()");
3913 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003914}
3915
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003916int Channel::SetInitialPlayoutDelay(int delay_ms)
3917{
3918 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3919 "Channel::SetInitialPlayoutDelay()");
3920 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3921 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3922 {
3923 _engineStatisticsPtr->SetLastError(
3924 VE_INVALID_ARGUMENT, kTraceError,
3925 "SetInitialPlayoutDelay() invalid min delay");
3926 return -1;
3927 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003928 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003929 {
3930 _engineStatisticsPtr->SetLastError(
3931 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3932 "SetInitialPlayoutDelay() failed to set min playout delay");
3933 return -1;
3934 }
3935 return 0;
3936}
3937
3938
niklase@google.com470e71d2011-07-07 08:21:25 +00003939int
3940Channel::SetMinimumPlayoutDelay(int delayMs)
3941{
3942 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3943 "Channel::SetMinimumPlayoutDelay()");
3944 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3945 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3946 {
3947 _engineStatisticsPtr->SetLastError(
3948 VE_INVALID_ARGUMENT, kTraceError,
3949 "SetMinimumPlayoutDelay() invalid min delay");
3950 return -1;
3951 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003952 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003953 {
3954 _engineStatisticsPtr->SetLastError(
3955 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3956 "SetMinimumPlayoutDelay() failed to set min playout delay");
3957 return -1;
3958 }
3959 return 0;
3960}
3961
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003962void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3963 uint32_t playout_timestamp = 0;
3964
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003965 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3967 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3968 " timestamp from the ACM");
3969 _engineStatisticsPtr->SetLastError(
3970 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3971 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
3972 return;
3973 }
3974
3975 uint16_t delay_ms = 0;
3976 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3977 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3978 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3979 " delay from the ADM");
3980 _engineStatisticsPtr->SetLastError(
3981 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3982 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3983 return;
3984 }
3985
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003986 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003987 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003988 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003989 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3990 playout_frequency = 8000;
3991 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3992 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00003993 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003994 }
3995
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003996 jitter_buffer_playout_timestamp_ = playout_timestamp;
3997
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003998 // Remove the playout delay.
3999 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4000
4001 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4002 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4003 playout_timestamp);
4004
4005 if (rtcp) {
4006 playout_timestamp_rtcp_ = playout_timestamp;
4007 } else {
4008 playout_timestamp_rtp_ = playout_timestamp;
4009 }
4010 playout_delay_ms_ = delay_ms;
4011}
4012
4013int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4014 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4015 "Channel::GetPlayoutTimestamp()");
4016 if (playout_timestamp_rtp_ == 0) {
4017 _engineStatisticsPtr->SetLastError(
4018 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4019 "GetPlayoutTimestamp() failed to retrieve timestamp");
4020 return -1;
4021 }
4022 timestamp = playout_timestamp_rtp_;
4023 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4024 VoEId(_instanceId,_channelId),
4025 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4026 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004027}
4028
4029int
4030Channel::SetInitTimestamp(unsigned int timestamp)
4031{
4032 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4033 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004034 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004035 {
4036 _engineStatisticsPtr->SetLastError(
4037 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4038 return -1;
4039 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004040 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004041 {
4042 _engineStatisticsPtr->SetLastError(
4043 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4044 "SetInitTimestamp() failed to set timestamp");
4045 return -1;
4046 }
4047 return 0;
4048}
4049
4050int
4051Channel::SetInitSequenceNumber(short sequenceNumber)
4052{
4053 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4054 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004055 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004056 {
4057 _engineStatisticsPtr->SetLastError(
4058 VE_SENDING, kTraceError,
4059 "SetInitSequenceNumber() already sending");
4060 return -1;
4061 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004062 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004063 {
4064 _engineStatisticsPtr->SetLastError(
4065 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4066 "SetInitSequenceNumber() failed to set sequence number");
4067 return -1;
4068 }
4069 return 0;
4070}
4071
4072int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004073Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004074{
4075 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4076 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004077 *rtpRtcpModule = _rtpRtcpModule.get();
4078 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004079 return 0;
4080}
4081
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004082// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4083// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004084int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004085Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004086{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004087 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004088 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004089
4090 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004091 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004092
4093 if (_inputFilePlayerPtr == NULL)
4094 {
4095 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4096 VoEId(_instanceId, _channelId),
4097 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4098 " doesnt exist");
4099 return -1;
4100 }
4101
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004102 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004103 fileSamples,
4104 mixingFrequency) == -1)
4105 {
4106 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4107 VoEId(_instanceId, _channelId),
4108 "Channel::MixOrReplaceAudioWithFile() file mixing "
4109 "failed");
4110 return -1;
4111 }
4112 if (fileSamples == 0)
4113 {
4114 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4115 VoEId(_instanceId, _channelId),
4116 "Channel::MixOrReplaceAudioWithFile() file is ended");
4117 return 0;
4118 }
4119 }
4120
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004121 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004122
4123 if (_mixFileWithMicrophone)
4124 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004125 // Currently file stream is always mono.
4126 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004127 MixWithSat(_audioFrame.data_,
4128 _audioFrame.num_channels_,
4129 fileBuffer.get(),
4130 1,
4131 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004132 }
4133 else
4134 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004135 // Replace ACM audio with file.
4136 // Currently file stream is always mono.
4137 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004138 _audioFrame.UpdateFrame(_channelId,
4139 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004140 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004141 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004142 mixingFrequency,
4143 AudioFrame::kNormalSpeech,
4144 AudioFrame::kVadUnknown,
4145 1);
4146
4147 }
4148 return 0;
4149}
4150
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004151int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004152Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004153 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004154{
4155 assert(mixingFrequency <= 32000);
4156
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004157 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004158 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004159
4160 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004161 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004162
4163 if (_outputFilePlayerPtr == NULL)
4164 {
4165 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4166 VoEId(_instanceId, _channelId),
4167 "Channel::MixAudioWithFile() file mixing failed");
4168 return -1;
4169 }
4170
4171 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004172 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004173 fileSamples,
4174 mixingFrequency) == -1)
4175 {
4176 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4177 VoEId(_instanceId, _channelId),
4178 "Channel::MixAudioWithFile() file mixing failed");
4179 return -1;
4180 }
4181 }
4182
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004183 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004184 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004185 // Currently file stream is always mono.
4186 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004187 MixWithSat(audioFrame.data_,
4188 audioFrame.num_channels_,
4189 fileBuffer.get(),
4190 1,
4191 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004192 }
4193 else
4194 {
4195 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004196 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004197 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004198 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004199 return -1;
4200 }
4201
4202 return 0;
4203}
4204
4205int
4206Channel::InsertInbandDtmfTone()
4207{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004208 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004209 if (_inbandDtmfQueue.PendingDtmf() &&
4210 !_inbandDtmfGenerator.IsAddingTone() &&
4211 _inbandDtmfGenerator.DelaySinceLastTone() >
4212 kMinTelephoneEventSeparationMs)
4213 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004214 int8_t eventCode(0);
4215 uint16_t lengthMs(0);
4216 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004217
4218 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4219 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4220 if (_playInbandDtmfEvent)
4221 {
4222 // Add tone to output mixer using a reduced length to minimize
4223 // risk of echo.
4224 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4225 attenuationDb);
4226 }
4227 }
4228
4229 if (_inbandDtmfGenerator.IsAddingTone())
4230 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004231 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004232 _inbandDtmfGenerator.GetSampleRate(frequency);
4233
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004234 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004235 {
4236 // Update sample rate of Dtmf tone since the mixing frequency
4237 // has changed.
4238 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004239 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004240 // Reset the tone to be added taking the new sample rate into
4241 // account.
4242 _inbandDtmfGenerator.ResetTone();
4243 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004244
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004245 int16_t toneBuffer[320];
4246 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004247 // Get 10ms tone segment and set time since last tone to zero
4248 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4249 {
4250 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4251 VoEId(_instanceId, _channelId),
4252 "Channel::EncodeAndSend() inserting Dtmf failed");
4253 return -1;
4254 }
4255
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004256 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004257 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004258 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004259 sample++)
4260 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004261 for (int channel = 0;
4262 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004263 channel++)
4264 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004265 const int index = sample * _audioFrame.num_channels_ + channel;
4266 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004267 }
4268 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004269
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004270 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004271 } else
4272 {
4273 // Add 10ms to "delay-since-last-tone" counter
4274 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4275 }
4276 return 0;
4277}
4278
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004279int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004280Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4281{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004282 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004283 if (_transportPtr == NULL)
4284 {
4285 return -1;
4286 }
4287 if (!RTCP)
4288 {
4289 return _transportPtr->SendPacket(_channelId, data, len);
4290 }
4291 else
4292 {
4293 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4294 }
4295}
4296
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004297// Called for incoming RTP packets after successful RTP header parsing.
4298void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4299 uint16_t sequence_number) {
4300 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4301 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4302 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004303
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004304 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004305 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004306
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004307 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004308 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004309 return;
4310 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004311
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004312 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004313 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004314
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004315 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4316 // Even though the actual sampling rate for G.722 audio is
4317 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4318 // 8,000 Hz because that value was erroneously assigned in
4319 // RFC 1890 and must remain unchanged for backward compatibility.
4320 rtp_receive_frequency = 8000;
4321 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4322 // We are resampling Opus internally to 32,000 Hz until all our
4323 // DSP routines can operate at 48,000 Hz, but the RTP clock
4324 // rate for the Opus payload format is standardized to 48,000 Hz,
4325 // because that is the maximum supported decoding sampling rate.
4326 rtp_receive_frequency = 48000;
4327 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004328
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004329 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4330 // every incoming packet.
4331 uint32_t timestamp_diff_ms = (rtp_timestamp -
4332 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004333 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4334 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4335 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4336 // timestamp, the resulting difference is negative, but is set to zero.
4337 // This can happen when a network glitch causes a packet to arrive late,
4338 // and during long comfort noise periods with clock drift.
4339 timestamp_diff_ms = 0;
4340 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004341
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004342 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4343 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004344
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004345 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004346
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004347 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004348
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004349 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4350 _recPacketDelayMs = packet_delay_ms;
4351 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004352
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004353 if (_average_jitter_buffer_delay_us == 0) {
4354 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4355 return;
4356 }
4357
4358 // Filter average delay value using exponential filter (alpha is
4359 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4360 // risk of rounding error) and compensate for it in GetDelayEstimate()
4361 // later.
4362 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4363 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004364}
4365
4366void
4367Channel::RegisterReceiveCodecsToRTPModule()
4368{
4369 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4370 "Channel::RegisterReceiveCodecsToRTPModule()");
4371
4372
4373 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004374 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004375
4376 for (int idx = 0; idx < nSupportedCodecs; idx++)
4377 {
4378 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004379 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004380 (rtp_receiver_->RegisterReceivePayload(
4381 codec.plname,
4382 codec.pltype,
4383 codec.plfreq,
4384 codec.channels,
4385 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004386 {
4387 WEBRTC_TRACE(
4388 kTraceWarning,
4389 kTraceVoice,
4390 VoEId(_instanceId, _channelId),
4391 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4392 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4393 codec.plname, codec.pltype, codec.plfreq,
4394 codec.channels, codec.rate);
4395 }
4396 else
4397 {
4398 WEBRTC_TRACE(
4399 kTraceInfo,
4400 kTraceVoice,
4401 VoEId(_instanceId, _channelId),
4402 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004403 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004404 "receiver",
4405 codec.plname, codec.pltype, codec.plfreq,
4406 codec.channels, codec.rate);
4407 }
4408 }
4409}
4410
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004411int Channel::SetSecondarySendCodec(const CodecInst& codec,
4412 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004413 // Sanity check for payload type.
4414 if (red_payload_type < 0 || red_payload_type > 127) {
4415 _engineStatisticsPtr->SetLastError(
4416 VE_PLTYPE_ERROR, kTraceError,
4417 "SetRedPayloadType() invalid RED payload type");
4418 return -1;
4419 }
4420
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004421 if (SetRedPayloadType(red_payload_type) < 0) {
4422 _engineStatisticsPtr->SetLastError(
4423 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4424 "SetSecondarySendCodec() Failed to register RED ACM");
4425 return -1;
4426 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004427 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004428 _engineStatisticsPtr->SetLastError(
4429 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4430 "SetSecondarySendCodec() Failed to register secondary send codec in "
4431 "ACM");
4432 return -1;
4433 }
4434
4435 return 0;
4436}
4437
4438void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004439 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004440}
4441
4442int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004443 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004444 _engineStatisticsPtr->SetLastError(
4445 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4446 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4447 return -1;
4448 }
4449 return 0;
4450}
4451
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004452// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004453int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004454 CodecInst codec;
4455 bool found_red = false;
4456
4457 // Get default RED settings from the ACM database
4458 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4459 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004460 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004461 if (!STR_CASE_CMP(codec.plname, "RED")) {
4462 found_red = true;
4463 break;
4464 }
4465 }
4466
4467 if (!found_red) {
4468 _engineStatisticsPtr->SetLastError(
4469 VE_CODEC_ERROR, kTraceError,
4470 "SetRedPayloadType() RED is not supported");
4471 return -1;
4472 }
4473
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004474 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004475 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004476 _engineStatisticsPtr->SetLastError(
4477 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4478 "SetRedPayloadType() RED registration in ACM module failed");
4479 return -1;
4480 }
4481
4482 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4483 _engineStatisticsPtr->SetLastError(
4484 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4485 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4486 return -1;
4487 }
4488 return 0;
4489}
4490
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004491int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4492 unsigned char id) {
4493 int error = 0;
4494 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4495 if (enable) {
4496 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4497 }
4498 return error;
4499}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004500} // namespace voe
4501} // namespace webrtc