blob: f919c3d09f1ebc175e8a71be7584e104fa107734 [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
667 return 0;
668}
669
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000670int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000671Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000672{
673 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
674 "Channel::NeededFrequency(id=%d)", id);
675
676 int highestNeeded = 0;
677
678 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000679 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000680
681 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000682 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000683 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000684 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000685 }
686 else
687 {
688 highestNeeded = receiveFrequency;
689 }
690
691 // Special case, if we're playing a file on the playout side
692 // we take that frequency into consideration as well
693 // This is not needed on sending side, since the codec will
694 // limit the spectrum anyway.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000695 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000697 CriticalSectionScoped cs(&_fileCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000698 if (_outputFilePlayerPtr)
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 {
700 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
701 {
702 highestNeeded=_outputFilePlayerPtr->Frequency();
703 }
704 }
705 }
706
707 return(highestNeeded);
708}
709
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000710int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000711Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000712 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000713 uint32_t instanceId,
714 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000715{
716 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
717 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
718 channelId, instanceId);
719
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000720 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000721 if (channel == NULL)
722 {
723 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
724 VoEId(instanceId,channelId),
725 "Channel::CreateChannel() unable to allocate memory for"
726 " channel");
727 return -1;
728 }
729 return 0;
730}
731
732void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000733Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000734{
735 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
736 "Channel::PlayNotification(id=%d, durationMs=%d)",
737 id, durationMs);
738
739 // Not implement yet
740}
741
742void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000743Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000744{
745 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
746 "Channel::RecordNotification(id=%d, durationMs=%d)",
747 id, durationMs);
748
749 // Not implement yet
750}
751
752void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000753Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000754{
755 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
756 "Channel::PlayFileEnded(id=%d)", id);
757
758 if (id == _inputFilePlayerId)
759 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000760 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
762 VoEId(_instanceId,_channelId),
763 "Channel::PlayFileEnded() => input file player module is"
764 " shutdown");
765 }
766 else if (id == _outputFilePlayerId)
767 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000768 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000769 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
770 VoEId(_instanceId,_channelId),
771 "Channel::PlayFileEnded() => output file player module is"
772 " shutdown");
773 }
774}
775
776void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000777Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000778{
779 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
780 "Channel::RecordFileEnded(id=%d)", id);
781
782 assert(id == _outputFileRecorderId);
783
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000784 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000785
786 _outputFileRecording = false;
787 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
788 VoEId(_instanceId,_channelId),
789 "Channel::RecordFileEnded() => output file recorder module is"
790 " shutdown");
791}
792
pbos@webrtc.org92135212013-05-14 08:31:39 +0000793Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000794 uint32_t instanceId,
795 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000796 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
797 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000798 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000800 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000801 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000802 rtp_payload_registry_(
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000803 new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(true))),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000804 rtp_receive_statistics_(ReceiveStatistics::Create(
805 Clock::GetRealTimeClock())),
806 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
807 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
808 this, this, rtp_payload_registry_.get())),
809 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
henrik.lundin@webrtc.org34fe0152014-04-22 19:04:34 +0000810 audio_coding_(AudioCodingModule::Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000811 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 _rtpDumpIn(*RtpDump::CreateRtpDump()),
813 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000814 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000815 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000816 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 _inputFilePlayerPtr(NULL),
818 _outputFilePlayerPtr(NULL),
819 _outputFileRecorderPtr(NULL),
820 // Avoid conflict with other channels by adding 1024 - 1026,
821 // won't use as much as 1024 channels.
822 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
823 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
824 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000826 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
827 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
xians@google.com22963ab2011-08-03 12:40:23 +0000828 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000829 _inputExternalMediaCallbackPtr(NULL),
830 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000831 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
832 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000833 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000834 playout_timestamp_rtp_(0),
835 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000836 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000837 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000838 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000839 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000840 _outputMixerPtr(NULL),
841 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000842 _moduleProcessThreadPtr(NULL),
843 _audioDeviceModulePtr(NULL),
844 _voiceEngineObserverPtr(NULL),
845 _callbackCritSectPtr(NULL),
846 _transportPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000847 _rxVadObserverPtr(NULL),
848 _oldVadDecision(-1),
849 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000851 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000852 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000853 _mixFileWithMicrophone(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000854 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000855 _mute(false),
856 _panLeft(1.0f),
857 _panRight(1.0f),
858 _outputGain(1.0f),
859 _playOutbandDtmfEvent(false),
860 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000861 _lastLocalTimeStamp(0),
862 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000863 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000864 _rtpPacketTimedOut(false),
865 _rtpPacketTimeOutIsEnabled(false),
866 _rtpTimeOutSeconds(0),
867 _connectionObserver(false),
868 _connectionObserverPtr(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +0000869 _outputSpeechType(AudioFrame::kNormalSpeech),
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000870 vie_network_(NULL),
871 video_channel_(-1),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000872 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +0000873 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000874 _previousTimestamp(0),
875 _recPacketDelayMs(20),
876 _RxVadDetection(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000877 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000878 _rxNsIsEnabled(false),
879 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +0000880{
881 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
882 "Channel::Channel() - ctor");
883 _inbandDtmfQueue.ResetDtmf();
884 _inbandDtmfGenerator.Init();
885 _outputAudioLevel.Clear();
886
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000887 RtpRtcp::Configuration configuration;
888 configuration.id = VoEModuleId(instanceId, channelId);
889 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000890 configuration.outgoing_transport = this;
891 configuration.rtcp_feedback = this;
892 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000893 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000894
895 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000896
897 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
898 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
899 statistics_proxy_.get());
aluebs@webrtc.orgf927fd62014-04-16 11:58:18 +0000900
901 Config audioproc_config;
902 audioproc_config.Set<ExperimentalAgc>(new ExperimentalAgc(false));
903 rx_audioproc_.reset(AudioProcessing::Create(audioproc_config));
niklase@google.com470e71d2011-07-07 08:21:25 +0000904}
905
906Channel::~Channel()
907{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000908 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000909 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
910 "Channel::~Channel() - dtor");
911
912 if (_outputExternalMedia)
913 {
914 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
915 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000916 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 {
918 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
919 }
920 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000921 StopPlayout();
922
923 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000924 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000925 if (_inputFilePlayerPtr)
926 {
927 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
928 _inputFilePlayerPtr->StopPlayingFile();
929 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
930 _inputFilePlayerPtr = NULL;
931 }
932 if (_outputFilePlayerPtr)
933 {
934 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
935 _outputFilePlayerPtr->StopPlayingFile();
936 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
937 _outputFilePlayerPtr = NULL;
938 }
939 if (_outputFileRecorderPtr)
940 {
941 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
942 _outputFileRecorderPtr->StopRecording();
943 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
944 _outputFileRecorderPtr = NULL;
945 }
946 }
947
948 // The order to safely shutdown modules in a channel is:
949 // 1. De-register callbacks in modules
950 // 2. De-register modules in process thread
951 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000952 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000953 {
954 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
955 VoEId(_instanceId,_channelId),
956 "~Channel() failed to de-register transport callback"
957 " (Audio coding module)");
958 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000959 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000960 {
961 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
962 VoEId(_instanceId,_channelId),
963 "~Channel() failed to de-register VAD callback"
964 " (Audio coding module)");
965 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000967 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000968 {
969 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
970 VoEId(_instanceId,_channelId),
971 "~Channel() failed to deregister RTP/RTCP module");
972 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000973 // End of modules shutdown
974
975 // Delete other objects
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +0000976 if (vie_network_) {
977 vie_network_->Release();
978 vie_network_ = NULL;
979 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000980 RtpDump::DestroyRtpDump(&_rtpDumpIn);
981 RtpDump::DestroyRtpDump(&_rtpDumpOut);
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +0000983 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +0000984 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000985}
986
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000987int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000988Channel::Init()
989{
990 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
991 "Channel::Init()");
992
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +0000993 channel_state_.Reset();
994
niklase@google.com470e71d2011-07-07 08:21:25 +0000995 // --- Initial sanity
996
997 if ((_engineStatisticsPtr == NULL) ||
998 (_moduleProcessThreadPtr == NULL))
999 {
1000 WEBRTC_TRACE(kTraceError, kTraceVoice,
1001 VoEId(_instanceId,_channelId),
1002 "Channel::Init() must call SetEngineInformation() first");
1003 return -1;
1004 }
1005
1006 // --- Add modules to process thread (for periodic schedulation)
1007
1008 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001009 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001010 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001011 if (processThreadFail)
1012 {
1013 _engineStatisticsPtr->SetLastError(
1014 VE_CANNOT_INIT_CHANNEL, kTraceError,
1015 "Channel::Init() modules not registered");
1016 return -1;
1017 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001018 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001019
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001020 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001021#ifdef WEBRTC_CODEC_AVT
1022 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001023 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001024#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001025 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001026 {
1027 _engineStatisticsPtr->SetLastError(
1028 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1029 "Channel::Init() unable to initialize the ACM - 1");
1030 return -1;
1031 }
1032
1033 // --- RTP/RTCP module initialization
1034
1035 // Ensure that RTCP is enabled by default for the created channel.
1036 // Note that, the module will keep generating RTCP until it is explicitly
1037 // disabled by the user.
1038 // After StopListen (when no sockets exists), RTCP packets will no longer
1039 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001040 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1041 // RTCP is enabled by default.
1042 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 {
1044 _engineStatisticsPtr->SetLastError(
1045 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1046 "Channel::Init() RTP/RTCP module not initialized");
1047 return -1;
1048 }
1049
1050 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001051 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001052 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1053 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
1055 if (fail)
1056 {
1057 _engineStatisticsPtr->SetLastError(
1058 VE_CANNOT_INIT_CHANNEL, kTraceError,
1059 "Channel::Init() callbacks not registered");
1060 return -1;
1061 }
1062
1063 // --- Register all supported codecs to the receiving side of the
1064 // RTP/RTCP module
1065
1066 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001067 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001068
1069 for (int idx = 0; idx < nSupportedCodecs; idx++)
1070 {
1071 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001072 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001073 (rtp_receiver_->RegisterReceivePayload(
1074 codec.plname,
1075 codec.pltype,
1076 codec.plfreq,
1077 codec.channels,
1078 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001079 {
1080 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1081 VoEId(_instanceId,_channelId),
1082 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1083 "to RTP/RTCP receiver",
1084 codec.plname, codec.pltype, codec.plfreq,
1085 codec.channels, codec.rate);
1086 }
1087 else
1088 {
1089 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1090 VoEId(_instanceId,_channelId),
1091 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1092 "the RTP/RTCP receiver",
1093 codec.plname, codec.pltype, codec.plfreq,
1094 codec.channels, codec.rate);
1095 }
1096
1097 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001098 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 {
1100 SetSendCodec(codec);
1101 }
1102
1103 // Register default PT for outband 'telephone-event'
1104 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1105 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001106 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001107 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001108 {
1109 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1110 VoEId(_instanceId,_channelId),
1111 "Channel::Init() failed to register outband "
1112 "'telephone-event' (%d/%d) correctly",
1113 codec.pltype, codec.plfreq);
1114 }
1115 }
1116
1117 if (!STR_CASE_CMP(codec.plname, "CN"))
1118 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001119 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1120 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001121 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001122 {
1123 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1124 VoEId(_instanceId,_channelId),
1125 "Channel::Init() failed to register CN (%d/%d) "
1126 "correctly - 1",
1127 codec.pltype, codec.plfreq);
1128 }
1129 }
1130#ifdef WEBRTC_CODEC_RED
1131 // Register RED to the receiving side of the ACM.
1132 // We will not receive an OnInitializeDecoder() callback for RED.
1133 if (!STR_CASE_CMP(codec.plname, "RED"))
1134 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001135 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001136 {
1137 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1138 VoEId(_instanceId,_channelId),
1139 "Channel::Init() failed to register RED (%d/%d) "
1140 "correctly",
1141 codec.pltype, codec.plfreq);
1142 }
1143 }
1144#endif
1145 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001146
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001147 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1148 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1149 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001150 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001151 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1152 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1153 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001154 }
1155
1156 return 0;
1157}
1158
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001159int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001160Channel::SetEngineInformation(Statistics& engineStatistics,
1161 OutputMixer& outputMixer,
1162 voe::TransmitMixer& transmitMixer,
1163 ProcessThread& moduleProcessThread,
1164 AudioDeviceModule& audioDeviceModule,
1165 VoiceEngineObserver* voiceEngineObserver,
1166 CriticalSectionWrapper* callbackCritSect)
1167{
1168 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1169 "Channel::SetEngineInformation()");
1170 _engineStatisticsPtr = &engineStatistics;
1171 _outputMixerPtr = &outputMixer;
1172 _transmitMixerPtr = &transmitMixer,
1173 _moduleProcessThreadPtr = &moduleProcessThread;
1174 _audioDeviceModulePtr = &audioDeviceModule;
1175 _voiceEngineObserverPtr = voiceEngineObserver;
1176 _callbackCritSectPtr = callbackCritSect;
1177 return 0;
1178}
1179
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001180int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001181Channel::UpdateLocalTimeStamp()
1182{
1183
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001184 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 return 0;
1186}
1187
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001188int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001189Channel::StartPlayout()
1190{
1191 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1192 "Channel::StartPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001193 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 {
1195 return 0;
1196 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001197
1198 if (!_externalMixing) {
1199 // Add participant as candidates for mixing.
1200 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1201 {
1202 _engineStatisticsPtr->SetLastError(
1203 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1204 "StartPlayout() failed to add participant to mixer");
1205 return -1;
1206 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001207 }
1208
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001209 channel_state_.SetPlaying(true);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001210 if (RegisterFilePlayingToMixer() != 0)
1211 return -1;
1212
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 return 0;
1214}
1215
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001216int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001217Channel::StopPlayout()
1218{
1219 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1220 "Channel::StopPlayout()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001221 if (!channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 {
1223 return 0;
1224 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001225
1226 if (!_externalMixing) {
1227 // Remove participant as candidates for mixing
1228 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1229 {
1230 _engineStatisticsPtr->SetLastError(
1231 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1232 "StopPlayout() failed to remove participant from mixer");
1233 return -1;
1234 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 }
1236
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001237 channel_state_.SetPlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001238 _outputAudioLevel.Clear();
1239
1240 return 0;
1241}
1242
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001243int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001244Channel::StartSend()
1245{
1246 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1247 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001248 // Resume the previous sequence number which was reset by StopSend().
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001249 // This needs to be done before |sending| is set to true.
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001250 if (send_sequence_number_)
1251 SetInitSequenceNumber(send_sequence_number_);
1252
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001253 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001254 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001255 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001256 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001257 channel_state_.SetSending(true);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001258
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001259 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 {
1261 _engineStatisticsPtr->SetLastError(
1262 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1263 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001264 CriticalSectionScoped cs(&_callbackCritSect);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001265 channel_state_.SetSending(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001266 return -1;
1267 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001268
niklase@google.com470e71d2011-07-07 08:21:25 +00001269 return 0;
1270}
1271
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001272int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001273Channel::StopSend()
1274{
1275 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1276 "Channel::StopSend()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001277 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001279 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001281 channel_state_.SetSending(false);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001282
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001283 // Store the sequence number to be able to pick up the same sequence for
1284 // the next StartSend(). This is needed for restarting device, otherwise
1285 // it might cause libSRTP to complain about packets being replayed.
1286 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1287 // CL is landed. See issue
1288 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1289 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1290
niklase@google.com470e71d2011-07-07 08:21:25 +00001291 // Reset sending SSRC and sequence number and triggers direct transmission
1292 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001293 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1294 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 {
1296 _engineStatisticsPtr->SetLastError(
1297 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1298 "StartSend() RTP/RTCP failed to stop sending");
1299 }
1300
niklase@google.com470e71d2011-07-07 08:21:25 +00001301 return 0;
1302}
1303
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001304int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001305Channel::StartReceiving()
1306{
1307 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1308 "Channel::StartReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001309 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001310 {
1311 return 0;
1312 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001313 channel_state_.SetReceiving(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001314 _numberOfDiscardedPackets = 0;
1315 return 0;
1316}
1317
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001318int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001319Channel::StopReceiving()
1320{
1321 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1322 "Channel::StopReceiving()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001323 if (!channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001324 {
1325 return 0;
1326 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001327
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001328 channel_state_.SetReceiving(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001329 return 0;
1330}
1331
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001332int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001333Channel::SetNetEQPlayoutMode(NetEqModes mode)
1334{
1335 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1336 "Channel::SetNetEQPlayoutMode()");
1337 AudioPlayoutMode playoutMode(voice);
1338 switch (mode)
1339 {
1340 case kNetEqDefault:
1341 playoutMode = voice;
1342 break;
1343 case kNetEqStreaming:
1344 playoutMode = streaming;
1345 break;
1346 case kNetEqFax:
1347 playoutMode = fax;
1348 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001349 case kNetEqOff:
1350 playoutMode = off;
1351 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001352 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001353 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001354 {
1355 _engineStatisticsPtr->SetLastError(
1356 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1357 "SetNetEQPlayoutMode() failed to set playout mode");
1358 return -1;
1359 }
1360 return 0;
1361}
1362
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001363int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001364Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1365{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001366 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001367 switch (playoutMode)
1368 {
1369 case voice:
1370 mode = kNetEqDefault;
1371 break;
1372 case streaming:
1373 mode = kNetEqStreaming;
1374 break;
1375 case fax:
1376 mode = kNetEqFax;
1377 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001378 case off:
1379 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001380 }
1381 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1382 VoEId(_instanceId,_channelId),
1383 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1384 return 0;
1385}
1386
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001387int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001388Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1389{
1390 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1391 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001392 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001393
1394 if (_voiceEngineObserverPtr)
1395 {
1396 _engineStatisticsPtr->SetLastError(
1397 VE_INVALID_OPERATION, kTraceError,
1398 "RegisterVoiceEngineObserver() observer already enabled");
1399 return -1;
1400 }
1401 _voiceEngineObserverPtr = &observer;
1402 return 0;
1403}
1404
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001405int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001406Channel::DeRegisterVoiceEngineObserver()
1407{
1408 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1409 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001410 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001411
1412 if (!_voiceEngineObserverPtr)
1413 {
1414 _engineStatisticsPtr->SetLastError(
1415 VE_INVALID_OPERATION, kTraceWarning,
1416 "DeRegisterVoiceEngineObserver() observer already disabled");
1417 return 0;
1418 }
1419 _voiceEngineObserverPtr = NULL;
1420 return 0;
1421}
1422
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001423int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001424Channel::GetSendCodec(CodecInst& codec)
1425{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001426 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001427}
1428
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001429int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001430Channel::GetRecCodec(CodecInst& codec)
1431{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001432 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001433}
1434
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001435int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001436Channel::SetSendCodec(const CodecInst& codec)
1437{
1438 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1439 "Channel::SetSendCodec()");
1440
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001441 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001442 {
1443 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1444 "SetSendCodec() failed to register codec to ACM");
1445 return -1;
1446 }
1447
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001448 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001449 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001450 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1451 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001452 {
1453 WEBRTC_TRACE(
1454 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1455 "SetSendCodec() failed to register codec to"
1456 " RTP/RTCP module");
1457 return -1;
1458 }
1459 }
1460
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001461 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 {
1463 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1464 "SetSendCodec() failed to set audio packet size");
1465 return -1;
1466 }
1467
1468 return 0;
1469}
1470
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001471int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001472Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1473{
1474 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1475 "Channel::SetVADStatus(mode=%d)", mode);
1476 // To disable VAD, DTX must be disabled too
1477 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001478 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001479 {
1480 _engineStatisticsPtr->SetLastError(
1481 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1482 "SetVADStatus() failed to set VAD");
1483 return -1;
1484 }
1485 return 0;
1486}
1487
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001488int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001489Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1490{
1491 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1492 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001493 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001494 {
1495 _engineStatisticsPtr->SetLastError(
1496 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1497 "GetVADStatus() failed to get VAD status");
1498 return -1;
1499 }
1500 disabledDTX = !disabledDTX;
1501 return 0;
1502}
1503
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001504int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001505Channel::SetRecPayloadType(const CodecInst& codec)
1506{
1507 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1508 "Channel::SetRecPayloadType()");
1509
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001510 if (channel_state_.Get().playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001511 {
1512 _engineStatisticsPtr->SetLastError(
1513 VE_ALREADY_PLAYING, kTraceError,
1514 "SetRecPayloadType() unable to set PT while playing");
1515 return -1;
1516 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001517 if (channel_state_.Get().receiving)
niklase@google.com470e71d2011-07-07 08:21:25 +00001518 {
1519 _engineStatisticsPtr->SetLastError(
1520 VE_ALREADY_LISTENING, kTraceError,
1521 "SetRecPayloadType() unable to set PT while listening");
1522 return -1;
1523 }
1524
1525 if (codec.pltype == -1)
1526 {
1527 // De-register the selected codec (RTP/RTCP module and ACM)
1528
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001529 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001530 CodecInst rxCodec = codec;
1531
1532 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001533 rtp_payload_registry_->ReceivePayloadType(
1534 rxCodec.plname,
1535 rxCodec.plfreq,
1536 rxCodec.channels,
1537 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1538 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001539 rxCodec.pltype = pltype;
1540
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001541 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001542 {
1543 _engineStatisticsPtr->SetLastError(
1544 VE_RTP_RTCP_MODULE_ERROR,
1545 kTraceError,
1546 "SetRecPayloadType() RTP/RTCP-module deregistration "
1547 "failed");
1548 return -1;
1549 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001550 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001551 {
1552 _engineStatisticsPtr->SetLastError(
1553 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1554 "SetRecPayloadType() ACM deregistration failed - 1");
1555 return -1;
1556 }
1557 return 0;
1558 }
1559
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001560 if (rtp_receiver_->RegisterReceivePayload(
1561 codec.plname,
1562 codec.pltype,
1563 codec.plfreq,
1564 codec.channels,
1565 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001566 {
1567 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001568 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1569 if (rtp_receiver_->RegisterReceivePayload(
1570 codec.plname,
1571 codec.pltype,
1572 codec.plfreq,
1573 codec.channels,
1574 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001575 {
1576 _engineStatisticsPtr->SetLastError(
1577 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1578 "SetRecPayloadType() RTP/RTCP-module registration failed");
1579 return -1;
1580 }
1581 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001582 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001583 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001584 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1585 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001586 {
1587 _engineStatisticsPtr->SetLastError(
1588 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1589 "SetRecPayloadType() ACM registration failed - 1");
1590 return -1;
1591 }
1592 }
1593 return 0;
1594}
1595
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001596int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001597Channel::GetRecPayloadType(CodecInst& codec)
1598{
1599 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1600 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001601 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001602 if (rtp_payload_registry_->ReceivePayloadType(
1603 codec.plname,
1604 codec.plfreq,
1605 codec.channels,
1606 (codec.rate < 0) ? 0 : codec.rate,
1607 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001608 {
1609 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001610 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001611 "GetRecPayloadType() failed to retrieve RX payload type");
1612 return -1;
1613 }
1614 codec.pltype = payloadType;
1615 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1616 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1617 return 0;
1618}
1619
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001620int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001621Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1622{
1623 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1624 "Channel::SetSendCNPayloadType()");
1625
1626 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001627 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001628 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001629 if (frequency == kFreq32000Hz)
1630 samplingFreqHz = 32000;
1631 else if (frequency == kFreq16000Hz)
1632 samplingFreqHz = 16000;
1633
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001634 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001635 {
1636 _engineStatisticsPtr->SetLastError(
1637 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1638 "SetSendCNPayloadType() failed to retrieve default CN codec "
1639 "settings");
1640 return -1;
1641 }
1642
1643 // Modify the payload type (must be set to dynamic range)
1644 codec.pltype = type;
1645
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001646 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001647 {
1648 _engineStatisticsPtr->SetLastError(
1649 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1650 "SetSendCNPayloadType() failed to register CN to ACM");
1651 return -1;
1652 }
1653
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001654 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001655 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001656 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1657 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001658 {
1659 _engineStatisticsPtr->SetLastError(
1660 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1661 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1662 "module");
1663 return -1;
1664 }
1665 }
1666 return 0;
1667}
1668
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001669int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00001670{
1671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
1672 "Channel::RegisterExternalTransport()");
1673
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001674 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001675
niklase@google.com470e71d2011-07-07 08:21:25 +00001676 if (_externalTransport)
1677 {
1678 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
1679 kTraceError,
1680 "RegisterExternalTransport() external transport already enabled");
1681 return -1;
1682 }
1683 _externalTransport = true;
1684 _transportPtr = &transport;
1685 return 0;
1686}
1687
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001688int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001689Channel::DeRegisterExternalTransport()
1690{
1691 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1692 "Channel::DeRegisterExternalTransport()");
1693
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001694 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00001695
niklase@google.com470e71d2011-07-07 08:21:25 +00001696 if (!_transportPtr)
1697 {
1698 _engineStatisticsPtr->SetLastError(
1699 VE_INVALID_OPERATION, kTraceWarning,
1700 "DeRegisterExternalTransport() external transport already "
1701 "disabled");
1702 return 0;
1703 }
1704 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001705 _transportPtr = NULL;
1706 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1707 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00001708 return 0;
1709}
1710
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001711int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length,
1712 const PacketTime& packet_time) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001713 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1714 "Channel::ReceivedRTPPacket()");
1715
1716 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001717 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001718
1719 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001720 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1721 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001722 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1723 VoEId(_instanceId,_channelId),
1724 "Channel::SendPacket() RTP dump to input file failed");
1725 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001726 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001727 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001728 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
1729 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1730 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001731 return -1;
1732 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001733 header.payload_type_frequency =
1734 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001735 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001736 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001737 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001738 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001739 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001740 rtp_payload_registry_->SetIncomingPayloadType(header);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00001741
1742 // Forward any packets to ViE bandwidth estimator, if enabled.
1743 {
1744 CriticalSectionScoped cs(&_callbackCritSect);
1745 if (vie_network_) {
1746 int64_t arrival_time_ms;
1747 if (packet_time.timestamp != -1) {
1748 arrival_time_ms = (packet_time.timestamp + 500) / 1000;
1749 } else {
1750 arrival_time_ms = TickTime::MillisecondTimestamp();
1751 }
1752 int payload_length = length - header.headerLength;
1753 vie_network_->ReceivedBWEPacket(video_channel_, arrival_time_ms,
1754 payload_length, header);
1755 }
1756 }
1757
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001758 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001759}
1760
1761bool Channel::ReceivePacket(const uint8_t* packet,
1762 int packet_length,
1763 const RTPHeader& header,
1764 bool in_order) {
1765 if (rtp_payload_registry_->IsEncapsulated(header)) {
1766 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001767 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001768 const uint8_t* payload = packet + header.headerLength;
1769 int payload_length = packet_length - header.headerLength;
1770 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001771 PayloadUnion payload_specific;
1772 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001773 &payload_specific)) {
1774 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001775 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001776 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
1777 payload_specific, in_order);
1778}
1779
1780bool Channel::HandleEncapsulation(const uint8_t* packet,
1781 int packet_length,
1782 const RTPHeader& header) {
1783 if (!rtp_payload_registry_->IsRtx(header))
1784 return false;
1785
1786 // Remove the RTX header and parse the original RTP header.
1787 if (packet_length < header.headerLength)
1788 return false;
1789 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
1790 return false;
1791 if (restored_packet_in_use_) {
1792 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1793 "Multiple RTX headers detected, dropping packet");
1794 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001795 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001796 uint8_t* restored_packet_ptr = restored_packet_;
1797 if (!rtp_payload_registry_->RestoreOriginalPacket(
1798 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
1799 header)) {
1800 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
1801 "Incoming RTX packet: invalid RTP header");
1802 return false;
1803 }
1804 restored_packet_in_use_ = true;
1805 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
1806 restored_packet_in_use_ = false;
1807 return ret;
1808}
1809
1810bool Channel::IsPacketInOrder(const RTPHeader& header) const {
1811 StreamStatistician* statistician =
1812 rtp_receive_statistics_->GetStatistician(header.ssrc);
1813 if (!statistician)
1814 return false;
1815 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00001816}
1817
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001818bool Channel::IsPacketRetransmitted(const RTPHeader& header,
1819 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001820 // Retransmissions are handled separately if RTX is enabled.
1821 if (rtp_payload_registry_->RtxEnabled())
1822 return false;
1823 StreamStatistician* statistician =
1824 rtp_receive_statistics_->GetStatistician(header.ssrc);
1825 if (!statistician)
1826 return false;
1827 // Check if this is a retransmission.
1828 uint16_t min_rtt = 0;
1829 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00001830 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001831 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001832}
1833
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001834int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001835 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
1836 "Channel::ReceivedRTCPPacket()");
1837 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001838 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001839
1840 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001841 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
1842 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001843 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1844 VoEId(_instanceId,_channelId),
1845 "Channel::SendPacket() RTCP dump to input file failed");
1846 }
1847
1848 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00001849 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
1850 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00001851 _engineStatisticsPtr->SetLastError(
1852 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
1853 "Channel::IncomingRTPPacket() RTCP packet is invalid");
1854 }
1855 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001856}
1857
niklase@google.com470e71d2011-07-07 08:21:25 +00001858int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001859 bool loop,
1860 FileFormats format,
1861 int startPosition,
1862 float volumeScaling,
1863 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001864 const CodecInst* codecInst)
1865{
1866 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1867 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
1868 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
1869 "stopPosition=%d)", fileName, loop, format, volumeScaling,
1870 startPosition, stopPosition);
1871
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001872 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_ALREADY_PLAYING, kTraceError,
1876 "StartPlayingFileLocally() is already playing");
1877 return -1;
1878 }
1879
niklase@google.com470e71d2011-07-07 08:21:25 +00001880 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001881 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001882
1883 if (_outputFilePlayerPtr)
1884 {
1885 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1886 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1887 _outputFilePlayerPtr = NULL;
1888 }
1889
1890 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1891 _outputFilePlayerId, (const FileFormats)format);
1892
1893 if (_outputFilePlayerPtr == NULL)
1894 {
1895 _engineStatisticsPtr->SetLastError(
1896 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00001897 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001898 return -1;
1899 }
1900
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001901 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001902
1903 if (_outputFilePlayerPtr->StartPlayingFile(
1904 fileName,
1905 loop,
1906 startPosition,
1907 volumeScaling,
1908 notificationTime,
1909 stopPosition,
1910 (const CodecInst*)codecInst) != 0)
1911 {
1912 _engineStatisticsPtr->SetLastError(
1913 VE_BAD_FILE, kTraceError,
1914 "StartPlayingFile() failed to start file playout");
1915 _outputFilePlayerPtr->StopPlayingFile();
1916 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1917 _outputFilePlayerPtr = NULL;
1918 return -1;
1919 }
1920 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001921 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001922 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001923
1924 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00001925 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001926
1927 return 0;
1928}
1929
1930int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00001931 FileFormats format,
1932 int startPosition,
1933 float volumeScaling,
1934 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00001935 const CodecInst* codecInst)
1936{
1937 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1938 "Channel::StartPlayingFileLocally(format=%d,"
1939 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
1940 format, volumeScaling, startPosition, stopPosition);
1941
1942 if(stream == NULL)
1943 {
1944 _engineStatisticsPtr->SetLastError(
1945 VE_BAD_FILE, kTraceError,
1946 "StartPlayingFileLocally() NULL as input stream");
1947 return -1;
1948 }
1949
1950
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001951 if (channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00001952 {
1953 _engineStatisticsPtr->SetLastError(
1954 VE_ALREADY_PLAYING, kTraceError,
1955 "StartPlayingFileLocally() is already playing");
1956 return -1;
1957 }
1958
niklase@google.com470e71d2011-07-07 08:21:25 +00001959 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001960 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001961
1962 // Destroy the old instance
1963 if (_outputFilePlayerPtr)
1964 {
1965 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1966 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1967 _outputFilePlayerPtr = NULL;
1968 }
1969
1970 // Create the instance
1971 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
1972 _outputFilePlayerId,
1973 (const FileFormats)format);
1974
1975 if (_outputFilePlayerPtr == NULL)
1976 {
1977 _engineStatisticsPtr->SetLastError(
1978 VE_INVALID_ARGUMENT, kTraceError,
1979 "StartPlayingFileLocally() filePlayer format isnot correct");
1980 return -1;
1981 }
1982
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001983 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00001984
1985 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
1986 volumeScaling,
1987 notificationTime,
1988 stopPosition, codecInst) != 0)
1989 {
1990 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
1991 "StartPlayingFile() failed to "
1992 "start file playout");
1993 _outputFilePlayerPtr->StopPlayingFile();
1994 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1995 _outputFilePlayerPtr = NULL;
1996 return -1;
1997 }
1998 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00001999 channel_state_.SetOutputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002000 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002001
2002 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002003 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002004
niklase@google.com470e71d2011-07-07 08:21:25 +00002005 return 0;
2006}
2007
2008int Channel::StopPlayingFileLocally()
2009{
2010 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2011 "Channel::StopPlayingFileLocally()");
2012
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002013 if (!channel_state_.Get().output_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002014 {
2015 _engineStatisticsPtr->SetLastError(
2016 VE_INVALID_OPERATION, kTraceWarning,
2017 "StopPlayingFileLocally() isnot playing");
2018 return 0;
2019 }
2020
niklase@google.com470e71d2011-07-07 08:21:25 +00002021 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002022 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002023
2024 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2025 {
2026 _engineStatisticsPtr->SetLastError(
2027 VE_STOP_RECORDING_FAILED, kTraceError,
2028 "StopPlayingFile() could not stop playing");
2029 return -1;
2030 }
2031 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2032 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2033 _outputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002034 channel_state_.SetOutputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002035 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002036 // _fileCritSect cannot be taken while calling
2037 // SetAnonymousMixibilityStatus. Refer to comments in
2038 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002039 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2040 {
2041 _engineStatisticsPtr->SetLastError(
2042 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002043 "StopPlayingFile() failed to stop participant from playing as"
2044 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002045 return -1;
2046 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002047
2048 return 0;
2049}
2050
2051int Channel::IsPlayingFileLocally() const
2052{
2053 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2054 "Channel::IsPlayingFileLocally()");
2055
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002056 return channel_state_.Get().output_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002057}
2058
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002059int Channel::RegisterFilePlayingToMixer()
2060{
2061 // Return success for not registering for file playing to mixer if:
2062 // 1. playing file before playout is started on that channel.
2063 // 2. starting playout without file playing on that channel.
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002064 if (!channel_state_.Get().playing ||
2065 !channel_state_.Get().output_file_playing)
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002066 {
2067 return 0;
2068 }
2069
2070 // |_fileCritSect| cannot be taken while calling
2071 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2072 // frames can be pulled by the mixer. Since the frames are generated from
2073 // the file, _fileCritSect will be taken. This would result in a deadlock.
2074 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2075 {
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002076 channel_state_.SetOutputFilePlaying(false);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002077 CriticalSectionScoped cs(&_fileCritSect);
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002078 _engineStatisticsPtr->SetLastError(
2079 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2080 "StartPlayingFile() failed to add participant as file to mixer");
2081 _outputFilePlayerPtr->StopPlayingFile();
2082 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2083 _outputFilePlayerPtr = NULL;
2084 return -1;
2085 }
2086
2087 return 0;
2088}
2089
niklase@google.com470e71d2011-07-07 08:21:25 +00002090int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002091 bool loop,
2092 FileFormats format,
2093 int startPosition,
2094 float volumeScaling,
2095 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002096 const CodecInst* codecInst)
2097{
2098 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2099 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2100 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2101 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2102 startPosition, stopPosition);
2103
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002104 CriticalSectionScoped cs(&_fileCritSect);
2105
2106 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002107 {
2108 _engineStatisticsPtr->SetLastError(
2109 VE_ALREADY_PLAYING, kTraceWarning,
2110 "StartPlayingFileAsMicrophone() filePlayer is playing");
2111 return 0;
2112 }
2113
niklase@google.com470e71d2011-07-07 08:21:25 +00002114 // Destroy the old instance
2115 if (_inputFilePlayerPtr)
2116 {
2117 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2118 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2119 _inputFilePlayerPtr = NULL;
2120 }
2121
2122 // Create the instance
2123 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2124 _inputFilePlayerId, (const FileFormats)format);
2125
2126 if (_inputFilePlayerPtr == NULL)
2127 {
2128 _engineStatisticsPtr->SetLastError(
2129 VE_INVALID_ARGUMENT, kTraceError,
2130 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2131 return -1;
2132 }
2133
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002134 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002135
2136 if (_inputFilePlayerPtr->StartPlayingFile(
2137 fileName,
2138 loop,
2139 startPosition,
2140 volumeScaling,
2141 notificationTime,
2142 stopPosition,
2143 (const CodecInst*)codecInst) != 0)
2144 {
2145 _engineStatisticsPtr->SetLastError(
2146 VE_BAD_FILE, kTraceError,
2147 "StartPlayingFile() failed to start file playout");
2148 _inputFilePlayerPtr->StopPlayingFile();
2149 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2150 _inputFilePlayerPtr = NULL;
2151 return -1;
2152 }
2153 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002154 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002155
2156 return 0;
2157}
2158
2159int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002160 FileFormats format,
2161 int startPosition,
2162 float volumeScaling,
2163 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002164 const CodecInst* codecInst)
2165{
2166 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2167 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2168 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2169 format, volumeScaling, startPosition, stopPosition);
2170
2171 if(stream == NULL)
2172 {
2173 _engineStatisticsPtr->SetLastError(
2174 VE_BAD_FILE, kTraceError,
2175 "StartPlayingFileAsMicrophone NULL as input stream");
2176 return -1;
2177 }
2178
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002179 CriticalSectionScoped cs(&_fileCritSect);
2180
2181 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002182 {
2183 _engineStatisticsPtr->SetLastError(
2184 VE_ALREADY_PLAYING, kTraceWarning,
2185 "StartPlayingFileAsMicrophone() is playing");
2186 return 0;
2187 }
2188
niklase@google.com470e71d2011-07-07 08:21:25 +00002189 // Destroy the old instance
2190 if (_inputFilePlayerPtr)
2191 {
2192 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2193 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2194 _inputFilePlayerPtr = NULL;
2195 }
2196
2197 // Create the instance
2198 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2199 _inputFilePlayerId, (const FileFormats)format);
2200
2201 if (_inputFilePlayerPtr == NULL)
2202 {
2203 _engineStatisticsPtr->SetLastError(
2204 VE_INVALID_ARGUMENT, kTraceError,
2205 "StartPlayingInputFile() filePlayer format isnot correct");
2206 return -1;
2207 }
2208
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002209 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002210
2211 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2212 volumeScaling, notificationTime,
2213 stopPosition, codecInst) != 0)
2214 {
2215 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2216 "StartPlayingFile() failed to start "
2217 "file playout");
2218 _inputFilePlayerPtr->StopPlayingFile();
2219 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2220 _inputFilePlayerPtr = NULL;
2221 return -1;
2222 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002223
niklase@google.com470e71d2011-07-07 08:21:25 +00002224 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002225 channel_state_.SetInputFilePlaying(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00002226
2227 return 0;
2228}
2229
2230int Channel::StopPlayingFileAsMicrophone()
2231{
2232 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2233 "Channel::StopPlayingFileAsMicrophone()");
2234
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002235 CriticalSectionScoped cs(&_fileCritSect);
2236
2237 if (!channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00002238 {
2239 _engineStatisticsPtr->SetLastError(
2240 VE_INVALID_OPERATION, kTraceWarning,
2241 "StopPlayingFileAsMicrophone() isnot playing");
2242 return 0;
2243 }
2244
niklase@google.com470e71d2011-07-07 08:21:25 +00002245 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2246 {
2247 _engineStatisticsPtr->SetLastError(
2248 VE_STOP_RECORDING_FAILED, kTraceError,
2249 "StopPlayingFile() could not stop playing");
2250 return -1;
2251 }
2252 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2253 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2254 _inputFilePlayerPtr = NULL;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002255 channel_state_.SetInputFilePlaying(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00002256
2257 return 0;
2258}
2259
2260int Channel::IsPlayingFileAsMicrophone() const
2261{
2262 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2263 "Channel::IsPlayingFileAsMicrophone()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002264 return channel_state_.Get().input_file_playing;
niklase@google.com470e71d2011-07-07 08:21:25 +00002265}
2266
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002267int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002268 const CodecInst* codecInst)
2269{
2270 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2271 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2272
2273 if (_outputFileRecording)
2274 {
2275 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2276 "StartRecordingPlayout() is already recording");
2277 return 0;
2278 }
2279
2280 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002281 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002282 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2283
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002284 if ((codecInst != NULL) &&
2285 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002286 {
2287 _engineStatisticsPtr->SetLastError(
2288 VE_BAD_ARGUMENT, kTraceError,
2289 "StartRecordingPlayout() invalid compression");
2290 return(-1);
2291 }
2292 if(codecInst == NULL)
2293 {
2294 format = kFileFormatPcm16kHzFile;
2295 codecInst=&dummyCodec;
2296 }
2297 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2298 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2299 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2300 {
2301 format = kFileFormatWavFile;
2302 }
2303 else
2304 {
2305 format = kFileFormatCompressedFile;
2306 }
2307
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002308 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002309
2310 // Destroy the old instance
2311 if (_outputFileRecorderPtr)
2312 {
2313 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2314 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2315 _outputFileRecorderPtr = NULL;
2316 }
2317
2318 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2319 _outputFileRecorderId, (const FileFormats)format);
2320 if (_outputFileRecorderPtr == NULL)
2321 {
2322 _engineStatisticsPtr->SetLastError(
2323 VE_INVALID_ARGUMENT, kTraceError,
2324 "StartRecordingPlayout() fileRecorder format isnot correct");
2325 return -1;
2326 }
2327
2328 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2329 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2330 {
2331 _engineStatisticsPtr->SetLastError(
2332 VE_BAD_FILE, kTraceError,
2333 "StartRecordingAudioFile() failed to start file recording");
2334 _outputFileRecorderPtr->StopRecording();
2335 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2336 _outputFileRecorderPtr = NULL;
2337 return -1;
2338 }
2339 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2340 _outputFileRecording = true;
2341
2342 return 0;
2343}
2344
2345int Channel::StartRecordingPlayout(OutStream* stream,
2346 const CodecInst* codecInst)
2347{
2348 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2349 "Channel::StartRecordingPlayout()");
2350
2351 if (_outputFileRecording)
2352 {
2353 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2354 "StartRecordingPlayout() is already recording");
2355 return 0;
2356 }
2357
2358 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002359 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002360 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2361
2362 if (codecInst != NULL && codecInst->channels != 1)
2363 {
2364 _engineStatisticsPtr->SetLastError(
2365 VE_BAD_ARGUMENT, kTraceError,
2366 "StartRecordingPlayout() invalid compression");
2367 return(-1);
2368 }
2369 if(codecInst == NULL)
2370 {
2371 format = kFileFormatPcm16kHzFile;
2372 codecInst=&dummyCodec;
2373 }
2374 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2375 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2376 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2377 {
2378 format = kFileFormatWavFile;
2379 }
2380 else
2381 {
2382 format = kFileFormatCompressedFile;
2383 }
2384
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002385 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002386
2387 // Destroy the old instance
2388 if (_outputFileRecorderPtr)
2389 {
2390 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2391 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2392 _outputFileRecorderPtr = NULL;
2393 }
2394
2395 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2396 _outputFileRecorderId, (const FileFormats)format);
2397 if (_outputFileRecorderPtr == NULL)
2398 {
2399 _engineStatisticsPtr->SetLastError(
2400 VE_INVALID_ARGUMENT, kTraceError,
2401 "StartRecordingPlayout() fileRecorder format isnot correct");
2402 return -1;
2403 }
2404
2405 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2406 notificationTime) != 0)
2407 {
2408 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2409 "StartRecordingPlayout() failed to "
2410 "start file recording");
2411 _outputFileRecorderPtr->StopRecording();
2412 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2413 _outputFileRecorderPtr = NULL;
2414 return -1;
2415 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002416
niklase@google.com470e71d2011-07-07 08:21:25 +00002417 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2418 _outputFileRecording = true;
2419
2420 return 0;
2421}
2422
2423int Channel::StopRecordingPlayout()
2424{
2425 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2426 "Channel::StopRecordingPlayout()");
2427
2428 if (!_outputFileRecording)
2429 {
2430 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2431 "StopRecordingPlayout() isnot recording");
2432 return -1;
2433 }
2434
2435
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002436 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002437
2438 if (_outputFileRecorderPtr->StopRecording() != 0)
2439 {
2440 _engineStatisticsPtr->SetLastError(
2441 VE_STOP_RECORDING_FAILED, kTraceError,
2442 "StopRecording() could not stop recording");
2443 return(-1);
2444 }
2445 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2446 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2447 _outputFileRecorderPtr = NULL;
2448 _outputFileRecording = false;
2449
2450 return 0;
2451}
2452
2453void
2454Channel::SetMixWithMicStatus(bool mix)
2455{
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002456 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002457 _mixFileWithMicrophone=mix;
2458}
2459
2460int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002461Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002462{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002463 int8_t currentLevel = _outputAudioLevel.Level();
2464 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002465 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2466 VoEId(_instanceId,_channelId),
2467 "GetSpeechOutputLevel() => level=%u", level);
2468 return 0;
2469}
2470
2471int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002472Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002473{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002474 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2475 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002476 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2477 VoEId(_instanceId,_channelId),
2478 "GetSpeechOutputLevelFullRange() => level=%u", level);
2479 return 0;
2480}
2481
2482int
2483Channel::SetMute(bool enable)
2484{
wu@webrtc.org63420662013-10-17 18:28:55 +00002485 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002486 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2487 "Channel::SetMute(enable=%d)", enable);
2488 _mute = enable;
2489 return 0;
2490}
2491
2492bool
2493Channel::Mute() const
2494{
wu@webrtc.org63420662013-10-17 18:28:55 +00002495 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002496 return _mute;
2497}
2498
2499int
2500Channel::SetOutputVolumePan(float left, float right)
2501{
wu@webrtc.org63420662013-10-17 18:28:55 +00002502 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002503 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2504 "Channel::SetOutputVolumePan()");
2505 _panLeft = left;
2506 _panRight = right;
2507 return 0;
2508}
2509
2510int
2511Channel::GetOutputVolumePan(float& left, float& right) const
2512{
wu@webrtc.org63420662013-10-17 18:28:55 +00002513 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002514 left = _panLeft;
2515 right = _panRight;
2516 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2517 VoEId(_instanceId,_channelId),
2518 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
2519 return 0;
2520}
2521
2522int
2523Channel::SetChannelOutputVolumeScaling(float scaling)
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::SetChannelOutputVolumeScaling()");
2528 _outputGain = scaling;
2529 return 0;
2530}
2531
2532int
2533Channel::GetChannelOutputVolumeScaling(float& scaling) const
2534{
wu@webrtc.org63420662013-10-17 18:28:55 +00002535 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002536 scaling = _outputGain;
2537 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2538 VoEId(_instanceId,_channelId),
2539 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
2540 return 0;
2541}
2542
niklase@google.com470e71d2011-07-07 08:21:25 +00002543int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002544 int lengthMs, int attenuationDb,
2545 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00002546{
2547 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2548 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
2549 playDtmfEvent);
2550
2551 _playOutbandDtmfEvent = playDtmfEvent;
2552
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002553 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00002554 attenuationDb) != 0)
2555 {
2556 _engineStatisticsPtr->SetLastError(
2557 VE_SEND_DTMF_FAILED,
2558 kTraceWarning,
2559 "SendTelephoneEventOutband() failed to send event");
2560 return -1;
2561 }
2562 return 0;
2563}
2564
2565int Channel::SendTelephoneEventInband(unsigned char eventCode,
2566 int lengthMs,
2567 int attenuationDb,
2568 bool playDtmfEvent)
2569{
2570 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2571 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
2572 playDtmfEvent);
2573
2574 _playInbandDtmfEvent = playDtmfEvent;
2575 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
2576
2577 return 0;
2578}
2579
2580int
2581Channel::SetDtmfPlayoutStatus(bool enable)
2582{
2583 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2584 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002585 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002586 {
2587 _engineStatisticsPtr->SetLastError(
2588 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
2589 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
2590 return -1;
2591 }
2592 return 0;
2593}
2594
2595bool
2596Channel::DtmfPlayoutStatus() const
2597{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002598 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00002599}
2600
2601int
2602Channel::SetSendTelephoneEventPayloadType(unsigned char type)
2603{
2604 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2605 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00002606 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00002607 {
2608 _engineStatisticsPtr->SetLastError(
2609 VE_INVALID_ARGUMENT, kTraceError,
2610 "SetSendTelephoneEventPayloadType() invalid type");
2611 return -1;
2612 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00002613 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00002614 codec.plfreq = 8000;
2615 codec.pltype = type;
2616 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00002617 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002618 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00002619 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
2620 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
2621 _engineStatisticsPtr->SetLastError(
2622 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
2623 "SetSendTelephoneEventPayloadType() failed to register send"
2624 "payload type");
2625 return -1;
2626 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002627 }
2628 _sendTelephoneEventPayloadType = type;
2629 return 0;
2630}
2631
2632int
2633Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
2634{
2635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2636 "Channel::GetSendTelephoneEventPayloadType()");
2637 type = _sendTelephoneEventPayloadType;
2638 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2639 VoEId(_instanceId,_channelId),
2640 "GetSendTelephoneEventPayloadType() => type=%u", type);
2641 return 0;
2642}
2643
niklase@google.com470e71d2011-07-07 08:21:25 +00002644int
2645Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
2646{
2647 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2648 "Channel::UpdateRxVadDetection()");
2649
2650 int vadDecision = 1;
2651
andrew@webrtc.org63a50982012-05-02 23:56:37 +00002652 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002653
2654 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
2655 {
2656 OnRxVadDetected(vadDecision);
2657 _oldVadDecision = vadDecision;
2658 }
2659
2660 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2661 "Channel::UpdateRxVadDetection() => vadDecision=%d",
2662 vadDecision);
2663 return 0;
2664}
2665
2666int
2667Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
2668{
2669 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2670 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002671 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002672
2673 if (_rxVadObserverPtr)
2674 {
2675 _engineStatisticsPtr->SetLastError(
2676 VE_INVALID_OPERATION, kTraceError,
2677 "RegisterRxVadObserver() observer already enabled");
2678 return -1;
2679 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002680 _rxVadObserverPtr = &observer;
2681 _RxVadDetection = true;
2682 return 0;
2683}
2684
2685int
2686Channel::DeRegisterRxVadObserver()
2687{
2688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2689 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002690 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002691
2692 if (!_rxVadObserverPtr)
2693 {
2694 _engineStatisticsPtr->SetLastError(
2695 VE_INVALID_OPERATION, kTraceWarning,
2696 "DeRegisterRxVadObserver() observer already disabled");
2697 return 0;
2698 }
2699 _rxVadObserverPtr = NULL;
2700 _RxVadDetection = false;
2701 return 0;
2702}
2703
2704int
2705Channel::VoiceActivityIndicator(int &activity)
2706{
2707 activity = _sendFrameType;
2708
2709 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002710 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00002711 return 0;
2712}
2713
2714#ifdef WEBRTC_VOICE_ENGINE_AGC
2715
2716int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002717Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002718{
2719 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2720 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
2721 (int)enable, (int)mode);
2722
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002723 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002724 switch (mode)
2725 {
2726 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002727 break;
2728 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002729 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002730 break;
2731 case kAgcFixedDigital:
2732 agcMode = GainControl::kFixedDigital;
2733 break;
2734 case kAgcAdaptiveDigital:
2735 agcMode =GainControl::kAdaptiveDigital;
2736 break;
2737 default:
2738 _engineStatisticsPtr->SetLastError(
2739 VE_INVALID_ARGUMENT, kTraceError,
2740 "SetRxAgcStatus() invalid Agc mode");
2741 return -1;
2742 }
2743
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002744 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002745 {
2746 _engineStatisticsPtr->SetLastError(
2747 VE_APM_ERROR, kTraceError,
2748 "SetRxAgcStatus() failed to set Agc mode");
2749 return -1;
2750 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002751 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002752 {
2753 _engineStatisticsPtr->SetLastError(
2754 VE_APM_ERROR, kTraceError,
2755 "SetRxAgcStatus() failed to set Agc state");
2756 return -1;
2757 }
2758
2759 _rxAgcIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002760 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002761
2762 return 0;
2763}
2764
2765int
2766Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
2767{
2768 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2769 "Channel::GetRxAgcStatus(enable=?, mode=?)");
2770
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002771 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002772 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002773 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00002774
2775 enabled = enable;
2776
2777 switch (agcMode)
2778 {
2779 case GainControl::kFixedDigital:
2780 mode = kAgcFixedDigital;
2781 break;
2782 case GainControl::kAdaptiveDigital:
2783 mode = kAgcAdaptiveDigital;
2784 break;
2785 default:
2786 _engineStatisticsPtr->SetLastError(
2787 VE_APM_ERROR, kTraceError,
2788 "GetRxAgcStatus() invalid Agc mode");
2789 return -1;
2790 }
2791
2792 return 0;
2793}
2794
2795int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002796Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00002797{
2798 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2799 "Channel::SetRxAgcConfig()");
2800
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002801 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00002802 config.targetLeveldBOv) != 0)
2803 {
2804 _engineStatisticsPtr->SetLastError(
2805 VE_APM_ERROR, kTraceError,
2806 "SetRxAgcConfig() failed to set target peak |level|"
2807 "(or envelope) of the Agc");
2808 return -1;
2809 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002810 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00002811 config.digitalCompressionGaindB) != 0)
2812 {
2813 _engineStatisticsPtr->SetLastError(
2814 VE_APM_ERROR, kTraceError,
2815 "SetRxAgcConfig() failed to set the range in |gain| the"
2816 " digital compression stage may apply");
2817 return -1;
2818 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002819 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00002820 config.limiterEnable) != 0)
2821 {
2822 _engineStatisticsPtr->SetLastError(
2823 VE_APM_ERROR, kTraceError,
2824 "SetRxAgcConfig() failed to set hard limiter to the signal");
2825 return -1;
2826 }
2827
2828 return 0;
2829}
2830
2831int
2832Channel::GetRxAgcConfig(AgcConfig& config)
2833{
2834 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2835 "Channel::GetRxAgcConfig(config=%?)");
2836
2837 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002838 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00002839 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002840 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00002841 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002842 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002843
2844 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2845 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
2846 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
2847 " limiterEnable=%d",
2848 config.targetLeveldBOv,
2849 config.digitalCompressionGaindB,
2850 config.limiterEnable);
2851
2852 return 0;
2853}
2854
2855#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
2856
2857#ifdef WEBRTC_VOICE_ENGINE_NR
2858
2859int
pbos@webrtc.org92135212013-05-14 08:31:39 +00002860Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00002861{
2862 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2863 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
2864 (int)enable, (int)mode);
2865
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002866 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00002867 switch (mode)
2868 {
2869
2870 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00002871 break;
2872 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002873 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002874 break;
2875 case kNsConference:
2876 nsLevel = NoiseSuppression::kHigh;
2877 break;
2878 case kNsLowSuppression:
2879 nsLevel = NoiseSuppression::kLow;
2880 break;
2881 case kNsModerateSuppression:
2882 nsLevel = NoiseSuppression::kModerate;
2883 break;
2884 case kNsHighSuppression:
2885 nsLevel = NoiseSuppression::kHigh;
2886 break;
2887 case kNsVeryHighSuppression:
2888 nsLevel = NoiseSuppression::kVeryHigh;
2889 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002890 }
2891
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002892 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00002893 != 0)
2894 {
2895 _engineStatisticsPtr->SetLastError(
2896 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002897 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00002898 return -1;
2899 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002900 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00002901 {
2902 _engineStatisticsPtr->SetLastError(
2903 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00002904 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00002905 return -1;
2906 }
2907
2908 _rxNsIsEnabled = enable;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002909 channel_state_.SetRxApmIsEnabled(_rxAgcIsEnabled || _rxNsIsEnabled);
niklase@google.com470e71d2011-07-07 08:21:25 +00002910
2911 return 0;
2912}
2913
2914int
2915Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
2916{
2917 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2918 "Channel::GetRxNsStatus(enable=?, mode=?)");
2919
2920 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002921 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00002922 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00002923 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00002924
2925 enabled = enable;
2926
2927 switch (ncLevel)
2928 {
2929 case NoiseSuppression::kLow:
2930 mode = kNsLowSuppression;
2931 break;
2932 case NoiseSuppression::kModerate:
2933 mode = kNsModerateSuppression;
2934 break;
2935 case NoiseSuppression::kHigh:
2936 mode = kNsHighSuppression;
2937 break;
2938 case NoiseSuppression::kVeryHigh:
2939 mode = kNsVeryHighSuppression;
2940 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00002941 }
2942
2943 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2944 VoEId(_instanceId,_channelId),
2945 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
2946 return 0;
2947}
2948
2949#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
2950
2951int
niklase@google.com470e71d2011-07-07 08:21:25 +00002952Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
2953{
2954 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2955 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002956 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002957
2958 if (_rtcpObserverPtr)
2959 {
2960 _engineStatisticsPtr->SetLastError(
2961 VE_INVALID_OPERATION, kTraceError,
2962 "RegisterRTCPObserver() observer already enabled");
2963 return -1;
2964 }
2965
2966 _rtcpObserverPtr = &observer;
2967 _rtcpObserver = true;
2968
2969 return 0;
2970}
2971
2972int
2973Channel::DeRegisterRTCPObserver()
2974{
2975 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2976 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002977 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002978
2979 if (!_rtcpObserverPtr)
2980 {
2981 _engineStatisticsPtr->SetLastError(
2982 VE_INVALID_OPERATION, kTraceWarning,
2983 "DeRegisterRTCPObserver() observer already disabled");
2984 return 0;
2985 }
2986
2987 _rtcpObserver = false;
2988 _rtcpObserverPtr = NULL;
2989
2990 return 0;
2991}
2992
2993int
2994Channel::SetLocalSSRC(unsigned int ssrc)
2995{
2996 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2997 "Channel::SetLocalSSRC()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00002998 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00002999 {
3000 _engineStatisticsPtr->SetLastError(
3001 VE_ALREADY_SENDING, kTraceError,
3002 "SetLocalSSRC() already sending");
3003 return -1;
3004 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003005 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003006 {
3007 _engineStatisticsPtr->SetLastError(
3008 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3009 "SetLocalSSRC() failed to set SSRC");
3010 return -1;
3011 }
3012 return 0;
3013}
3014
3015int
3016Channel::GetLocalSSRC(unsigned int& ssrc)
3017{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003018 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003019 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3020 VoEId(_instanceId,_channelId),
3021 "GetLocalSSRC() => ssrc=%lu", ssrc);
3022 return 0;
3023}
3024
3025int
3026Channel::GetRemoteSSRC(unsigned int& ssrc)
3027{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003028 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003029 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3030 VoEId(_instanceId,_channelId),
3031 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3032 return 0;
3033}
3034
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003035int Channel::SetSendAudioLevelIndicationStatus(bool enable, unsigned char id) {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003036 _includeAudioLevelIndication = enable;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003037 return SetSendRtpHeaderExtension(enable, kRtpExtensionAudioLevel, id);
niklase@google.com470e71d2011-07-07 08:21:25 +00003038}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003039
wu@webrtc.org93fd25c2014-04-24 20:33:08 +00003040int Channel::SetReceiveAudioLevelIndicationStatus(bool enable,
3041 unsigned char id) {
3042 rtp_header_parser_->DeregisterRtpHeaderExtension(
3043 kRtpExtensionAudioLevel);
3044 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3045 kRtpExtensionAudioLevel, id)) {
3046 return -1;
3047 }
3048 return 0;
3049}
3050
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003051int Channel::SetSendAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3052 return SetSendRtpHeaderExtension(enable, kRtpExtensionAbsoluteSendTime, id);
3053}
3054
3055int Channel::SetReceiveAbsoluteSenderTimeStatus(bool enable, unsigned char id) {
3056 rtp_header_parser_->DeregisterRtpHeaderExtension(
3057 kRtpExtensionAbsoluteSendTime);
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003058 if (enable && !rtp_header_parser_->RegisterRtpHeaderExtension(
3059 kRtpExtensionAbsoluteSendTime, id)) {
3060 return -1;
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00003061 }
3062 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003063}
3064
3065int
3066Channel::SetRTCPStatus(bool enable)
3067{
3068 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3069 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003070 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003071 kRtcpCompound : kRtcpOff) != 0)
3072 {
3073 _engineStatisticsPtr->SetLastError(
3074 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3075 "SetRTCPStatus() failed to set RTCP status");
3076 return -1;
3077 }
3078 return 0;
3079}
3080
3081int
3082Channel::GetRTCPStatus(bool& enabled)
3083{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003084 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003085 enabled = (method != kRtcpOff);
3086 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3087 VoEId(_instanceId,_channelId),
3088 "GetRTCPStatus() => enabled=%d", enabled);
3089 return 0;
3090}
3091
3092int
3093Channel::SetRTCP_CNAME(const char cName[256])
3094{
3095 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3096 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003097 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003098 {
3099 _engineStatisticsPtr->SetLastError(
3100 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3101 "SetRTCP_CNAME() failed to set RTCP CNAME");
3102 return -1;
3103 }
3104 return 0;
3105}
3106
3107int
3108Channel::GetRTCP_CNAME(char cName[256])
3109{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003110 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003111 {
3112 _engineStatisticsPtr->SetLastError(
3113 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3114 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3115 return -1;
3116 }
3117 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3118 VoEId(_instanceId, _channelId),
3119 "GetRTCP_CNAME() => cName=%s", cName);
3120 return 0;
3121}
3122
3123int
3124Channel::GetRemoteRTCP_CNAME(char cName[256])
3125{
3126 if (cName == NULL)
3127 {
3128 _engineStatisticsPtr->SetLastError(
3129 VE_INVALID_ARGUMENT, kTraceError,
3130 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3131 return -1;
3132 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003133 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003134 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003135 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003136 {
3137 _engineStatisticsPtr->SetLastError(
3138 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3139 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3140 return -1;
3141 }
3142 strcpy(cName, cname);
3143 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3144 VoEId(_instanceId, _channelId),
3145 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3146 return 0;
3147}
3148
3149int
3150Channel::GetRemoteRTCPData(
3151 unsigned int& NTPHigh,
3152 unsigned int& NTPLow,
3153 unsigned int& timestamp,
3154 unsigned int& playoutTimestamp,
3155 unsigned int* jitter,
3156 unsigned short* fractionLost)
3157{
3158 // --- Information from sender info in received Sender Reports
3159
3160 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003161 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003162 {
3163 _engineStatisticsPtr->SetLastError(
3164 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003165 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003166 "side");
3167 return -1;
3168 }
3169
3170 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3171 // and octet count)
3172 NTPHigh = senderInfo.NTPseconds;
3173 NTPLow = senderInfo.NTPfraction;
3174 timestamp = senderInfo.RTPtimeStamp;
3175
3176 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3177 VoEId(_instanceId, _channelId),
3178 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3179 "timestamp=%lu",
3180 NTPHigh, NTPLow, timestamp);
3181
3182 // --- Locally derived information
3183
3184 // This value is updated on each incoming RTCP packet (0 when no packet
3185 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003186 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003187
3188 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3189 VoEId(_instanceId, _channelId),
3190 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003191 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003192
3193 if (NULL != jitter || NULL != fractionLost)
3194 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003195 // Get all RTCP receiver report blocks that have been received on this
3196 // channel. If we receive RTP packets from a remote source we know the
3197 // remote SSRC and use the report block from him.
3198 // Otherwise use the first report block.
3199 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003200 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003201 remote_stats.empty()) {
3202 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3203 VoEId(_instanceId, _channelId),
3204 "GetRemoteRTCPData() failed to measure statistics due"
3205 " to lack of received RTP and/or RTCP packets");
3206 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003207 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003208
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003209 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003210 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3211 for (; it != remote_stats.end(); ++it) {
3212 if (it->remoteSSRC == remoteSSRC)
3213 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003214 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003215
3216 if (it == remote_stats.end()) {
3217 // If we have not received any RTCP packets from this SSRC it probably
3218 // means that we have not received any RTP packets.
3219 // Use the first received report block instead.
3220 it = remote_stats.begin();
3221 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003222 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003223
xians@webrtc.org79af7342012-01-31 12:22:14 +00003224 if (jitter) {
3225 *jitter = it->jitter;
3226 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3227 VoEId(_instanceId, _channelId),
3228 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3229 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003230
xians@webrtc.org79af7342012-01-31 12:22:14 +00003231 if (fractionLost) {
3232 *fractionLost = it->fractionLost;
3233 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3234 VoEId(_instanceId, _channelId),
3235 "GetRemoteRTCPData() => fractionLost = %lu",
3236 *fractionLost);
3237 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003238 }
3239 return 0;
3240}
3241
3242int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003243Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003244 unsigned int name,
3245 const char* data,
3246 unsigned short dataLengthInBytes)
3247{
3248 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3249 "Channel::SendApplicationDefinedRTCPPacket()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003250 if (!channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00003251 {
3252 _engineStatisticsPtr->SetLastError(
3253 VE_NOT_SENDING, kTraceError,
3254 "SendApplicationDefinedRTCPPacket() not sending");
3255 return -1;
3256 }
3257 if (NULL == data)
3258 {
3259 _engineStatisticsPtr->SetLastError(
3260 VE_INVALID_ARGUMENT, kTraceError,
3261 "SendApplicationDefinedRTCPPacket() invalid data value");
3262 return -1;
3263 }
3264 if (dataLengthInBytes % 4 != 0)
3265 {
3266 _engineStatisticsPtr->SetLastError(
3267 VE_INVALID_ARGUMENT, kTraceError,
3268 "SendApplicationDefinedRTCPPacket() invalid length value");
3269 return -1;
3270 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003271 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003272 if (status == kRtcpOff)
3273 {
3274 _engineStatisticsPtr->SetLastError(
3275 VE_RTCP_ERROR, kTraceError,
3276 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3277 return -1;
3278 }
3279
3280 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003281 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003282 subType,
3283 name,
3284 (const unsigned char*) data,
3285 dataLengthInBytes) != 0)
3286 {
3287 _engineStatisticsPtr->SetLastError(
3288 VE_SEND_ERROR, kTraceError,
3289 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3290 return -1;
3291 }
3292 return 0;
3293}
3294
3295int
3296Channel::GetRTPStatistics(
3297 unsigned int& averageJitterMs,
3298 unsigned int& maxJitterMs,
3299 unsigned int& discardedPackets)
3300{
niklase@google.com470e71d2011-07-07 08:21:25 +00003301 // The jitter statistics is updated for each received RTP packet and is
3302 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003303 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3304 // If RTCP is off, there is no timed thread in the RTCP module regularly
3305 // generating new stats, trigger the update manually here instead.
3306 StreamStatistician* statistician =
3307 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3308 if (statistician) {
3309 // Don't use returned statistics, use data from proxy instead so that
3310 // max jitter can be fetched atomically.
3311 RtcpStatistics s;
3312 statistician->GetStatistics(&s, true);
3313 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003314 }
3315
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003316 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003317 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003318 if (playoutFrequency > 0) {
3319 // Scale RTP statistics given the current playout frequency
3320 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3321 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003322 }
3323
3324 discardedPackets = _numberOfDiscardedPackets;
3325
3326 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3327 VoEId(_instanceId, _channelId),
3328 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003329 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003330 averageJitterMs, maxJitterMs, discardedPackets);
3331 return 0;
3332}
3333
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003334int Channel::GetRemoteRTCPReportBlocks(
3335 std::vector<ReportBlock>* report_blocks) {
3336 if (report_blocks == NULL) {
3337 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3338 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3339 return -1;
3340 }
3341
3342 // Get the report blocks from the latest received RTCP Sender or Receiver
3343 // Report. Each element in the vector contains the sender's SSRC and a
3344 // report block according to RFC 3550.
3345 std::vector<RTCPReportBlock> rtcp_report_blocks;
3346 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3347 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3348 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3349 return -1;
3350 }
3351
3352 if (rtcp_report_blocks.empty())
3353 return 0;
3354
3355 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3356 for (; it != rtcp_report_blocks.end(); ++it) {
3357 ReportBlock report_block;
3358 report_block.sender_SSRC = it->remoteSSRC;
3359 report_block.source_SSRC = it->sourceSSRC;
3360 report_block.fraction_lost = it->fractionLost;
3361 report_block.cumulative_num_packets_lost = it->cumulativeLost;
3362 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
3363 report_block.interarrival_jitter = it->jitter;
3364 report_block.last_SR_timestamp = it->lastSR;
3365 report_block.delay_since_last_SR = it->delaySinceLastSR;
3366 report_blocks->push_back(report_block);
3367 }
3368 return 0;
3369}
3370
niklase@google.com470e71d2011-07-07 08:21:25 +00003371int
3372Channel::GetRTPStatistics(CallStatistics& stats)
3373{
niklase@google.com470e71d2011-07-07 08:21:25 +00003374 // --- Part one of the final structure (four values)
3375
3376 // The jitter statistics is updated for each received RTP packet and is
3377 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003378 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003379 StreamStatistician* statistician =
3380 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3381 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003382 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
3383 _engineStatisticsPtr->SetLastError(
3384 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
3385 "GetRTPStatistics() failed to read RTP statistics from the "
3386 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00003387 }
3388
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003389 stats.fractionLost = statistics.fraction_lost;
3390 stats.cumulativeLost = statistics.cumulative_lost;
3391 stats.extendedMax = statistics.extended_max_sequence_number;
3392 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00003393
3394 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3395 VoEId(_instanceId, _channelId),
3396 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003397 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003398 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
3399 stats.jitterSamples);
3400
3401 // --- Part two of the final structure (one value)
3402
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003403 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003404 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003405 if (method == kRtcpOff)
3406 {
3407 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3408 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003409 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00003410 "measurements cannot be retrieved");
3411 } else
3412 {
3413 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003414 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003415 if (remoteSSRC > 0)
3416 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003417 uint16_t avgRTT(0);
3418 uint16_t maxRTT(0);
3419 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003420
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003421 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00003422 != 0)
3423 {
3424 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3425 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003426 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00003427 "the RTP/RTCP module");
3428 }
3429 } else
3430 {
3431 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3432 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003433 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00003434 "RTP packets have been received yet");
3435 }
3436 }
3437
3438 stats.rttMs = static_cast<int> (RTT);
3439
3440 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3441 VoEId(_instanceId, _channelId),
3442 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
3443
3444 // --- Part three of the final structure (four values)
3445
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003446 uint32_t bytesSent(0);
3447 uint32_t packetsSent(0);
3448 uint32_t bytesReceived(0);
3449 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00003450
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00003451 if (statistician) {
3452 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
3453 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003454
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003455 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003456 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003457 {
3458 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3459 VoEId(_instanceId, _channelId),
3460 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003461 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00003462 }
3463
3464 stats.bytesSent = bytesSent;
3465 stats.packetsSent = packetsSent;
3466 stats.bytesReceived = bytesReceived;
3467 stats.packetsReceived = packetsReceived;
3468
3469 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3470 VoEId(_instanceId, _channelId),
3471 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003472 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003473 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
3474 stats.packetsReceived);
3475
3476 return 0;
3477}
3478
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003479int Channel::SetFECStatus(bool enable, int redPayloadtype) {
3480 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3481 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00003482
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00003483 if (enable) {
3484 if (redPayloadtype < 0 || redPayloadtype > 127) {
3485 _engineStatisticsPtr->SetLastError(
3486 VE_PLTYPE_ERROR, kTraceError,
3487 "SetFECStatus() invalid RED payload type");
3488 return -1;
3489 }
3490
3491 if (SetRedPayloadType(redPayloadtype) < 0) {
3492 _engineStatisticsPtr->SetLastError(
3493 VE_CODEC_ERROR, kTraceError,
3494 "SetSecondarySendCodec() Failed to register RED ACM");
3495 return -1;
3496 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003497 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003498
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003499 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00003500 _engineStatisticsPtr->SetLastError(
3501 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3502 "SetFECStatus() failed to set FEC state in the ACM");
3503 return -1;
3504 }
3505 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003506}
3507
3508int
3509Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
3510{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003511 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003512 if (enabled)
3513 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003514 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003515 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003516 {
3517 _engineStatisticsPtr->SetLastError(
3518 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3519 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
3520 "module");
3521 return -1;
3522 }
3523 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3524 VoEId(_instanceId, _channelId),
3525 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
3526 enabled, redPayloadtype);
3527 return 0;
3528 }
3529 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3530 VoEId(_instanceId, _channelId),
3531 "GetFECStatus() => enabled=%d", enabled);
3532 return 0;
3533}
3534
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003535void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
3536 // None of these functions can fail.
3537 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00003538 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
3539 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003540 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003541 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003542 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003543 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003544}
3545
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00003546// Called when we are missing one or more packets.
3547int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00003548 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
3549}
3550
niklase@google.com470e71d2011-07-07 08:21:25 +00003551int
niklase@google.com470e71d2011-07-07 08:21:25 +00003552Channel::StartRTPDump(const char fileNameUTF8[1024],
3553 RTPDirections direction)
3554{
3555 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3556 "Channel::StartRTPDump()");
3557 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3558 {
3559 _engineStatisticsPtr->SetLastError(
3560 VE_INVALID_ARGUMENT, kTraceError,
3561 "StartRTPDump() invalid RTP direction");
3562 return -1;
3563 }
3564 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3565 &_rtpDumpIn : &_rtpDumpOut;
3566 if (rtpDumpPtr == NULL)
3567 {
3568 assert(false);
3569 return -1;
3570 }
3571 if (rtpDumpPtr->IsActive())
3572 {
3573 rtpDumpPtr->Stop();
3574 }
3575 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
3576 {
3577 _engineStatisticsPtr->SetLastError(
3578 VE_BAD_FILE, kTraceError,
3579 "StartRTPDump() failed to create file");
3580 return -1;
3581 }
3582 return 0;
3583}
3584
3585int
3586Channel::StopRTPDump(RTPDirections direction)
3587{
3588 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3589 "Channel::StopRTPDump()");
3590 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
3591 {
3592 _engineStatisticsPtr->SetLastError(
3593 VE_INVALID_ARGUMENT, kTraceError,
3594 "StopRTPDump() invalid RTP direction");
3595 return -1;
3596 }
3597 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3598 &_rtpDumpIn : &_rtpDumpOut;
3599 if (rtpDumpPtr == NULL)
3600 {
3601 assert(false);
3602 return -1;
3603 }
3604 if (!rtpDumpPtr->IsActive())
3605 {
3606 return 0;
3607 }
3608 return rtpDumpPtr->Stop();
3609}
3610
3611bool
3612Channel::RTPDumpIsActive(RTPDirections direction)
3613{
3614 if ((direction != kRtpIncoming) &&
3615 (direction != kRtpOutgoing))
3616 {
3617 _engineStatisticsPtr->SetLastError(
3618 VE_INVALID_ARGUMENT, kTraceError,
3619 "RTPDumpIsActive() invalid RTP direction");
3620 return false;
3621 }
3622 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
3623 &_rtpDumpIn : &_rtpDumpOut;
3624 return rtpDumpPtr->IsActive();
3625}
3626
solenberg@webrtc.orgb1f50102014-03-24 10:38:25 +00003627void Channel::SetVideoEngineBWETarget(ViENetwork* vie_network,
3628 int video_channel) {
3629 CriticalSectionScoped cs(&_callbackCritSect);
3630 if (vie_network_) {
3631 vie_network_->Release();
3632 vie_network_ = NULL;
3633 }
3634 video_channel_ = -1;
3635
3636 if (vie_network != NULL && video_channel != -1) {
3637 vie_network_ = vie_network;
3638 video_channel_ = video_channel;
3639 }
3640}
3641
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003642uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003643Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00003644{
3645 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003646 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00003647 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003648 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003649 return 0;
3650}
3651
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003652void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003653 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003654 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00003655 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003656 CodecInst codec;
3657 GetSendCodec(codec);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003658
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003659 if (!mono_recording_audio_.get()) {
3660 // Temporary space for DownConvertToCodecFormat.
3661 mono_recording_audio_.reset(new int16_t[kMaxMonoDataSizeSamples]);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003662 }
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00003663 DownConvertToCodecFormat(audio_data,
3664 number_of_frames,
3665 number_of_channels,
3666 sample_rate,
3667 codec.channels,
3668 codec.plfreq,
3669 mono_recording_audio_.get(),
3670 &input_resampler_,
3671 &_audioFrame);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00003672}
3673
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003674uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00003675Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00003676{
3677 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3678 "Channel::PrepareEncodeAndSend()");
3679
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003680 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003681 {
3682 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3683 "Channel::PrepareEncodeAndSend() invalid audio frame");
3684 return -1;
3685 }
3686
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003687 if (channel_state_.Get().input_file_playing)
niklase@google.com470e71d2011-07-07 08:21:25 +00003688 {
3689 MixOrReplaceAudioWithFile(mixingFrequency);
3690 }
3691
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003692 bool is_muted = Mute(); // Cache locally as Mute() takes a lock.
3693 if (is_muted) {
3694 AudioFrameOperations::Mute(_audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +00003695 }
3696
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003697 if (channel_state_.Get().input_external_media)
niklase@google.com470e71d2011-07-07 08:21:25 +00003698 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003699 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003700 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00003701 if (_inputExternalMediaCallbackPtr)
3702 {
3703 _inputExternalMediaCallbackPtr->Process(
3704 _channelId,
3705 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003706 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003707 _audioFrame.samples_per_channel_,
3708 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00003709 isStereo);
3710 }
3711 }
3712
3713 InsertInbandDtmfTone();
3714
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00003715 if (_includeAudioLevelIndication) {
andrew@webrtc.org382c0c22014-05-05 18:22:21 +00003716 int length = _audioFrame.samples_per_channel_ * _audioFrame.num_channels_;
andrew@webrtc.org21299d42014-05-14 19:00:59 +00003717 if (is_muted) {
3718 rms_level_.ProcessMuted(length);
3719 } else {
3720 rms_level_.Process(_audioFrame.data_, length);
3721 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003722 }
3723
niklase@google.com470e71d2011-07-07 08:21:25 +00003724 return 0;
3725}
3726
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003727uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00003728Channel::EncodeAndSend()
3729{
3730 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3731 "Channel::EncodeAndSend()");
3732
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003733 assert(_audioFrame.num_channels_ <= 2);
3734 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003735 {
3736 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3737 "Channel::EncodeAndSend() invalid audio frame");
3738 return -1;
3739 }
3740
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003741 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00003742
3743 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
3744
3745 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003746 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003747 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003748 {
3749 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
3750 "Channel::EncodeAndSend() ACM encoding failed");
3751 return -1;
3752 }
3753
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003754 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003755
3756 // --- Encode if complete frame is ready
3757
3758 // This call will trigger AudioPacketizationCallback::SendData if encoding
3759 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003760 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00003761}
3762
3763int Channel::RegisterExternalMediaProcessing(
3764 ProcessingTypes type,
3765 VoEMediaProcess& processObject)
3766{
3767 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3768 "Channel::RegisterExternalMediaProcessing()");
3769
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003770 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003771
3772 if (kPlaybackPerChannel == type)
3773 {
3774 if (_outputExternalMediaCallbackPtr)
3775 {
3776 _engineStatisticsPtr->SetLastError(
3777 VE_INVALID_OPERATION, kTraceError,
3778 "Channel::RegisterExternalMediaProcessing() "
3779 "output external media already enabled");
3780 return -1;
3781 }
3782 _outputExternalMediaCallbackPtr = &processObject;
3783 _outputExternalMedia = true;
3784 }
3785 else if (kRecordingPerChannel == type)
3786 {
3787 if (_inputExternalMediaCallbackPtr)
3788 {
3789 _engineStatisticsPtr->SetLastError(
3790 VE_INVALID_OPERATION, kTraceError,
3791 "Channel::RegisterExternalMediaProcessing() "
3792 "output external media already enabled");
3793 return -1;
3794 }
3795 _inputExternalMediaCallbackPtr = &processObject;
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003796 channel_state_.SetInputExternalMedia(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00003797 }
3798 return 0;
3799}
3800
3801int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
3802{
3803 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3804 "Channel::DeRegisterExternalMediaProcessing()");
3805
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003806 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003807
3808 if (kPlaybackPerChannel == type)
3809 {
3810 if (!_outputExternalMediaCallbackPtr)
3811 {
3812 _engineStatisticsPtr->SetLastError(
3813 VE_INVALID_OPERATION, kTraceWarning,
3814 "Channel::DeRegisterExternalMediaProcessing() "
3815 "output external media already disabled");
3816 return 0;
3817 }
3818 _outputExternalMedia = false;
3819 _outputExternalMediaCallbackPtr = NULL;
3820 }
3821 else if (kRecordingPerChannel == type)
3822 {
3823 if (!_inputExternalMediaCallbackPtr)
3824 {
3825 _engineStatisticsPtr->SetLastError(
3826 VE_INVALID_OPERATION, kTraceWarning,
3827 "Channel::DeRegisterExternalMediaProcessing() "
3828 "input external media already disabled");
3829 return 0;
3830 }
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003831 channel_state_.SetInputExternalMedia(false);
niklase@google.com470e71d2011-07-07 08:21:25 +00003832 _inputExternalMediaCallbackPtr = NULL;
3833 }
3834
3835 return 0;
3836}
3837
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003838int Channel::SetExternalMixing(bool enabled) {
3839 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3840 "Channel::SetExternalMixing(enabled=%d)", enabled);
3841
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00003842 if (channel_state_.Get().playing)
roosa@google.com1b60ceb2012-12-12 23:00:29 +00003843 {
3844 _engineStatisticsPtr->SetLastError(
3845 VE_INVALID_OPERATION, kTraceError,
3846 "Channel::SetExternalMixing() "
3847 "external mixing cannot be changed while playing.");
3848 return -1;
3849 }
3850
3851 _externalMixing = enabled;
3852
3853 return 0;
3854}
3855
niklase@google.com470e71d2011-07-07 08:21:25 +00003856int
niklase@google.com470e71d2011-07-07 08:21:25 +00003857Channel::GetNetworkStatistics(NetworkStatistics& stats)
3858{
3859 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3860 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003861 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003862 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00003863 if (return_value >= 0) {
3864 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
3865 }
3866 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00003867}
3868
wu@webrtc.org24301a62013-12-13 19:17:43 +00003869void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
3870 audio_coding_->GetDecodingCallStatistics(stats);
3871}
3872
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003873bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
3874 int* playout_buffer_delay_ms) const {
3875 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00003876 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003877 "Channel::GetDelayEstimate() no valid estimate.");
3878 return false;
3879 }
3880 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
3881 _recPacketDelayMs;
3882 *playout_buffer_delay_ms = playout_delay_ms_;
3883 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3884 "Channel::GetDelayEstimate()");
3885 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00003886}
3887
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003888int Channel::SetInitialPlayoutDelay(int delay_ms)
3889{
3890 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3891 "Channel::SetInitialPlayoutDelay()");
3892 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
3893 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
3894 {
3895 _engineStatisticsPtr->SetLastError(
3896 VE_INVALID_ARGUMENT, kTraceError,
3897 "SetInitialPlayoutDelay() invalid min delay");
3898 return -1;
3899 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003900 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00003901 {
3902 _engineStatisticsPtr->SetLastError(
3903 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3904 "SetInitialPlayoutDelay() failed to set min playout delay");
3905 return -1;
3906 }
3907 return 0;
3908}
3909
3910
niklase@google.com470e71d2011-07-07 08:21:25 +00003911int
3912Channel::SetMinimumPlayoutDelay(int delayMs)
3913{
3914 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3915 "Channel::SetMinimumPlayoutDelay()");
3916 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
3917 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
3918 {
3919 _engineStatisticsPtr->SetLastError(
3920 VE_INVALID_ARGUMENT, kTraceError,
3921 "SetMinimumPlayoutDelay() invalid min delay");
3922 return -1;
3923 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003924 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003925 {
3926 _engineStatisticsPtr->SetLastError(
3927 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
3928 "SetMinimumPlayoutDelay() failed to set min playout delay");
3929 return -1;
3930 }
3931 return 0;
3932}
3933
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003934void Channel::UpdatePlayoutTimestamp(bool rtcp) {
3935 uint32_t playout_timestamp = 0;
3936
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003937 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003938 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3939 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3940 " timestamp from the ACM");
3941 _engineStatisticsPtr->SetLastError(
3942 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3943 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
3944 return;
3945 }
3946
3947 uint16_t delay_ms = 0;
3948 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
3949 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
3950 "Channel::UpdatePlayoutTimestamp() failed to read playout"
3951 " delay from the ADM");
3952 _engineStatisticsPtr->SetLastError(
3953 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3954 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
3955 return;
3956 }
3957
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003958 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003959 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003960 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003961 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
3962 playout_frequency = 8000;
3963 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
3964 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00003965 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003966 }
3967
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00003968 jitter_buffer_playout_timestamp_ = playout_timestamp;
3969
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003970 // Remove the playout delay.
3971 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
3972
3973 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3974 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
3975 playout_timestamp);
3976
3977 if (rtcp) {
3978 playout_timestamp_rtcp_ = playout_timestamp;
3979 } else {
3980 playout_timestamp_rtp_ = playout_timestamp;
3981 }
3982 playout_delay_ms_ = delay_ms;
3983}
3984
3985int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
3986 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3987 "Channel::GetPlayoutTimestamp()");
3988 if (playout_timestamp_rtp_ == 0) {
3989 _engineStatisticsPtr->SetLastError(
3990 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
3991 "GetPlayoutTimestamp() failed to retrieve timestamp");
3992 return -1;
3993 }
3994 timestamp = playout_timestamp_rtp_;
3995 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3996 VoEId(_instanceId,_channelId),
3997 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
3998 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003999}
4000
4001int
4002Channel::SetInitTimestamp(unsigned int timestamp)
4003{
4004 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4005 "Channel::SetInitTimestamp()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004006 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004007 {
4008 _engineStatisticsPtr->SetLastError(
4009 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4010 return -1;
4011 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004012 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004013 {
4014 _engineStatisticsPtr->SetLastError(
4015 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4016 "SetInitTimestamp() failed to set timestamp");
4017 return -1;
4018 }
4019 return 0;
4020}
4021
4022int
4023Channel::SetInitSequenceNumber(short sequenceNumber)
4024{
4025 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4026 "Channel::SetInitSequenceNumber()");
henrika@webrtc.org944cbeb2014-03-18 10:32:33 +00004027 if (channel_state_.Get().sending)
niklase@google.com470e71d2011-07-07 08:21:25 +00004028 {
4029 _engineStatisticsPtr->SetLastError(
4030 VE_SENDING, kTraceError,
4031 "SetInitSequenceNumber() already sending");
4032 return -1;
4033 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004034 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004035 {
4036 _engineStatisticsPtr->SetLastError(
4037 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4038 "SetInitSequenceNumber() failed to set sequence number");
4039 return -1;
4040 }
4041 return 0;
4042}
4043
4044int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004045Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004046{
4047 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4048 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004049 *rtpRtcpModule = _rtpRtcpModule.get();
4050 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004051 return 0;
4052}
4053
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004054// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4055// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004056int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004057Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004058{
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004059 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004060 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004061
4062 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004063 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004064
4065 if (_inputFilePlayerPtr == NULL)
4066 {
4067 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4068 VoEId(_instanceId, _channelId),
4069 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4070 " doesnt exist");
4071 return -1;
4072 }
4073
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004074 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004075 fileSamples,
4076 mixingFrequency) == -1)
4077 {
4078 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4079 VoEId(_instanceId, _channelId),
4080 "Channel::MixOrReplaceAudioWithFile() file mixing "
4081 "failed");
4082 return -1;
4083 }
4084 if (fileSamples == 0)
4085 {
4086 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4087 VoEId(_instanceId, _channelId),
4088 "Channel::MixOrReplaceAudioWithFile() file is ended");
4089 return 0;
4090 }
4091 }
4092
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004093 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004094
4095 if (_mixFileWithMicrophone)
4096 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004097 // Currently file stream is always mono.
4098 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004099 MixWithSat(_audioFrame.data_,
4100 _audioFrame.num_channels_,
4101 fileBuffer.get(),
4102 1,
4103 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004104 }
4105 else
4106 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004107 // Replace ACM audio with file.
4108 // Currently file stream is always mono.
4109 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004110 _audioFrame.UpdateFrame(_channelId,
4111 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004112 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004113 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004114 mixingFrequency,
4115 AudioFrame::kNormalSpeech,
4116 AudioFrame::kVadUnknown,
4117 1);
4118
4119 }
4120 return 0;
4121}
4122
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004123int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004124Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004125 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004126{
4127 assert(mixingFrequency <= 32000);
4128
andrew@webrtc.org8f693302014-04-25 23:10:28 +00004129 scoped_ptr<int16_t[]> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004130 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004131
4132 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004133 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004134
4135 if (_outputFilePlayerPtr == NULL)
4136 {
4137 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4138 VoEId(_instanceId, _channelId),
4139 "Channel::MixAudioWithFile() file mixing failed");
4140 return -1;
4141 }
4142
4143 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004144 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004145 fileSamples,
4146 mixingFrequency) == -1)
4147 {
4148 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4149 VoEId(_instanceId, _channelId),
4150 "Channel::MixAudioWithFile() file mixing failed");
4151 return -1;
4152 }
4153 }
4154
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004155 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004156 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004157 // Currently file stream is always mono.
4158 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +00004159 MixWithSat(audioFrame.data_,
4160 audioFrame.num_channels_,
4161 fileBuffer.get(),
4162 1,
4163 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004164 }
4165 else
4166 {
4167 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004168 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004169 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004170 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004171 return -1;
4172 }
4173
4174 return 0;
4175}
4176
4177int
4178Channel::InsertInbandDtmfTone()
4179{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004180 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004181 if (_inbandDtmfQueue.PendingDtmf() &&
4182 !_inbandDtmfGenerator.IsAddingTone() &&
4183 _inbandDtmfGenerator.DelaySinceLastTone() >
4184 kMinTelephoneEventSeparationMs)
4185 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004186 int8_t eventCode(0);
4187 uint16_t lengthMs(0);
4188 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004189
4190 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
4191 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
4192 if (_playInbandDtmfEvent)
4193 {
4194 // Add tone to output mixer using a reduced length to minimize
4195 // risk of echo.
4196 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
4197 attenuationDb);
4198 }
4199 }
4200
4201 if (_inbandDtmfGenerator.IsAddingTone())
4202 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004203 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004204 _inbandDtmfGenerator.GetSampleRate(frequency);
4205
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004206 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00004207 {
4208 // Update sample rate of Dtmf tone since the mixing frequency
4209 // has changed.
4210 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004211 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00004212 // Reset the tone to be added taking the new sample rate into
4213 // account.
4214 _inbandDtmfGenerator.ResetTone();
4215 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004216
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004217 int16_t toneBuffer[320];
4218 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004219 // Get 10ms tone segment and set time since last tone to zero
4220 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
4221 {
4222 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4223 VoEId(_instanceId, _channelId),
4224 "Channel::EncodeAndSend() inserting Dtmf failed");
4225 return -1;
4226 }
4227
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004228 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004229 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004230 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004231 sample++)
4232 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004233 for (int channel = 0;
4234 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004235 channel++)
4236 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004237 const int index = sample * _audioFrame.num_channels_ + channel;
4238 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004239 }
4240 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004241
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004242 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004243 } else
4244 {
4245 // Add 10ms to "delay-since-last-tone" counter
4246 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
4247 }
4248 return 0;
4249}
4250
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004251int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004252Channel::SendPacketRaw(const void *data, int len, bool RTCP)
4253{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00004254 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004255 if (_transportPtr == NULL)
4256 {
4257 return -1;
4258 }
4259 if (!RTCP)
4260 {
4261 return _transportPtr->SendPacket(_channelId, data, len);
4262 }
4263 else
4264 {
4265 return _transportPtr->SendRTCPPacket(_channelId, data, len);
4266 }
4267}
4268
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004269// Called for incoming RTP packets after successful RTP header parsing.
4270void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
4271 uint16_t sequence_number) {
4272 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4273 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
4274 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00004275
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004276 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004277 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00004278
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004279 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004280 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004281 return;
4282 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004283
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004284 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004285 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00004286
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004287 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
4288 // Even though the actual sampling rate for G.722 audio is
4289 // 16,000 Hz, the RTP clock rate for the G722 payload format is
4290 // 8,000 Hz because that value was erroneously assigned in
4291 // RFC 1890 and must remain unchanged for backward compatibility.
4292 rtp_receive_frequency = 8000;
4293 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
4294 // We are resampling Opus internally to 32,000 Hz until all our
4295 // DSP routines can operate at 48,000 Hz, but the RTP clock
4296 // rate for the Opus payload format is standardized to 48,000 Hz,
4297 // because that is the maximum supported decoding sampling rate.
4298 rtp_receive_frequency = 48000;
4299 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004300
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004301 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
4302 // every incoming packet.
4303 uint32_t timestamp_diff_ms = (rtp_timestamp -
4304 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
henrik.lundin@webrtc.orgd6692992014-03-20 12:04:09 +00004305 if (!IsNewerTimestamp(rtp_timestamp, jitter_buffer_playout_timestamp_) ||
4306 timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
4307 // If |jitter_buffer_playout_timestamp_| is newer than the incoming RTP
4308 // timestamp, the resulting difference is negative, but is set to zero.
4309 // This can happen when a network glitch causes a packet to arrive late,
4310 // and during long comfort noise periods with clock drift.
4311 timestamp_diff_ms = 0;
4312 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004313
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004314 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
4315 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00004316
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004317 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00004318
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004319 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00004320
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004321 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
4322 _recPacketDelayMs = packet_delay_ms;
4323 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004324
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004325 if (_average_jitter_buffer_delay_us == 0) {
4326 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
4327 return;
4328 }
4329
4330 // Filter average delay value using exponential filter (alpha is
4331 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
4332 // risk of rounding error) and compensate for it in GetDelayEstimate()
4333 // later.
4334 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
4335 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00004336}
4337
4338void
4339Channel::RegisterReceiveCodecsToRTPModule()
4340{
4341 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4342 "Channel::RegisterReceiveCodecsToRTPModule()");
4343
4344
4345 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004346 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00004347
4348 for (int idx = 0; idx < nSupportedCodecs; idx++)
4349 {
4350 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004351 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004352 (rtp_receiver_->RegisterReceivePayload(
4353 codec.plname,
4354 codec.pltype,
4355 codec.plfreq,
4356 codec.channels,
4357 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00004358 {
4359 WEBRTC_TRACE(
4360 kTraceWarning,
4361 kTraceVoice,
4362 VoEId(_instanceId, _channelId),
4363 "Channel::RegisterReceiveCodecsToRTPModule() unable"
4364 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
4365 codec.plname, codec.pltype, codec.plfreq,
4366 codec.channels, codec.rate);
4367 }
4368 else
4369 {
4370 WEBRTC_TRACE(
4371 kTraceInfo,
4372 kTraceVoice,
4373 VoEId(_instanceId, _channelId),
4374 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004375 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00004376 "receiver",
4377 codec.plname, codec.pltype, codec.plfreq,
4378 codec.channels, codec.rate);
4379 }
4380 }
4381}
4382
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004383int Channel::SetSecondarySendCodec(const CodecInst& codec,
4384 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004385 // Sanity check for payload type.
4386 if (red_payload_type < 0 || red_payload_type > 127) {
4387 _engineStatisticsPtr->SetLastError(
4388 VE_PLTYPE_ERROR, kTraceError,
4389 "SetRedPayloadType() invalid RED payload type");
4390 return -1;
4391 }
4392
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004393 if (SetRedPayloadType(red_payload_type) < 0) {
4394 _engineStatisticsPtr->SetLastError(
4395 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4396 "SetSecondarySendCodec() Failed to register RED ACM");
4397 return -1;
4398 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004399 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004400 _engineStatisticsPtr->SetLastError(
4401 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4402 "SetSecondarySendCodec() Failed to register secondary send codec in "
4403 "ACM");
4404 return -1;
4405 }
4406
4407 return 0;
4408}
4409
4410void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004411 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004412}
4413
4414int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004415 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004416 _engineStatisticsPtr->SetLastError(
4417 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4418 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
4419 return -1;
4420 }
4421 return 0;
4422}
4423
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004424// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004425int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004426 CodecInst codec;
4427 bool found_red = false;
4428
4429 // Get default RED settings from the ACM database
4430 const int num_codecs = AudioCodingModule::NumberOfCodecs();
4431 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004432 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004433 if (!STR_CASE_CMP(codec.plname, "RED")) {
4434 found_red = true;
4435 break;
4436 }
4437 }
4438
4439 if (!found_red) {
4440 _engineStatisticsPtr->SetLastError(
4441 VE_CODEC_ERROR, kTraceError,
4442 "SetRedPayloadType() RED is not supported");
4443 return -1;
4444 }
4445
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00004446 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004447 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004448 _engineStatisticsPtr->SetLastError(
4449 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4450 "SetRedPayloadType() RED registration in ACM module failed");
4451 return -1;
4452 }
4453
4454 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
4455 _engineStatisticsPtr->SetLastError(
4456 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4457 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
4458 return -1;
4459 }
4460 return 0;
4461}
4462
wu@webrtc.orgebdb0e32014-03-06 23:49:08 +00004463int Channel::SetSendRtpHeaderExtension(bool enable, RTPExtensionType type,
4464 unsigned char id) {
4465 int error = 0;
4466 _rtpRtcpModule->DeregisterSendRtpHeaderExtension(type);
4467 if (enable) {
4468 error = _rtpRtcpModule->RegisterSendRtpHeaderExtension(type, id);
4469 }
4470 return error;
4471}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00004472} // namespace voe
4473} // namespace webrtc