blob: 2724f528f570981bffc90095b8f2d85ef5e28fc2 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
henrika@webrtc.org2919e952012-01-31 08:45:03 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000011#include "webrtc/voice_engine/channel.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
minyue@webrtc.orge509f942013-09-12 17:03:00 +000013#include "webrtc/common.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000014#include "webrtc/modules/audio_device/include/audio_device.h"
15#include "webrtc/modules/audio_processing/include/audio_processing.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000016#include "webrtc/modules/rtp_rtcp/interface/receive_statistics.h"
17#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
18#include "webrtc/modules/rtp_rtcp/interface/rtp_receiver.h"
19#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +000020#include "webrtc/modules/utility/interface/audio_frame_operations.h"
21#include "webrtc/modules/utility/interface/process_thread.h"
22#include "webrtc/modules/utility/interface/rtp_dump.h"
23#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24#include "webrtc/system_wrappers/interface/logging.h"
25#include "webrtc/system_wrappers/interface/trace.h"
26#include "webrtc/voice_engine/include/voe_base.h"
27#include "webrtc/voice_engine/include/voe_external_media.h"
28#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
29#include "webrtc/voice_engine/output_mixer.h"
30#include "webrtc/voice_engine/statistics.h"
31#include "webrtc/voice_engine/transmit_mixer.h"
32#include "webrtc/voice_engine/utility.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000033
34#if defined(_WIN32)
35#include <Qos.h>
36#endif
37
andrew@webrtc.org50419b02012-11-14 19:07:54 +000038namespace webrtc {
39namespace voe {
niklase@google.com470e71d2011-07-07 08:21:25 +000040
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +000041// Extend the default RTCP statistics struct with max_jitter, defined as the
42// maximum jitter value seen in an RTCP report block.
43struct ChannelStatistics : public RtcpStatistics {
44 ChannelStatistics() : rtcp(), max_jitter(0) {}
45
46 RtcpStatistics rtcp;
47 uint32_t max_jitter;
48};
49
50// Statistics callback, called at each generation of a new RTCP report block.
51class StatisticsProxy : public RtcpStatisticsCallback {
52 public:
53 StatisticsProxy(uint32_t ssrc)
54 : stats_lock_(CriticalSectionWrapper::CreateCriticalSection()),
55 ssrc_(ssrc) {}
56 virtual ~StatisticsProxy() {}
57
58 virtual void StatisticsUpdated(const RtcpStatistics& statistics,
59 uint32_t ssrc) OVERRIDE {
60 if (ssrc != ssrc_)
61 return;
62
63 CriticalSectionScoped cs(stats_lock_.get());
64 stats_.rtcp = statistics;
65 if (statistics.jitter > stats_.max_jitter) {
66 stats_.max_jitter = statistics.jitter;
67 }
68 }
69
70 void ResetStatistics() {
71 CriticalSectionScoped cs(stats_lock_.get());
72 stats_ = ChannelStatistics();
73 }
74
75 ChannelStatistics GetStats() {
76 CriticalSectionScoped cs(stats_lock_.get());
77 return stats_;
78 }
79
80 private:
81 // StatisticsUpdated calls are triggered from threads in the RTP module,
82 // while GetStats calls can be triggered from the public voice engine API,
83 // hence synchronization is needed.
84 scoped_ptr<CriticalSectionWrapper> stats_lock_;
85 const uint32_t ssrc_;
86 ChannelStatistics stats_;
87};
88
pbos@webrtc.org6141e132013-04-09 10:09:10 +000089int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +000090Channel::SendData(FrameType frameType,
pbos@webrtc.org6141e132013-04-09 10:09:10 +000091 uint8_t payloadType,
92 uint32_t timeStamp,
93 const uint8_t* payloadData,
94 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +000095 const RTPFragmentationHeader* fragmentation)
96{
97 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
98 "Channel::SendData(frameType=%u, payloadType=%u, timeStamp=%u,"
99 " payloadSize=%u, fragmentation=0x%x)",
100 frameType, payloadType, timeStamp, payloadSize, fragmentation);
101
102 if (_includeAudioLevelIndication)
103 {
104 // Store current audio level in the RTP/RTCP module.
105 // The level will be used in combination with voice-activity state
106 // (frameType) to add an RTP header extension
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000107 _rtpRtcpModule->SetAudioLevel(rtp_audioproc_->level_estimator()->RMS());
niklase@google.com470e71d2011-07-07 08:21:25 +0000108 }
109
110 // Push data from ACM to RTP/RTCP-module to deliver audio frame for
111 // packetization.
112 // This call will trigger Transport::SendPacket() from the RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +0000113 if (_rtpRtcpModule->SendOutgoingData((FrameType&)frameType,
niklase@google.com470e71d2011-07-07 08:21:25 +0000114 payloadType,
115 timeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +0000116 // Leaving the time when this frame was
117 // received from the capture device as
118 // undefined for voice for now.
119 -1,
niklase@google.com470e71d2011-07-07 08:21:25 +0000120 payloadData,
121 payloadSize,
122 fragmentation) == -1)
123 {
124 _engineStatisticsPtr->SetLastError(
125 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
126 "Channel::SendData() failed to send data to RTP/RTCP module");
127 return -1;
128 }
129
130 _lastLocalTimeStamp = timeStamp;
131 _lastPayloadType = payloadType;
132
133 return 0;
134}
135
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000136int32_t
137Channel::InFrameType(int16_t frameType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000138{
139 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
140 "Channel::InFrameType(frameType=%d)", frameType);
141
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000142 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000143 // 1 indicates speech
144 _sendFrameType = (frameType == 1) ? 1 : 0;
145 return 0;
146}
147
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000148int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000149Channel::OnRxVadDetected(int vadDecision)
niklase@google.com470e71d2011-07-07 08:21:25 +0000150{
151 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
152 "Channel::OnRxVadDetected(vadDecision=%d)", vadDecision);
153
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000154 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000155 if (_rxVadObserverPtr)
156 {
157 _rxVadObserverPtr->OnRxVad(_channelId, vadDecision);
158 }
159
160 return 0;
161}
162
163int
164Channel::SendPacket(int channel, const void *data, int len)
165{
166 channel = VoEChannelId(channel);
167 assert(channel == _channelId);
168
169 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
170 "Channel::SendPacket(channel=%d, len=%d)", channel, len);
171
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000172 CriticalSectionScoped cs(&_callbackCritSect);
173
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 if (_transportPtr == NULL)
175 {
176 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
177 "Channel::SendPacket() failed to send RTP packet due to"
178 " invalid transport object");
179 return -1;
180 }
181
182 // Insert extra RTP packet using if user has called the InsertExtraRTPPacket
183 // API
184 if (_insertExtraRTPPacket)
185 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000186 uint8_t* rtpHdr = (uint8_t*)data;
187 uint8_t M_PT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 if (_extraMarkerBit)
189 {
190 M_PT = 0x80; // set the M-bit
191 }
192 M_PT += _extraPayloadType; // set the payload type
193 *(++rtpHdr) = M_PT; // modify the M|PT-byte within the RTP header
194 _insertExtraRTPPacket = false; // insert one packet only
195 }
196
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000197 uint8_t* bufferToSendPtr = (uint8_t*)data;
198 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000199
200 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000201 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 {
203 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
204 VoEId(_instanceId,_channelId),
205 "Channel::SendPacket() RTP dump to output file failed");
206 }
207
208 // SRTP or External encryption
209 if (_encrypting)
210 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 if (_encryptionPtr)
212 {
213 if (!_encryptionRTPBufferPtr)
214 {
215 // Allocate memory for encryption buffer one time only
216 _encryptionRTPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000217 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
xians@webrtc.org51253502012-10-25 13:58:02 +0000218 memset(_encryptionRTPBufferPtr, 0,
219 kVoiceEngineMaxIpPacketSizeBytes);
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 }
221
222 // Perform encryption (SRTP or external)
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000223 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 _encryptionPtr->encrypt(_channelId,
225 bufferToSendPtr,
226 _encryptionRTPBufferPtr,
227 bufferLength,
228 (int*)&encryptedBufferLength);
229 if (encryptedBufferLength <= 0)
230 {
231 _engineStatisticsPtr->SetLastError(
232 VE_ENCRYPTION_FAILED,
233 kTraceError, "Channel::SendPacket() encryption failed");
234 return -1;
235 }
236
237 // Replace default data buffer with encrypted buffer
238 bufferToSendPtr = _encryptionRTPBufferPtr;
239 bufferLength = encryptedBufferLength;
240 }
241 }
242
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000243 int n = _transportPtr->SendPacket(channel, bufferToSendPtr,
244 bufferLength);
245 if (n < 0) {
246 std::string transport_name =
247 _externalTransport ? "external transport" : "WebRtc sockets";
248 WEBRTC_TRACE(kTraceError, kTraceVoice,
249 VoEId(_instanceId,_channelId),
250 "Channel::SendPacket() RTP transmission using %s failed",
251 transport_name.c_str());
252 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000253 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000254 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000255}
256
257int
258Channel::SendRTCPPacket(int channel, const void *data, int len)
259{
260 channel = VoEChannelId(channel);
261 assert(channel == _channelId);
262
263 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
264 "Channel::SendRTCPPacket(channel=%d, len=%d)", channel, len);
265
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000266 CriticalSectionScoped cs(&_callbackCritSect);
267 if (_transportPtr == NULL)
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 {
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000269 WEBRTC_TRACE(kTraceError, kTraceVoice,
270 VoEId(_instanceId,_channelId),
271 "Channel::SendRTCPPacket() failed to send RTCP packet"
272 " due to invalid transport object");
273 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000274 }
275
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000276 uint8_t* bufferToSendPtr = (uint8_t*)data;
277 int32_t bufferLength = len;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278
279 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000280 if (_rtpDumpOut.DumpPacket((const uint8_t*)data, len) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000281 {
282 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
283 VoEId(_instanceId,_channelId),
284 "Channel::SendPacket() RTCP dump to output file failed");
285 }
286
287 // SRTP or External encryption
288 if (_encrypting)
289 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000290 if (_encryptionPtr)
291 {
292 if (!_encryptionRTCPBufferPtr)
293 {
294 // Allocate memory for encryption buffer one time only
295 _encryptionRTCPBufferPtr =
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000296 new uint8_t[kVoiceEngineMaxIpPacketSizeBytes];
niklase@google.com470e71d2011-07-07 08:21:25 +0000297 }
298
299 // Perform encryption (SRTP or external).
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000300 int32_t encryptedBufferLength = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000301 _encryptionPtr->encrypt_rtcp(_channelId,
302 bufferToSendPtr,
303 _encryptionRTCPBufferPtr,
304 bufferLength,
305 (int*)&encryptedBufferLength);
306 if (encryptedBufferLength <= 0)
307 {
308 _engineStatisticsPtr->SetLastError(
309 VE_ENCRYPTION_FAILED, kTraceError,
310 "Channel::SendRTCPPacket() encryption failed");
311 return -1;
312 }
313
314 // Replace default data buffer with encrypted buffer
315 bufferToSendPtr = _encryptionRTCPBufferPtr;
316 bufferLength = encryptedBufferLength;
317 }
318 }
319
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000320 int n = _transportPtr->SendRTCPPacket(channel,
321 bufferToSendPtr,
322 bufferLength);
323 if (n < 0) {
324 std::string transport_name =
325 _externalTransport ? "external transport" : "WebRtc sockets";
326 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
327 VoEId(_instanceId,_channelId),
328 "Channel::SendRTCPPacket() transmission using %s failed",
329 transport_name.c_str());
330 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000331 }
wu@webrtc.orgfb648da2013-10-18 21:10:51 +0000332 return n;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333}
334
335void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000336Channel::OnPlayTelephoneEvent(int32_t id,
337 uint8_t event,
338 uint16_t lengthMs,
339 uint8_t volume)
niklase@google.com470e71d2011-07-07 08:21:25 +0000340{
341 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
342 "Channel::OnPlayTelephoneEvent(id=%d, event=%u, lengthMs=%u,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +0000343 " volume=%u)", id, event, lengthMs, volume);
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
345 if (!_playOutbandDtmfEvent || (event > 15))
346 {
347 // Ignore callback since feedback is disabled or event is not a
348 // Dtmf tone event.
349 return;
350 }
351
352 assert(_outputMixerPtr != NULL);
353
354 // Start playing out the Dtmf tone (if playout is enabled).
355 // Reduce length of tone with 80ms to the reduce risk of echo.
356 _outputMixerPtr->PlayDtmfTone(event, lengthMs - 80, volume);
357}
358
359void
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000360Channel::OnIncomingSSRCChanged(int32_t id, uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000361{
362 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
363 "Channel::OnIncomingSSRCChanged(id=%d, SSRC=%d)",
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000364 id, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000365
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000366 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000367 assert(channel == _channelId);
368
dwkang@webrtc.orgb295a3f2013-08-29 07:34:12 +0000369 // Update ssrc so that NTP for AV sync can be updated.
370 _rtpRtcpModule->SetRemoteSSRC(ssrc);
371
niklase@google.com470e71d2011-07-07 08:21:25 +0000372 if (_rtpObserver)
373 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000374 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000375
376 if (_rtpObserverPtr)
377 {
378 // Send new SSRC to registered observer using callback
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000379 _rtpObserverPtr->OnIncomingSSRCChanged(channel, ssrc);
niklase@google.com470e71d2011-07-07 08:21:25 +0000380 }
381 }
382}
383
pbos@webrtc.org92135212013-05-14 08:31:39 +0000384void Channel::OnIncomingCSRCChanged(int32_t id,
385 uint32_t CSRC,
386 bool added)
niklase@google.com470e71d2011-07-07 08:21:25 +0000387{
388 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
389 "Channel::OnIncomingCSRCChanged(id=%d, CSRC=%d, added=%d)",
390 id, CSRC, added);
391
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000392 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000393 assert(channel == _channelId);
394
395 if (_rtpObserver)
396 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000397 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000398
399 if (_rtpObserverPtr)
400 {
401 _rtpObserverPtr->OnIncomingCSRCChanged(channel, CSRC, added);
402 }
403 }
404}
405
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000406void Channel::ResetStatistics(uint32_t ssrc) {
407 StreamStatistician* statistician =
408 rtp_receive_statistics_->GetStatistician(ssrc);
409 if (statistician) {
410 statistician->ResetStatistics();
411 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000412 statistics_proxy_->ResetStatistics();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000413}
414
niklase@google.com470e71d2011-07-07 08:21:25 +0000415void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000416Channel::OnApplicationDataReceived(int32_t id,
417 uint8_t subType,
418 uint32_t name,
419 uint16_t length,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000420 const uint8_t* data)
niklase@google.com470e71d2011-07-07 08:21:25 +0000421{
422 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
423 "Channel::OnApplicationDataReceived(id=%d, subType=%u,"
424 " name=%u, length=%u)",
425 id, subType, name, length);
426
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000427 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428 assert(channel == _channelId);
429
430 if (_rtcpObserver)
431 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000432 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000433
434 if (_rtcpObserverPtr)
435 {
436 _rtcpObserverPtr->OnApplicationDataReceived(channel,
437 subType,
438 name,
439 data,
440 length);
441 }
442 }
443}
444
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000445int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000446Channel::OnInitializeDecoder(
pbos@webrtc.org92135212013-05-14 08:31:39 +0000447 int32_t id,
448 int8_t payloadType,
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +0000449 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
pbos@webrtc.org92135212013-05-14 08:31:39 +0000450 int frequency,
451 uint8_t channels,
452 uint32_t rate)
niklase@google.com470e71d2011-07-07 08:21:25 +0000453{
454 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
455 "Channel::OnInitializeDecoder(id=%d, payloadType=%d, "
456 "payloadName=%s, frequency=%u, channels=%u, rate=%u)",
457 id, payloadType, payloadName, frequency, channels, rate);
458
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000459 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000460
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000461 CodecInst receiveCodec = {0};
462 CodecInst dummyCodec = {0};
niklase@google.com470e71d2011-07-07 08:21:25 +0000463
464 receiveCodec.pltype = payloadType;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 receiveCodec.plfreq = frequency;
466 receiveCodec.channels = channels;
467 receiveCodec.rate = rate;
henrika@webrtc.orgf75901f2012-01-16 08:45:42 +0000468 strncpy(receiveCodec.plname, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +0000469
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000470 audio_coding_->Codec(payloadName, &dummyCodec, frequency, channels);
niklase@google.com470e71d2011-07-07 08:21:25 +0000471 receiveCodec.pacsize = dummyCodec.pacsize;
472
473 // Register the new codec to the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000474 if (audio_coding_->RegisterReceiveCodec(receiveCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 {
476 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000477 VoEId(_instanceId, _channelId),
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 "Channel::OnInitializeDecoder() invalid codec ("
479 "pt=%d, name=%s) received - 1", payloadType, payloadName);
480 _engineStatisticsPtr->SetLastError(VE_AUDIO_CODING_MODULE_ERROR);
481 return -1;
482 }
483
484 return 0;
485}
486
487void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000488Channel::OnPacketTimeout(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000489{
490 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
491 "Channel::OnPacketTimeout(id=%d)", id);
492
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000493 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 if (_voiceEngineObserverPtr)
495 {
496 if (_receiving || _externalTransport)
497 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000498 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000499 assert(channel == _channelId);
500 // Ensure that next OnReceivedPacket() callback will trigger
501 // a VE_PACKET_RECEIPT_RESTARTED callback.
502 _rtpPacketTimedOut = true;
503 // Deliver callback to the observer
504 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
505 VoEId(_instanceId,_channelId),
506 "Channel::OnPacketTimeout() => "
507 "CallbackOnError(VE_RECEIVE_PACKET_TIMEOUT)");
508 _voiceEngineObserverPtr->CallbackOnError(channel,
509 VE_RECEIVE_PACKET_TIMEOUT);
510 }
511 }
512}
513
514void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000515Channel::OnReceivedPacket(int32_t id,
516 RtpRtcpPacketType packetType)
niklase@google.com470e71d2011-07-07 08:21:25 +0000517{
518 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
519 "Channel::OnReceivedPacket(id=%d, packetType=%d)",
520 id, packetType);
521
andrew@webrtc.orgceb148c2011-08-23 17:53:54 +0000522 assert(VoEChannelId(id) == _channelId);
niklase@google.com470e71d2011-07-07 08:21:25 +0000523
524 // Notify only for the case when we have restarted an RTP session.
525 if (_rtpPacketTimedOut && (kPacketRtp == packetType))
526 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000527 CriticalSectionScoped cs(_callbackCritSectPtr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 if (_voiceEngineObserverPtr)
529 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000530 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000531 assert(channel == _channelId);
532 // Reset timeout mechanism
533 _rtpPacketTimedOut = false;
534 // Deliver callback to the observer
535 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
536 VoEId(_instanceId,_channelId),
537 "Channel::OnPacketTimeout() =>"
538 " CallbackOnError(VE_PACKET_RECEIPT_RESTARTED)");
539 _voiceEngineObserverPtr->CallbackOnError(
540 channel,
541 VE_PACKET_RECEIPT_RESTARTED);
542 }
543 }
544}
545
546void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000547Channel::OnPeriodicDeadOrAlive(int32_t id,
548 RTPAliveType alive)
niklase@google.com470e71d2011-07-07 08:21:25 +0000549{
550 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
551 "Channel::OnPeriodicDeadOrAlive(id=%d, alive=%d)", id, alive);
552
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000553 {
554 CriticalSectionScoped cs(&_callbackCritSect);
555 if (!_connectionObserver)
556 return;
557 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000558
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000559 int32_t channel = VoEChannelId(id);
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 assert(channel == _channelId);
561
562 // Use Alive as default to limit risk of false Dead detections
563 bool isAlive(true);
564
565 // Always mark the connection as Dead when the module reports kRtpDead
566 if (kRtpDead == alive)
567 {
568 isAlive = false;
569 }
570
571 // It is possible that the connection is alive even if no RTP packet has
572 // been received for a long time since the other side might use VAD/DTX
573 // and a low SID-packet update rate.
574 if ((kRtpNoRtp == alive) && _playing)
575 {
576 // Detect Alive for all NetEQ states except for the case when we are
577 // in PLC_CNG state.
578 // PLC_CNG <=> background noise only due to long expand or error.
579 // Note that, the case where the other side stops sending during CNG
580 // state will be detected as Alive. Dead is is not set until after
581 // missing RTCP packets for at least twelve seconds (handled
582 // internally by the RTP/RTCP module).
583 isAlive = (_outputSpeechType != AudioFrame::kPLCCNG);
584 }
585
586 UpdateDeadOrAliveCounters(isAlive);
587
588 // Send callback to the registered observer
589 if (_connectionObserver)
590 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000591 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 if (_connectionObserverPtr)
593 {
594 _connectionObserverPtr->OnPeriodicDeadOrAlive(channel, isAlive);
595 }
596 }
597}
598
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000599int32_t
600Channel::OnReceivedPayloadData(const uint8_t* payloadData,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000601 uint16_t payloadSize,
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 const WebRtcRTPHeader* rtpHeader)
603{
604 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
605 "Channel::OnReceivedPayloadData(payloadSize=%d,"
606 " payloadType=%u, audioChannel=%u)",
607 payloadSize,
608 rtpHeader->header.payloadType,
609 rtpHeader->type.Audio.channel);
610
roosa@google.com0870f022012-12-12 21:31:41 +0000611 _lastRemoteTimeStamp = rtpHeader->header.timestamp;
612
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 if (!_playing)
614 {
615 // Avoid inserting into NetEQ when we are not playing. Count the
616 // packet as discarded.
617 WEBRTC_TRACE(kTraceStream, kTraceVoice,
618 VoEId(_instanceId, _channelId),
619 "received packet is discarded since playing is not"
620 " activated");
621 _numberOfDiscardedPackets++;
622 return 0;
623 }
624
625 // Push the incoming payload (parsed and ready for decoding) into the ACM
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000626 if (audio_coding_->IncomingPacket(payloadData,
627 payloadSize,
628 *rtpHeader) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 {
630 _engineStatisticsPtr->SetLastError(
631 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
632 "Channel::OnReceivedPayloadData() unable to push data to the ACM");
633 return -1;
634 }
635
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000636 // Update the packet delay.
niklase@google.com470e71d2011-07-07 08:21:25 +0000637 UpdatePacketDelay(rtpHeader->header.timestamp,
638 rtpHeader->header.sequenceNumber);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000639
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000640 uint16_t round_trip_time = 0;
641 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), &round_trip_time,
642 NULL, NULL, NULL);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000643
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000644 std::vector<uint16_t> nack_list = audio_coding_->GetNackList(
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000645 round_trip_time);
646 if (!nack_list.empty()) {
647 // Can't use nack_list.data() since it's not supported by all
648 // compilers.
649 ResendPackets(&(nack_list[0]), static_cast<int>(nack_list.size()));
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +0000650 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 return 0;
652}
653
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000654bool Channel::OnRecoveredPacket(const uint8_t* rtp_packet,
655 int rtp_packet_length) {
656 RTPHeader header;
657 if (!rtp_header_parser_->Parse(rtp_packet, rtp_packet_length, &header)) {
658 WEBRTC_TRACE(kTraceDebug, webrtc::kTraceVoice, _channelId,
659 "IncomingPacket invalid RTP header");
660 return false;
661 }
662 header.payload_type_frequency =
663 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
664 if (header.payload_type_frequency < 0)
665 return false;
666 return ReceivePacket(rtp_packet, rtp_packet_length, header, false);
667}
668
pbos@webrtc.org92135212013-05-14 08:31:39 +0000669int32_t Channel::GetAudioFrame(int32_t id, AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000670{
671 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
672 "Channel::GetAudioFrame(id=%d)", id);
673
674 // Get 10ms raw PCM data from the ACM (mixer limits output frequency)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000675 if (audio_coding_->PlayoutData10Ms(audioFrame.sample_rate_hz_,
676 &audioFrame) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 {
678 WEBRTC_TRACE(kTraceError, kTraceVoice,
679 VoEId(_instanceId,_channelId),
680 "Channel::GetAudioFrame() PlayoutData10Ms() failed!");
andrew@webrtc.org7859e102012-01-13 00:30:11 +0000681 // In all likelihood, the audio in this frame is garbage. We return an
682 // error so that the audio mixer module doesn't add it to the mix. As
683 // a result, it won't be played out and the actions skipped here are
684 // irrelevant.
685 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000686 }
687
688 if (_RxVadDetection)
689 {
690 UpdateRxVadDetection(audioFrame);
691 }
692
693 // Convert module ID to internal VoE channel ID
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000694 audioFrame.id_ = VoEChannelId(audioFrame.id_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 // Store speech type for dead-or-alive detection
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000696 _outputSpeechType = audioFrame.speech_type_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000697
698 // Perform far-end AudioProcessing module processing on the received signal
699 if (_rxApmIsEnabled)
700 {
701 ApmProcessRx(audioFrame);
702 }
703
wu@webrtc.org63420662013-10-17 18:28:55 +0000704 float output_gain = 1.0f;
705 float left_pan = 1.0f;
706 float right_pan = 1.0f;
niklase@google.com470e71d2011-07-07 08:21:25 +0000707 {
wu@webrtc.org63420662013-10-17 18:28:55 +0000708 CriticalSectionScoped cs(&volume_settings_critsect_);
709 output_gain = _outputGain;
710 left_pan = _panLeft;
711 right_pan= _panRight;
712 }
713
714 // Output volume scaling
715 if (output_gain < 0.99f || output_gain > 1.01f)
716 {
717 AudioFrameOperations::ScaleWithSat(output_gain, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000718 }
719
720 // Scale left and/or right channel(s) if stereo and master balance is
721 // active
722
wu@webrtc.org63420662013-10-17 18:28:55 +0000723 if (left_pan != 1.0f || right_pan != 1.0f)
niklase@google.com470e71d2011-07-07 08:21:25 +0000724 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000725 if (audioFrame.num_channels_ == 1)
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 {
727 // Emulate stereo mode since panning is active.
728 // The mono signal is copied to both left and right channels here.
andrew@webrtc.org4ecea3e2012-06-27 03:25:31 +0000729 AudioFrameOperations::MonoToStereo(&audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000730 }
731 // For true stereo mode (when we are receiving a stereo signal), no
732 // action is needed.
733
734 // Do the panning operation (the audio frame contains stereo at this
735 // stage)
wu@webrtc.org63420662013-10-17 18:28:55 +0000736 AudioFrameOperations::Scale(left_pan, right_pan, audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000737 }
738
739 // Mix decoded PCM output with file if file mixing is enabled
740 if (_outputFilePlaying)
741 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000742 MixAudioWithFile(audioFrame, audioFrame.sample_rate_hz_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000743 }
744
745 // Place channel in on-hold state (~muted) if on-hold is activated
746 if (_outputIsOnHold)
747 {
748 AudioFrameOperations::Mute(audioFrame);
749 }
750
751 // External media
752 if (_outputExternalMedia)
753 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000754 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000755 const bool isStereo = (audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000756 if (_outputExternalMediaCallbackPtr)
757 {
758 _outputExternalMediaCallbackPtr->Process(
759 _channelId,
760 kPlaybackPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000761 (int16_t*)audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000762 audioFrame.samples_per_channel_,
763 audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000764 isStereo);
765 }
766 }
767
768 // Record playout if enabled
769 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000770 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000771
772 if (_outputFileRecording && _outputFileRecorderPtr)
773 {
niklas.enbom@webrtc.org5398d952012-03-26 08:11:25 +0000774 _outputFileRecorderPtr->RecordAudioToFile(audioFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000775 }
776 }
777
778 // Measure audio level (0-9)
779 _outputAudioLevel.ComputeLevel(audioFrame);
780
781 return 0;
782}
783
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000784int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +0000785Channel::NeededFrequency(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000786{
787 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
788 "Channel::NeededFrequency(id=%d)", id);
789
790 int highestNeeded = 0;
791
792 // Determine highest needed receive frequency
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000793 int32_t receiveFrequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
795 // Return the bigger of playout and receive frequency in the ACM.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000796 if (audio_coding_->PlayoutFrequency() > receiveFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +0000797 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000798 highestNeeded = audio_coding_->PlayoutFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +0000799 }
800 else
801 {
802 highestNeeded = receiveFrequency;
803 }
804
805 // Special case, if we're playing a file on the playout side
806 // we take that frequency into consideration as well
807 // This is not needed on sending side, since the codec will
808 // limit the spectrum anyway.
809 if (_outputFilePlaying)
810 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000811 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000812 if (_outputFilePlayerPtr && _outputFilePlaying)
813 {
814 if(_outputFilePlayerPtr->Frequency()>highestNeeded)
815 {
816 highestNeeded=_outputFilePlayerPtr->Frequency();
817 }
818 }
819 }
820
821 return(highestNeeded);
822}
823
pbos@webrtc.org6141e132013-04-09 10:09:10 +0000824int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000825Channel::CreateChannel(Channel*& channel,
pbos@webrtc.org92135212013-05-14 08:31:39 +0000826 int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000827 uint32_t instanceId,
828 const Config& config)
niklase@google.com470e71d2011-07-07 08:21:25 +0000829{
830 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(instanceId,channelId),
831 "Channel::CreateChannel(channelId=%d, instanceId=%d)",
832 channelId, instanceId);
833
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000834 channel = new Channel(channelId, instanceId, config);
niklase@google.com470e71d2011-07-07 08:21:25 +0000835 if (channel == NULL)
836 {
837 WEBRTC_TRACE(kTraceMemory, kTraceVoice,
838 VoEId(instanceId,channelId),
839 "Channel::CreateChannel() unable to allocate memory for"
840 " channel");
841 return -1;
842 }
843 return 0;
844}
845
846void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000847Channel::PlayNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000848{
849 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
850 "Channel::PlayNotification(id=%d, durationMs=%d)",
851 id, durationMs);
852
853 // Not implement yet
854}
855
856void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000857Channel::RecordNotification(int32_t id, uint32_t durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000858{
859 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
860 "Channel::RecordNotification(id=%d, durationMs=%d)",
861 id, durationMs);
862
863 // Not implement yet
864}
865
866void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000867Channel::PlayFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000868{
869 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
870 "Channel::PlayFileEnded(id=%d)", id);
871
872 if (id == _inputFilePlayerId)
873 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000874 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000875
876 _inputFilePlaying = false;
877 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
878 VoEId(_instanceId,_channelId),
879 "Channel::PlayFileEnded() => input file player module is"
880 " shutdown");
881 }
882 else if (id == _outputFilePlayerId)
883 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000884 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000885
886 _outputFilePlaying = false;
887 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
888 VoEId(_instanceId,_channelId),
889 "Channel::PlayFileEnded() => output file player module is"
890 " shutdown");
891 }
892}
893
894void
pbos@webrtc.org92135212013-05-14 08:31:39 +0000895Channel::RecordFileEnded(int32_t id)
niklase@google.com470e71d2011-07-07 08:21:25 +0000896{
897 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
898 "Channel::RecordFileEnded(id=%d)", id);
899
900 assert(id == _outputFileRecorderId);
901
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +0000902 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +0000903
904 _outputFileRecording = false;
905 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
906 VoEId(_instanceId,_channelId),
907 "Channel::RecordFileEnded() => output file recorder module is"
908 " shutdown");
909}
910
pbos@webrtc.org92135212013-05-14 08:31:39 +0000911Channel::Channel(int32_t channelId,
minyue@webrtc.orge509f942013-09-12 17:03:00 +0000912 uint32_t instanceId,
913 const Config& config) :
niklase@google.com470e71d2011-07-07 08:21:25 +0000914 _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
915 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
wu@webrtc.org63420662013-10-17 18:28:55 +0000916 volume_settings_critsect_(*CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000917 _instanceId(instanceId),
xians@google.com22963ab2011-08-03 12:40:23 +0000918 _channelId(channelId),
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +0000919 rtp_header_parser_(RtpHeaderParser::Create()),
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000920 rtp_payload_registry_(
921 new RTPPayloadRegistry(channelId,
922 RTPPayloadStrategy::CreateStrategy(true))),
923 rtp_receive_statistics_(ReceiveStatistics::Create(
924 Clock::GetRealTimeClock())),
925 rtp_receiver_(RtpReceiver::CreateAudioReceiver(
926 VoEModuleId(instanceId, channelId), Clock::GetRealTimeClock(), this,
927 this, this, rtp_payload_registry_.get())),
928 telephone_event_handler_(rtp_receiver_->GetTelephoneEventHandler()),
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +0000929 audio_coding_(config.Get<AudioCodingModuleFactory>().Create(
xians@google.com22963ab2011-08-03 12:40:23 +0000930 VoEModuleId(instanceId, channelId))),
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 _rtpDumpIn(*RtpDump::CreateRtpDump()),
932 _rtpDumpOut(*RtpDump::CreateRtpDump()),
niklase@google.com470e71d2011-07-07 08:21:25 +0000933 _outputAudioLevel(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 _externalTransport(false),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000935 _audioLevel_dBov(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000936 _inputFilePlayerPtr(NULL),
937 _outputFilePlayerPtr(NULL),
938 _outputFileRecorderPtr(NULL),
939 // Avoid conflict with other channels by adding 1024 - 1026,
940 // won't use as much as 1024 channels.
941 _inputFilePlayerId(VoEModuleId(instanceId, channelId) + 1024),
942 _outputFilePlayerId(VoEModuleId(instanceId, channelId) + 1025),
943 _outputFileRecorderId(VoEModuleId(instanceId, channelId) + 1026),
944 _inputFilePlaying(false),
945 _outputFilePlaying(false),
946 _outputFileRecording(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000947 _inbandDtmfQueue(VoEModuleId(instanceId, channelId)),
948 _inbandDtmfGenerator(VoEModuleId(instanceId, channelId)),
niklase@google.com470e71d2011-07-07 08:21:25 +0000949 _inputExternalMedia(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000950 _outputExternalMedia(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000951 _inputExternalMediaCallbackPtr(NULL),
952 _outputExternalMediaCallbackPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000953 _encryptionRTPBufferPtr(NULL),
954 _decryptionRTPBufferPtr(NULL),
955 _encryptionRTCPBufferPtr(NULL),
956 _decryptionRTCPBufferPtr(NULL),
957 _timeStamp(0), // This is just an offset, RTP module will add it's own random offset
958 _sendTelephoneEventPayloadType(106),
turaj@webrtc.org167b6df2013-12-13 21:05:07 +0000959 jitter_buffer_playout_timestamp_(0),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +0000960 playout_timestamp_rtp_(0),
961 playout_timestamp_rtcp_(0),
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000962 playout_delay_ms_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000963 _numberOfDiscardedPackets(0),
xians@webrtc.org09e8c472013-07-31 16:30:19 +0000964 send_sequence_number_(0),
xians@google.com22963ab2011-08-03 12:40:23 +0000965 _engineStatisticsPtr(NULL),
henrika@webrtc.org2919e952012-01-31 08:45:03 +0000966 _outputMixerPtr(NULL),
967 _transmitMixerPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000968 _moduleProcessThreadPtr(NULL),
969 _audioDeviceModulePtr(NULL),
970 _voiceEngineObserverPtr(NULL),
971 _callbackCritSectPtr(NULL),
972 _transportPtr(NULL),
973 _encryptionPtr(NULL),
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000974 rx_audioproc_(AudioProcessing::Create(VoEModuleId(instanceId, channelId))),
xians@google.com22963ab2011-08-03 12:40:23 +0000975 _rxVadObserverPtr(NULL),
976 _oldVadDecision(-1),
977 _sendFrameType(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 _rtpObserverPtr(NULL),
979 _rtcpObserverPtr(NULL),
xians@google.com22963ab2011-08-03 12:40:23 +0000980 _outputIsOnHold(false),
981 _externalPlayout(false),
roosa@google.com1b60ceb2012-12-12 23:00:29 +0000982 _externalMixing(false),
xians@google.com22963ab2011-08-03 12:40:23 +0000983 _inputIsOnHold(false),
984 _playing(false),
985 _sending(false),
986 _receiving(false),
987 _mixFileWithMicrophone(false),
988 _rtpObserver(false),
989 _rtcpObserver(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000990 _mute(false),
991 _panLeft(1.0f),
992 _panRight(1.0f),
993 _outputGain(1.0f),
xians@google.com22963ab2011-08-03 12:40:23 +0000994 _encrypting(false),
995 _decrypting(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000996 _playOutbandDtmfEvent(false),
997 _playInbandDtmfEvent(false),
niklase@google.com470e71d2011-07-07 08:21:25 +0000998 _extraPayloadType(0),
999 _insertExtraRTPPacket(false),
1000 _extraMarkerBit(false),
1001 _lastLocalTimeStamp(0),
roosa@google.com0870f022012-12-12 21:31:41 +00001002 _lastRemoteTimeStamp(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001003 _lastPayloadType(0),
xians@google.com22963ab2011-08-03 12:40:23 +00001004 _includeAudioLevelIndication(false),
niklase@google.com470e71d2011-07-07 08:21:25 +00001005 _rtpPacketTimedOut(false),
1006 _rtpPacketTimeOutIsEnabled(false),
1007 _rtpTimeOutSeconds(0),
1008 _connectionObserver(false),
1009 _connectionObserverPtr(NULL),
1010 _countAliveDetections(0),
1011 _countDeadDetections(0),
1012 _outputSpeechType(AudioFrame::kNormalSpeech),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00001013 _average_jitter_buffer_delay_us(0),
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00001014 least_required_delay_ms_(0),
niklase@google.com470e71d2011-07-07 08:21:25 +00001015 _previousTimestamp(0),
1016 _recPacketDelayMs(20),
1017 _RxVadDetection(false),
1018 _rxApmIsEnabled(false),
1019 _rxAgcIsEnabled(false),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00001020 _rxNsIsEnabled(false),
1021 restored_packet_in_use_(false)
niklase@google.com470e71d2011-07-07 08:21:25 +00001022{
1023 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1024 "Channel::Channel() - ctor");
1025 _inbandDtmfQueue.ResetDtmf();
1026 _inbandDtmfGenerator.Init();
1027 _outputAudioLevel.Clear();
1028
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001029 RtpRtcp::Configuration configuration;
1030 configuration.id = VoEModuleId(instanceId, channelId);
1031 configuration.audio = true;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001032 configuration.outgoing_transport = this;
1033 configuration.rtcp_feedback = this;
1034 configuration.audio_messages = this;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001035 configuration.receive_statistics = rtp_receive_statistics_.get();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001036
1037 _rtpRtcpModule.reset(RtpRtcp::CreateRtpRtcp(configuration));
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001038
1039 statistics_proxy_.reset(new StatisticsProxy(_rtpRtcpModule->SSRC()));
1040 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(
1041 statistics_proxy_.get());
niklase@google.com470e71d2011-07-07 08:21:25 +00001042}
1043
1044Channel::~Channel()
1045{
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001046 rtp_receive_statistics_->RegisterRtcpStatisticsCallback(NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,_channelId),
1048 "Channel::~Channel() - dtor");
1049
1050 if (_outputExternalMedia)
1051 {
1052 DeRegisterExternalMediaProcessing(kPlaybackPerChannel);
1053 }
1054 if (_inputExternalMedia)
1055 {
1056 DeRegisterExternalMediaProcessing(kRecordingPerChannel);
1057 }
1058 StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 StopPlayout();
1060
1061 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001062 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 if (_inputFilePlayerPtr)
1064 {
1065 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1066 _inputFilePlayerPtr->StopPlayingFile();
1067 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
1068 _inputFilePlayerPtr = NULL;
1069 }
1070 if (_outputFilePlayerPtr)
1071 {
1072 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
1073 _outputFilePlayerPtr->StopPlayingFile();
1074 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
1075 _outputFilePlayerPtr = NULL;
1076 }
1077 if (_outputFileRecorderPtr)
1078 {
1079 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
1080 _outputFileRecorderPtr->StopRecording();
1081 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
1082 _outputFileRecorderPtr = NULL;
1083 }
1084 }
1085
1086 // The order to safely shutdown modules in a channel is:
1087 // 1. De-register callbacks in modules
1088 // 2. De-register modules in process thread
1089 // 3. Destroy modules
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001090 if (audio_coding_->RegisterTransportCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001091 {
1092 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1093 VoEId(_instanceId,_channelId),
1094 "~Channel() failed to de-register transport callback"
1095 " (Audio coding module)");
1096 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001097 if (audio_coding_->RegisterVADCallback(NULL) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001098 {
1099 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1100 VoEId(_instanceId,_channelId),
1101 "~Channel() failed to de-register VAD callback"
1102 " (Audio coding module)");
1103 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001104 // De-register modules in process thread
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001105 if (_moduleProcessThreadPtr->DeRegisterModule(_rtpRtcpModule.get()) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001106 {
1107 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1108 VoEId(_instanceId,_channelId),
1109 "~Channel() failed to deregister RTP/RTCP module");
1110 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001111 // End of modules shutdown
1112
1113 // Delete other objects
1114 RtpDump::DestroyRtpDump(&_rtpDumpIn);
1115 RtpDump::DestroyRtpDump(&_rtpDumpOut);
1116 delete [] _encryptionRTPBufferPtr;
1117 delete [] _decryptionRTPBufferPtr;
1118 delete [] _encryptionRTCPBufferPtr;
1119 delete [] _decryptionRTCPBufferPtr;
1120 delete &_callbackCritSect;
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 delete &_fileCritSect;
wu@webrtc.org63420662013-10-17 18:28:55 +00001122 delete &volume_settings_critsect_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001123}
1124
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001125int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001126Channel::Init()
1127{
1128 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1129 "Channel::Init()");
1130
1131 // --- Initial sanity
1132
1133 if ((_engineStatisticsPtr == NULL) ||
1134 (_moduleProcessThreadPtr == NULL))
1135 {
1136 WEBRTC_TRACE(kTraceError, kTraceVoice,
1137 VoEId(_instanceId,_channelId),
1138 "Channel::Init() must call SetEngineInformation() first");
1139 return -1;
1140 }
1141
1142 // --- Add modules to process thread (for periodic schedulation)
1143
1144 const bool processThreadFail =
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001145 ((_moduleProcessThreadPtr->RegisterModule(_rtpRtcpModule.get()) != 0) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001146 false);
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 if (processThreadFail)
1148 {
1149 _engineStatisticsPtr->SetLastError(
1150 VE_CANNOT_INIT_CHANNEL, kTraceError,
1151 "Channel::Init() modules not registered");
1152 return -1;
1153 }
pwestin@webrtc.orgc450a192012-01-04 15:00:12 +00001154 // --- ACM initialization
niklase@google.com470e71d2011-07-07 08:21:25 +00001155
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001156 if ((audio_coding_->InitializeReceiver() == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001157#ifdef WEBRTC_CODEC_AVT
1158 // out-of-band Dtmf tones are played out by default
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001159 (audio_coding_->SetDtmfPlayoutStatus(true) == -1) ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001160#endif
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001161 (audio_coding_->InitializeSender() == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 {
1163 _engineStatisticsPtr->SetLastError(
1164 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1165 "Channel::Init() unable to initialize the ACM - 1");
1166 return -1;
1167 }
1168
1169 // --- RTP/RTCP module initialization
1170
1171 // Ensure that RTCP is enabled by default for the created channel.
1172 // Note that, the module will keep generating RTCP until it is explicitly
1173 // disabled by the user.
1174 // After StopListen (when no sockets exists), RTCP packets will no longer
1175 // be transmitted since the Transport object will then be invalid.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001176 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
1177 // RTCP is enabled by default.
1178 if (_rtpRtcpModule->SetRTCPStatus(kRtcpCompound) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001179 {
1180 _engineStatisticsPtr->SetLastError(
1181 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1182 "Channel::Init() RTP/RTCP module not initialized");
1183 return -1;
1184 }
1185
1186 // --- Register all permanent callbacks
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 const bool fail =
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001188 (audio_coding_->RegisterTransportCallback(this) == -1) ||
1189 (audio_coding_->RegisterVADCallback(this) == -1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001190
1191 if (fail)
1192 {
1193 _engineStatisticsPtr->SetLastError(
1194 VE_CANNOT_INIT_CHANNEL, kTraceError,
1195 "Channel::Init() callbacks not registered");
1196 return -1;
1197 }
1198
1199 // --- Register all supported codecs to the receiving side of the
1200 // RTP/RTCP module
1201
1202 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001203 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00001204
1205 for (int idx = 0; idx < nSupportedCodecs; idx++)
1206 {
1207 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001208 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001209 (rtp_receiver_->RegisterReceivePayload(
1210 codec.plname,
1211 codec.pltype,
1212 codec.plfreq,
1213 codec.channels,
1214 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 {
1216 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1217 VoEId(_instanceId,_channelId),
1218 "Channel::Init() unable to register %s (%d/%d/%d/%d) "
1219 "to RTP/RTCP receiver",
1220 codec.plname, codec.pltype, codec.plfreq,
1221 codec.channels, codec.rate);
1222 }
1223 else
1224 {
1225 WEBRTC_TRACE(kTraceInfo, kTraceVoice,
1226 VoEId(_instanceId,_channelId),
1227 "Channel::Init() %s (%d/%d/%d/%d) has been added to "
1228 "the RTP/RTCP receiver",
1229 codec.plname, codec.pltype, codec.plfreq,
1230 codec.channels, codec.rate);
1231 }
1232
1233 // Ensure that PCMU is used as default codec on the sending side
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001234 if (!STR_CASE_CMP(codec.plname, "PCMU") && (codec.channels == 1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001235 {
1236 SetSendCodec(codec);
1237 }
1238
1239 // Register default PT for outband 'telephone-event'
1240 if (!STR_CASE_CMP(codec.plname, "telephone-event"))
1241 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001242 if ((_rtpRtcpModule->RegisterSendPayload(codec) == -1) ||
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001243 (audio_coding_->RegisterReceiveCodec(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001244 {
1245 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1246 VoEId(_instanceId,_channelId),
1247 "Channel::Init() failed to register outband "
1248 "'telephone-event' (%d/%d) correctly",
1249 codec.pltype, codec.plfreq);
1250 }
1251 }
1252
1253 if (!STR_CASE_CMP(codec.plname, "CN"))
1254 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001255 if ((audio_coding_->RegisterSendCodec(codec) == -1) ||
1256 (audio_coding_->RegisterReceiveCodec(codec) == -1) ||
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001257 (_rtpRtcpModule->RegisterSendPayload(codec) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00001258 {
1259 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1260 VoEId(_instanceId,_channelId),
1261 "Channel::Init() failed to register CN (%d/%d) "
1262 "correctly - 1",
1263 codec.pltype, codec.plfreq);
1264 }
1265 }
1266#ifdef WEBRTC_CODEC_RED
1267 // Register RED to the receiving side of the ACM.
1268 // We will not receive an OnInitializeDecoder() callback for RED.
1269 if (!STR_CASE_CMP(codec.plname, "RED"))
1270 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001271 if (audio_coding_->RegisterReceiveCodec(codec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 {
1273 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
1274 VoEId(_instanceId,_channelId),
1275 "Channel::Init() failed to register RED (%d/%d) "
1276 "correctly",
1277 codec.pltype, codec.plfreq);
1278 }
1279 }
1280#endif
1281 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001282
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001283 if (rx_audioproc_->noise_suppression()->set_level(kDefaultNsMode) != 0) {
1284 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode);
1285 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001286 }
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00001287 if (rx_audioproc_->gain_control()->set_mode(kDefaultRxAgcMode) != 0) {
1288 LOG_FERR1(LS_ERROR, gain_control()->set_mode, kDefaultRxAgcMode);
1289 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001290 }
1291
1292 return 0;
1293}
1294
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001295int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001296Channel::SetEngineInformation(Statistics& engineStatistics,
1297 OutputMixer& outputMixer,
1298 voe::TransmitMixer& transmitMixer,
1299 ProcessThread& moduleProcessThread,
1300 AudioDeviceModule& audioDeviceModule,
1301 VoiceEngineObserver* voiceEngineObserver,
1302 CriticalSectionWrapper* callbackCritSect)
1303{
1304 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1305 "Channel::SetEngineInformation()");
1306 _engineStatisticsPtr = &engineStatistics;
1307 _outputMixerPtr = &outputMixer;
1308 _transmitMixerPtr = &transmitMixer,
1309 _moduleProcessThreadPtr = &moduleProcessThread;
1310 _audioDeviceModulePtr = &audioDeviceModule;
1311 _voiceEngineObserverPtr = voiceEngineObserver;
1312 _callbackCritSectPtr = callbackCritSect;
1313 return 0;
1314}
1315
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001316int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001317Channel::UpdateLocalTimeStamp()
1318{
1319
andrew@webrtc.org63a50982012-05-02 23:56:37 +00001320 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00001321 return 0;
1322}
1323
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001324int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001325Channel::StartPlayout()
1326{
1327 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1328 "Channel::StartPlayout()");
1329 if (_playing)
1330 {
1331 return 0;
1332 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001333
1334 if (!_externalMixing) {
1335 // Add participant as candidates for mixing.
1336 if (_outputMixerPtr->SetMixabilityStatus(*this, true) != 0)
1337 {
1338 _engineStatisticsPtr->SetLastError(
1339 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1340 "StartPlayout() failed to add participant to mixer");
1341 return -1;
1342 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001343 }
1344
1345 _playing = true;
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00001346
1347 if (RegisterFilePlayingToMixer() != 0)
1348 return -1;
1349
niklase@google.com470e71d2011-07-07 08:21:25 +00001350 return 0;
1351}
1352
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001353int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001354Channel::StopPlayout()
1355{
1356 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1357 "Channel::StopPlayout()");
1358 if (!_playing)
1359 {
1360 return 0;
1361 }
roosa@google.com1b60ceb2012-12-12 23:00:29 +00001362
1363 if (!_externalMixing) {
1364 // Remove participant as candidates for mixing
1365 if (_outputMixerPtr->SetMixabilityStatus(*this, false) != 0)
1366 {
1367 _engineStatisticsPtr->SetLastError(
1368 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
1369 "StopPlayout() failed to remove participant from mixer");
1370 return -1;
1371 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001372 }
1373
1374 _playing = false;
1375 _outputAudioLevel.Clear();
1376
1377 return 0;
1378}
1379
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001380int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001381Channel::StartSend()
1382{
1383 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1384 "Channel::StartSend()");
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001385 // Resume the previous sequence number which was reset by StopSend().
1386 // This needs to be done before |_sending| is set to true.
1387 if (send_sequence_number_)
1388 SetInitSequenceNumber(send_sequence_number_);
1389
niklase@google.com470e71d2011-07-07 08:21:25 +00001390 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001391 // A lock is needed because |_sending| can be accessed or modified by
1392 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001393 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001394
1395 if (_sending)
1396 {
1397 return 0;
1398 }
1399 _sending = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001400 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001401
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001402 if (_rtpRtcpModule->SetSendingStatus(true) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001403 {
1404 _engineStatisticsPtr->SetLastError(
1405 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1406 "StartSend() RTP/RTCP failed to start sending");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001407 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001408 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001409 return -1;
1410 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001411
niklase@google.com470e71d2011-07-07 08:21:25 +00001412 return 0;
1413}
1414
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001415int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001416Channel::StopSend()
1417{
1418 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1419 "Channel::StopSend()");
niklase@google.com470e71d2011-07-07 08:21:25 +00001420 {
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001421 // A lock is needed because |_sending| can be accessed or modified by
1422 // another thread at the same time.
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001423 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001424
1425 if (!_sending)
1426 {
1427 return 0;
1428 }
1429 _sending = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00001430 }
xians@webrtc.orge07247a2011-11-28 16:31:28 +00001431
xians@webrtc.org09e8c472013-07-31 16:30:19 +00001432 // Store the sequence number to be able to pick up the same sequence for
1433 // the next StartSend(). This is needed for restarting device, otherwise
1434 // it might cause libSRTP to complain about packets being replayed.
1435 // TODO(xians): Remove this workaround after RtpRtcpModule's refactoring
1436 // CL is landed. See issue
1437 // https://code.google.com/p/webrtc/issues/detail?id=2111 .
1438 send_sequence_number_ = _rtpRtcpModule->SequenceNumber();
1439
niklase@google.com470e71d2011-07-07 08:21:25 +00001440 // Reset sending SSRC and sequence number and triggers direct transmission
1441 // of RTCP BYE
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001442 if (_rtpRtcpModule->SetSendingStatus(false) == -1 ||
1443 _rtpRtcpModule->ResetSendDataCountersRTP() == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001444 {
1445 _engineStatisticsPtr->SetLastError(
1446 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
1447 "StartSend() RTP/RTCP failed to stop sending");
1448 }
1449
niklase@google.com470e71d2011-07-07 08:21:25 +00001450 return 0;
1451}
1452
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001453int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001454Channel::StartReceiving()
1455{
1456 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1457 "Channel::StartReceiving()");
1458 if (_receiving)
1459 {
1460 return 0;
1461 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001462 _receiving = true;
1463 _numberOfDiscardedPackets = 0;
1464 return 0;
1465}
1466
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001467int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001468Channel::StopReceiving()
1469{
1470 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1471 "Channel::StopReceiving()");
1472 if (!_receiving)
1473 {
1474 return 0;
1475 }
pwestin@webrtc.org684f0572013-03-13 23:20:57 +00001476
henrika@webrtc.orgaf71f0e2011-12-05 07:02:22 +00001477 // Recover DTMF detection status.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001478 telephone_event_handler_->SetTelephoneEventForwardToDecoder(true);
niklase@google.com470e71d2011-07-07 08:21:25 +00001479 RegisterReceiveCodecsToRTPModule();
1480 _receiving = false;
1481 return 0;
1482}
1483
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001484int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001485Channel::SetNetEQPlayoutMode(NetEqModes mode)
1486{
1487 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1488 "Channel::SetNetEQPlayoutMode()");
1489 AudioPlayoutMode playoutMode(voice);
1490 switch (mode)
1491 {
1492 case kNetEqDefault:
1493 playoutMode = voice;
1494 break;
1495 case kNetEqStreaming:
1496 playoutMode = streaming;
1497 break;
1498 case kNetEqFax:
1499 playoutMode = fax;
1500 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001501 case kNetEqOff:
1502 playoutMode = off;
1503 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001504 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001505 if (audio_coding_->SetPlayoutMode(playoutMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 {
1507 _engineStatisticsPtr->SetLastError(
1508 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1509 "SetNetEQPlayoutMode() failed to set playout mode");
1510 return -1;
1511 }
1512 return 0;
1513}
1514
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001515int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001516Channel::GetNetEQPlayoutMode(NetEqModes& mode)
1517{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001518 const AudioPlayoutMode playoutMode = audio_coding_->PlayoutMode();
niklase@google.com470e71d2011-07-07 08:21:25 +00001519 switch (playoutMode)
1520 {
1521 case voice:
1522 mode = kNetEqDefault;
1523 break;
1524 case streaming:
1525 mode = kNetEqStreaming;
1526 break;
1527 case fax:
1528 mode = kNetEqFax;
1529 break;
roosa@google.comb7186192012-12-12 21:59:14 +00001530 case off:
1531 mode = kNetEqOff;
niklase@google.com470e71d2011-07-07 08:21:25 +00001532 }
1533 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
1534 VoEId(_instanceId,_channelId),
1535 "Channel::GetNetEQPlayoutMode() => mode=%u", mode);
1536 return 0;
1537}
1538
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001539int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001540Channel::SetOnHoldStatus(bool enable, OnHoldModes mode)
1541{
1542 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1543 "Channel::SetOnHoldStatus()");
1544 if (mode == kHoldSendAndPlay)
1545 {
1546 _outputIsOnHold = enable;
1547 _inputIsOnHold = enable;
1548 }
1549 else if (mode == kHoldPlayOnly)
1550 {
1551 _outputIsOnHold = enable;
1552 }
1553 if (mode == kHoldSendOnly)
1554 {
1555 _inputIsOnHold = enable;
1556 }
1557 return 0;
1558}
1559
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001560int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001561Channel::GetOnHoldStatus(bool& enabled, OnHoldModes& mode)
1562{
1563 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1564 "Channel::GetOnHoldStatus()");
1565 enabled = (_outputIsOnHold || _inputIsOnHold);
1566 if (_outputIsOnHold && _inputIsOnHold)
1567 {
1568 mode = kHoldSendAndPlay;
1569 }
1570 else if (_outputIsOnHold && !_inputIsOnHold)
1571 {
1572 mode = kHoldPlayOnly;
1573 }
1574 else if (!_outputIsOnHold && _inputIsOnHold)
1575 {
1576 mode = kHoldSendOnly;
1577 }
1578 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1579 "Channel::GetOnHoldStatus() => enabled=%d, mode=%d",
1580 enabled, mode);
1581 return 0;
1582}
1583
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001584int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001585Channel::RegisterVoiceEngineObserver(VoiceEngineObserver& observer)
1586{
1587 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1588 "Channel::RegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001589 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001590
1591 if (_voiceEngineObserverPtr)
1592 {
1593 _engineStatisticsPtr->SetLastError(
1594 VE_INVALID_OPERATION, kTraceError,
1595 "RegisterVoiceEngineObserver() observer already enabled");
1596 return -1;
1597 }
1598 _voiceEngineObserverPtr = &observer;
1599 return 0;
1600}
1601
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001602int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001603Channel::DeRegisterVoiceEngineObserver()
1604{
1605 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1606 "Channel::DeRegisterVoiceEngineObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00001607 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00001608
1609 if (!_voiceEngineObserverPtr)
1610 {
1611 _engineStatisticsPtr->SetLastError(
1612 VE_INVALID_OPERATION, kTraceWarning,
1613 "DeRegisterVoiceEngineObserver() observer already disabled");
1614 return 0;
1615 }
1616 _voiceEngineObserverPtr = NULL;
1617 return 0;
1618}
1619
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001620int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001621Channel::GetSendCodec(CodecInst& codec)
1622{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001623 return (audio_coding_->SendCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001624}
1625
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001626int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001627Channel::GetRecCodec(CodecInst& codec)
1628{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001629 return (audio_coding_->ReceiveCodec(&codec));
niklase@google.com470e71d2011-07-07 08:21:25 +00001630}
1631
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001632int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001633Channel::SetSendCodec(const CodecInst& codec)
1634{
1635 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1636 "Channel::SetSendCodec()");
1637
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001638 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001639 {
1640 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1641 "SetSendCodec() failed to register codec to ACM");
1642 return -1;
1643 }
1644
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001645 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001646 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001647 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1648 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001649 {
1650 WEBRTC_TRACE(
1651 kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1652 "SetSendCodec() failed to register codec to"
1653 " RTP/RTCP module");
1654 return -1;
1655 }
1656 }
1657
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001658 if (_rtpRtcpModule->SetAudioPacketSize(codec.pacsize) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001659 {
1660 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
1661 "SetSendCodec() failed to set audio packet size");
1662 return -1;
1663 }
1664
1665 return 0;
1666}
1667
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001668int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001669Channel::SetVADStatus(bool enableVAD, ACMVADMode mode, bool disableDTX)
1670{
1671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1672 "Channel::SetVADStatus(mode=%d)", mode);
1673 // To disable VAD, DTX must be disabled too
1674 disableDTX = ((enableVAD == false) ? true : disableDTX);
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001675 if (audio_coding_->SetVAD(!disableDTX, enableVAD, mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001676 {
1677 _engineStatisticsPtr->SetLastError(
1678 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1679 "SetVADStatus() failed to set VAD");
1680 return -1;
1681 }
1682 return 0;
1683}
1684
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001685int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001686Channel::GetVADStatus(bool& enabledVAD, ACMVADMode& mode, bool& disabledDTX)
1687{
1688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1689 "Channel::GetVADStatus");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001690 if (audio_coding_->VAD(&disabledDTX, &enabledVAD, &mode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001691 {
1692 _engineStatisticsPtr->SetLastError(
1693 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1694 "GetVADStatus() failed to get VAD status");
1695 return -1;
1696 }
1697 disabledDTX = !disabledDTX;
1698 return 0;
1699}
1700
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001701int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001702Channel::SetRecPayloadType(const CodecInst& codec)
1703{
1704 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1705 "Channel::SetRecPayloadType()");
1706
1707 if (_playing)
1708 {
1709 _engineStatisticsPtr->SetLastError(
1710 VE_ALREADY_PLAYING, kTraceError,
1711 "SetRecPayloadType() unable to set PT while playing");
1712 return -1;
1713 }
1714 if (_receiving)
1715 {
1716 _engineStatisticsPtr->SetLastError(
1717 VE_ALREADY_LISTENING, kTraceError,
1718 "SetRecPayloadType() unable to set PT while listening");
1719 return -1;
1720 }
1721
1722 if (codec.pltype == -1)
1723 {
1724 // De-register the selected codec (RTP/RTCP module and ACM)
1725
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001726 int8_t pltype(-1);
niklase@google.com470e71d2011-07-07 08:21:25 +00001727 CodecInst rxCodec = codec;
1728
1729 // Get payload type for the given codec
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001730 rtp_payload_registry_->ReceivePayloadType(
1731 rxCodec.plname,
1732 rxCodec.plfreq,
1733 rxCodec.channels,
1734 (rxCodec.rate < 0) ? 0 : rxCodec.rate,
1735 &pltype);
niklase@google.com470e71d2011-07-07 08:21:25 +00001736 rxCodec.pltype = pltype;
1737
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001738 if (rtp_receiver_->DeRegisterReceivePayload(pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001739 {
1740 _engineStatisticsPtr->SetLastError(
1741 VE_RTP_RTCP_MODULE_ERROR,
1742 kTraceError,
1743 "SetRecPayloadType() RTP/RTCP-module deregistration "
1744 "failed");
1745 return -1;
1746 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001747 if (audio_coding_->UnregisterReceiveCodec(rxCodec.pltype) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001748 {
1749 _engineStatisticsPtr->SetLastError(
1750 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1751 "SetRecPayloadType() ACM deregistration failed - 1");
1752 return -1;
1753 }
1754 return 0;
1755 }
1756
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001757 if (rtp_receiver_->RegisterReceivePayload(
1758 codec.plname,
1759 codec.pltype,
1760 codec.plfreq,
1761 codec.channels,
1762 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001763 {
1764 // First attempt to register failed => de-register and try again
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001765 rtp_receiver_->DeRegisterReceivePayload(codec.pltype);
1766 if (rtp_receiver_->RegisterReceivePayload(
1767 codec.plname,
1768 codec.pltype,
1769 codec.plfreq,
1770 codec.channels,
1771 (codec.rate < 0) ? 0 : codec.rate) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001772 {
1773 _engineStatisticsPtr->SetLastError(
1774 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1775 "SetRecPayloadType() RTP/RTCP-module registration failed");
1776 return -1;
1777 }
1778 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001779 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001780 {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001781 audio_coding_->UnregisterReceiveCodec(codec.pltype);
1782 if (audio_coding_->RegisterReceiveCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001783 {
1784 _engineStatisticsPtr->SetLastError(
1785 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1786 "SetRecPayloadType() ACM registration failed - 1");
1787 return -1;
1788 }
1789 }
1790 return 0;
1791}
1792
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001793int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001794Channel::GetRecPayloadType(CodecInst& codec)
1795{
1796 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1797 "Channel::GetRecPayloadType()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001798 int8_t payloadType(-1);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001799 if (rtp_payload_registry_->ReceivePayloadType(
1800 codec.plname,
1801 codec.plfreq,
1802 codec.channels,
1803 (codec.rate < 0) ? 0 : codec.rate,
1804 &payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001805 {
1806 _engineStatisticsPtr->SetLastError(
henrika@webrtc.org37198002012-06-18 11:00:12 +00001807 VE_RTP_RTCP_MODULE_ERROR, kTraceWarning,
niklase@google.com470e71d2011-07-07 08:21:25 +00001808 "GetRecPayloadType() failed to retrieve RX payload type");
1809 return -1;
1810 }
1811 codec.pltype = payloadType;
1812 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1813 "Channel::GetRecPayloadType() => pltype=%u", codec.pltype);
1814 return 0;
1815}
1816
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001817int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001818Channel::SetAMREncFormat(AmrMode mode)
1819{
1820 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1821 "Channel::SetAMREncFormat()");
1822
1823 // ACM doesn't support AMR
1824 return -1;
1825}
1826
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001827int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001828Channel::SetAMRDecFormat(AmrMode mode)
1829{
1830 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1831 "Channel::SetAMRDecFormat()");
1832
1833 // ACM doesn't support AMR
1834 return -1;
1835}
1836
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001837int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001838Channel::SetAMRWbEncFormat(AmrMode mode)
1839{
1840 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1841 "Channel::SetAMRWbEncFormat()");
1842
1843 // ACM doesn't support AMR
1844 return -1;
1845
1846}
1847
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001848int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001849Channel::SetAMRWbDecFormat(AmrMode mode)
1850{
1851 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1852 "Channel::SetAMRWbDecFormat()");
1853
1854 // ACM doesn't support AMR
1855 return -1;
1856}
1857
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001858int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001859Channel::SetSendCNPayloadType(int type, PayloadFrequencies frequency)
1860{
1861 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1862 "Channel::SetSendCNPayloadType()");
1863
1864 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001865 int32_t samplingFreqHz(-1);
tina.legrand@webrtc.org45175852012-06-01 09:27:35 +00001866 const int kMono = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001867 if (frequency == kFreq32000Hz)
1868 samplingFreqHz = 32000;
1869 else if (frequency == kFreq16000Hz)
1870 samplingFreqHz = 16000;
1871
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001872 if (audio_coding_->Codec("CN", &codec, samplingFreqHz, kMono) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001873 {
1874 _engineStatisticsPtr->SetLastError(
1875 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1876 "SetSendCNPayloadType() failed to retrieve default CN codec "
1877 "settings");
1878 return -1;
1879 }
1880
1881 // Modify the payload type (must be set to dynamic range)
1882 codec.pltype = type;
1883
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001884 if (audio_coding_->RegisterSendCodec(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001885 {
1886 _engineStatisticsPtr->SetLastError(
1887 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1888 "SetSendCNPayloadType() failed to register CN to ACM");
1889 return -1;
1890 }
1891
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001892 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001893 {
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00001894 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
1895 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001896 {
1897 _engineStatisticsPtr->SetLastError(
1898 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
1899 "SetSendCNPayloadType() failed to register CN to RTP/RTCP "
1900 "module");
1901 return -1;
1902 }
1903 }
1904 return 0;
1905}
1906
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001907int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001908Channel::SetISACInitTargetRate(int rateBps, bool useFixedFrameSize)
1909{
1910 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1911 "Channel::SetISACInitTargetRate()");
1912
1913 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001914 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001915 {
1916 _engineStatisticsPtr->SetLastError(
1917 VE_CODEC_ERROR, kTraceError,
1918 "SetISACInitTargetRate() failed to retrieve send codec");
1919 return -1;
1920 }
1921 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1922 {
1923 // This API is only valid if iSAC is setup to run in channel-adaptive
1924 // mode.
1925 // We do not validate the adaptive mode here. It is done later in the
1926 // ConfigISACBandwidthEstimator() API.
1927 _engineStatisticsPtr->SetLastError(
1928 VE_CODEC_ERROR, kTraceError,
1929 "SetISACInitTargetRate() send codec is not iSAC");
1930 return -1;
1931 }
1932
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001933 uint8_t initFrameSizeMsec(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00001934 if (16000 == sendCodec.plfreq)
1935 {
1936 // Note that 0 is a valid and corresponds to "use default
1937 if ((rateBps != 0 &&
1938 rateBps < kVoiceEngineMinIsacInitTargetRateBpsWb) ||
1939 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsWb))
1940 {
1941 _engineStatisticsPtr->SetLastError(
1942 VE_INVALID_ARGUMENT, kTraceError,
1943 "SetISACInitTargetRate() invalid target rate - 1");
1944 return -1;
1945 }
1946 // 30 or 60ms
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001947 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 16);
niklase@google.com470e71d2011-07-07 08:21:25 +00001948 }
1949 else if (32000 == sendCodec.plfreq)
1950 {
1951 if ((rateBps != 0 &&
1952 rateBps < kVoiceEngineMinIsacInitTargetRateBpsSwb) ||
1953 (rateBps > kVoiceEngineMaxIsacInitTargetRateBpsSwb))
1954 {
1955 _engineStatisticsPtr->SetLastError(
1956 VE_INVALID_ARGUMENT, kTraceError,
1957 "SetISACInitTargetRate() invalid target rate - 2");
1958 return -1;
1959 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001960 initFrameSizeMsec = (uint8_t)(sendCodec.pacsize / 32); // 30ms
niklase@google.com470e71d2011-07-07 08:21:25 +00001961 }
1962
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001963 if (audio_coding_->ConfigISACBandwidthEstimator(
niklase@google.com470e71d2011-07-07 08:21:25 +00001964 initFrameSizeMsec, rateBps, useFixedFrameSize) == -1)
1965 {
1966 _engineStatisticsPtr->SetLastError(
1967 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
1968 "SetISACInitTargetRate() iSAC BWE config failed");
1969 return -1;
1970 }
1971
1972 return 0;
1973}
1974
pbos@webrtc.org6141e132013-04-09 10:09:10 +00001975int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001976Channel::SetISACMaxRate(int rateBps)
1977{
1978 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
1979 "Channel::SetISACMaxRate()");
1980
1981 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00001982 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00001983 {
1984 _engineStatisticsPtr->SetLastError(
1985 VE_CODEC_ERROR, kTraceError,
1986 "SetISACMaxRate() failed to retrieve send codec");
1987 return -1;
1988 }
1989 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
1990 {
1991 // This API is only valid if iSAC is selected as sending codec.
1992 _engineStatisticsPtr->SetLastError(
1993 VE_CODEC_ERROR, kTraceError,
1994 "SetISACMaxRate() send codec is not iSAC");
1995 return -1;
1996 }
1997 if (16000 == sendCodec.plfreq)
1998 {
1999 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsWb) ||
2000 (rateBps > kVoiceEngineMaxIsacMaxRateBpsWb))
2001 {
2002 _engineStatisticsPtr->SetLastError(
2003 VE_INVALID_ARGUMENT, kTraceError,
2004 "SetISACMaxRate() invalid max rate - 1");
2005 return -1;
2006 }
2007 }
2008 else if (32000 == sendCodec.plfreq)
2009 {
2010 if ((rateBps < kVoiceEngineMinIsacMaxRateBpsSwb) ||
2011 (rateBps > kVoiceEngineMaxIsacMaxRateBpsSwb))
2012 {
2013 _engineStatisticsPtr->SetLastError(
2014 VE_INVALID_ARGUMENT, kTraceError,
2015 "SetISACMaxRate() invalid max rate - 2");
2016 return -1;
2017 }
2018 }
2019 if (_sending)
2020 {
2021 _engineStatisticsPtr->SetLastError(
2022 VE_SENDING, kTraceError,
2023 "SetISACMaxRate() unable to set max rate while sending");
2024 return -1;
2025 }
2026
2027 // Set the maximum instantaneous rate of iSAC (works for both adaptive
2028 // and non-adaptive mode)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002029 if (audio_coding_->SetISACMaxRate(rateBps) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002030 {
2031 _engineStatisticsPtr->SetLastError(
2032 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2033 "SetISACMaxRate() failed to set max rate");
2034 return -1;
2035 }
2036
2037 return 0;
2038}
2039
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002040int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002041Channel::SetISACMaxPayloadSize(int sizeBytes)
2042{
2043 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2044 "Channel::SetISACMaxPayloadSize()");
2045 CodecInst sendCodec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002046 if (audio_coding_->SendCodec(&sendCodec) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002047 {
2048 _engineStatisticsPtr->SetLastError(
2049 VE_CODEC_ERROR, kTraceError,
2050 "SetISACMaxPayloadSize() failed to retrieve send codec");
2051 return -1;
2052 }
2053 if (STR_CASE_CMP(sendCodec.plname, "ISAC") != 0)
2054 {
2055 _engineStatisticsPtr->SetLastError(
2056 VE_CODEC_ERROR, kTraceError,
2057 "SetISACMaxPayloadSize() send codec is not iSAC");
2058 return -1;
2059 }
2060 if (16000 == sendCodec.plfreq)
2061 {
2062 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesWb) ||
2063 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesWb))
2064 {
2065 _engineStatisticsPtr->SetLastError(
2066 VE_INVALID_ARGUMENT, kTraceError,
2067 "SetISACMaxPayloadSize() invalid max payload - 1");
2068 return -1;
2069 }
2070 }
2071 else if (32000 == sendCodec.plfreq)
2072 {
2073 if ((sizeBytes < kVoiceEngineMinIsacMaxPayloadSizeBytesSwb) ||
2074 (sizeBytes > kVoiceEngineMaxIsacMaxPayloadSizeBytesSwb))
2075 {
2076 _engineStatisticsPtr->SetLastError(
2077 VE_INVALID_ARGUMENT, kTraceError,
2078 "SetISACMaxPayloadSize() invalid max payload - 2");
2079 return -1;
2080 }
2081 }
2082 if (_sending)
2083 {
2084 _engineStatisticsPtr->SetLastError(
2085 VE_SENDING, kTraceError,
2086 "SetISACMaxPayloadSize() unable to set max rate while sending");
2087 return -1;
2088 }
2089
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00002090 if (audio_coding_->SetISACMaxPayloadSize(sizeBytes) == -1)
niklase@google.com470e71d2011-07-07 08:21:25 +00002091 {
2092 _engineStatisticsPtr->SetLastError(
2093 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
2094 "SetISACMaxPayloadSize() failed to set max payload size");
2095 return -1;
2096 }
2097 return 0;
2098}
2099
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002100int32_t Channel::RegisterExternalTransport(Transport& transport)
niklase@google.com470e71d2011-07-07 08:21:25 +00002101{
2102 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
2103 "Channel::RegisterExternalTransport()");
2104
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002105 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002106
niklase@google.com470e71d2011-07-07 08:21:25 +00002107 if (_externalTransport)
2108 {
2109 _engineStatisticsPtr->SetLastError(VE_INVALID_OPERATION,
2110 kTraceError,
2111 "RegisterExternalTransport() external transport already enabled");
2112 return -1;
2113 }
2114 _externalTransport = true;
2115 _transportPtr = &transport;
2116 return 0;
2117}
2118
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002119int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00002120Channel::DeRegisterExternalTransport()
2121{
2122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2123 "Channel::DeRegisterExternalTransport()");
2124
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002125 CriticalSectionScoped cs(&_callbackCritSect);
xians@webrtc.org83661f52011-11-25 10:58:15 +00002126
niklase@google.com470e71d2011-07-07 08:21:25 +00002127 if (!_transportPtr)
2128 {
2129 _engineStatisticsPtr->SetLastError(
2130 VE_INVALID_OPERATION, kTraceWarning,
2131 "DeRegisterExternalTransport() external transport already "
2132 "disabled");
2133 return 0;
2134 }
2135 _externalTransport = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002136 _transportPtr = NULL;
2137 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2138 "DeRegisterExternalTransport() all transport is disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +00002139 return 0;
2140}
2141
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002142int32_t Channel::ReceivedRTPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002143 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2144 "Channel::ReceivedRTPPacket()");
2145
2146 // Store playout timestamp for the received RTP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002147 UpdatePlayoutTimestamp(false);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002148
2149 // Dump the RTP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002150 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2151 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002152 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2153 VoEId(_instanceId,_channelId),
2154 "Channel::SendPacket() RTP dump to input file failed");
2155 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002156 const uint8_t* received_packet = reinterpret_cast<const uint8_t*>(data);
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002157 RTPHeader header;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002158 if (!rtp_header_parser_->Parse(received_packet, length, &header)) {
2159 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2160 "Incoming packet: invalid RTP header");
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002161 return -1;
2162 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002163 header.payload_type_frequency =
2164 rtp_payload_registry_->GetPayloadTypeFrequency(header.payloadType);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002165 if (header.payload_type_frequency < 0)
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002166 return -1;
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002167 bool in_order = IsPacketInOrder(header);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002168 rtp_receive_statistics_->IncomingPacket(header, length,
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002169 IsPacketRetransmitted(header, in_order));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002170 rtp_payload_registry_->SetIncomingPayloadType(header);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002171 return ReceivePacket(received_packet, length, header, in_order) ? 0 : -1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002172}
2173
2174bool Channel::ReceivePacket(const uint8_t* packet,
2175 int packet_length,
2176 const RTPHeader& header,
2177 bool in_order) {
2178 if (rtp_payload_registry_->IsEncapsulated(header)) {
2179 return HandleEncapsulation(packet, packet_length, header);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002180 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002181 const uint8_t* payload = packet + header.headerLength;
2182 int payload_length = packet_length - header.headerLength;
2183 assert(payload_length >= 0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002184 PayloadUnion payload_specific;
2185 if (!rtp_payload_registry_->GetPayloadSpecifics(header.payloadType,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002186 &payload_specific)) {
2187 return false;
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002188 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002189 return rtp_receiver_->IncomingRtpPacket(header, payload, payload_length,
2190 payload_specific, in_order);
2191}
2192
2193bool Channel::HandleEncapsulation(const uint8_t* packet,
2194 int packet_length,
2195 const RTPHeader& header) {
2196 if (!rtp_payload_registry_->IsRtx(header))
2197 return false;
2198
2199 // Remove the RTX header and parse the original RTP header.
2200 if (packet_length < header.headerLength)
2201 return false;
2202 if (packet_length > kVoiceEngineMaxIpPacketSizeBytes)
2203 return false;
2204 if (restored_packet_in_use_) {
2205 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2206 "Multiple RTX headers detected, dropping packet");
2207 return false;
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002208 }
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002209 uint8_t* restored_packet_ptr = restored_packet_;
2210 if (!rtp_payload_registry_->RestoreOriginalPacket(
2211 &restored_packet_ptr, packet, &packet_length, rtp_receiver_->SSRC(),
2212 header)) {
2213 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVoice, _channelId,
2214 "Incoming RTX packet: invalid RTP header");
2215 return false;
2216 }
2217 restored_packet_in_use_ = true;
2218 bool ret = OnRecoveredPacket(restored_packet_ptr, packet_length);
2219 restored_packet_in_use_ = false;
2220 return ret;
2221}
2222
2223bool Channel::IsPacketInOrder(const RTPHeader& header) const {
2224 StreamStatistician* statistician =
2225 rtp_receive_statistics_->GetStatistician(header.ssrc);
2226 if (!statistician)
2227 return false;
2228 return statistician->IsPacketInOrder(header.sequenceNumber);
niklase@google.com470e71d2011-07-07 08:21:25 +00002229}
2230
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002231bool Channel::IsPacketRetransmitted(const RTPHeader& header,
2232 bool in_order) const {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002233 // Retransmissions are handled separately if RTX is enabled.
2234 if (rtp_payload_registry_->RtxEnabled())
2235 return false;
2236 StreamStatistician* statistician =
2237 rtp_receive_statistics_->GetStatistician(header.ssrc);
2238 if (!statistician)
2239 return false;
2240 // Check if this is a retransmission.
2241 uint16_t min_rtt = 0;
2242 _rtpRtcpModule->RTT(rtp_receiver_->SSRC(), NULL, NULL, &min_rtt, NULL);
stefan@webrtc.org48df3812013-11-08 15:18:52 +00002243 return !in_order &&
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00002244 statistician->IsRetransmitOfOldPacket(header, min_rtt);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00002245}
2246
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002247int32_t Channel::ReceivedRTCPPacket(const int8_t* data, int32_t length) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002248 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
2249 "Channel::ReceivedRTCPPacket()");
2250 // Store playout timestamp for the received RTCP packet
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00002251 UpdatePlayoutTimestamp(true);
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002252
2253 // Dump the RTCP packet to a file (if RTP dump is enabled).
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002254 if (_rtpDumpIn.DumpPacket((const uint8_t*)data,
2255 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002256 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
2257 VoEId(_instanceId,_channelId),
2258 "Channel::SendPacket() RTCP dump to input file failed");
2259 }
2260
2261 // Deliver RTCP packet to RTP/RTCP module for parsing
stefan@webrtc.orga5cb98c2013-05-29 12:12:51 +00002262 if (_rtpRtcpModule->IncomingRtcpPacket((const uint8_t*)data,
2263 (uint16_t)length) == -1) {
pwestin@webrtc.org0c459572013-04-03 15:43:57 +00002264 _engineStatisticsPtr->SetLastError(
2265 VE_SOCKET_TRANSPORT_MODULE_ERROR, kTraceWarning,
2266 "Channel::IncomingRTPPacket() RTCP packet is invalid");
2267 }
2268 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00002269}
2270
niklase@google.com470e71d2011-07-07 08:21:25 +00002271int Channel::StartPlayingFileLocally(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002272 bool loop,
2273 FileFormats format,
2274 int startPosition,
2275 float volumeScaling,
2276 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002277 const CodecInst* codecInst)
2278{
2279 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2280 "Channel::StartPlayingFileLocally(fileNameUTF8[]=%s, loop=%d,"
2281 " format=%d, volumeScaling=%5.3f, startPosition=%d, "
2282 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2283 startPosition, stopPosition);
2284
2285 if (_outputFilePlaying)
2286 {
2287 _engineStatisticsPtr->SetLastError(
2288 VE_ALREADY_PLAYING, kTraceError,
2289 "StartPlayingFileLocally() is already playing");
2290 return -1;
2291 }
2292
niklase@google.com470e71d2011-07-07 08:21:25 +00002293 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002294 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002295
2296 if (_outputFilePlayerPtr)
2297 {
2298 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2299 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2300 _outputFilePlayerPtr = NULL;
2301 }
2302
2303 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2304 _outputFilePlayerId, (const FileFormats)format);
2305
2306 if (_outputFilePlayerPtr == NULL)
2307 {
2308 _engineStatisticsPtr->SetLastError(
2309 VE_INVALID_ARGUMENT, kTraceError,
henrike@webrtc.org31d30702011-11-18 19:59:32 +00002310 "StartPlayingFileLocally() filePlayer format is not correct");
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002311 return -1;
2312 }
2313
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002314 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002315
2316 if (_outputFilePlayerPtr->StartPlayingFile(
2317 fileName,
2318 loop,
2319 startPosition,
2320 volumeScaling,
2321 notificationTime,
2322 stopPosition,
2323 (const CodecInst*)codecInst) != 0)
2324 {
2325 _engineStatisticsPtr->SetLastError(
2326 VE_BAD_FILE, kTraceError,
2327 "StartPlayingFile() failed to start file playout");
2328 _outputFilePlayerPtr->StopPlayingFile();
2329 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2330 _outputFilePlayerPtr = NULL;
2331 return -1;
2332 }
2333 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2334 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002335 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002336
2337 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002338 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002339
2340 return 0;
2341}
2342
2343int Channel::StartPlayingFileLocally(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002344 FileFormats format,
2345 int startPosition,
2346 float volumeScaling,
2347 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002348 const CodecInst* codecInst)
2349{
2350 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2351 "Channel::StartPlayingFileLocally(format=%d,"
2352 " volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2353 format, volumeScaling, startPosition, stopPosition);
2354
2355 if(stream == NULL)
2356 {
2357 _engineStatisticsPtr->SetLastError(
2358 VE_BAD_FILE, kTraceError,
2359 "StartPlayingFileLocally() NULL as input stream");
2360 return -1;
2361 }
2362
2363
2364 if (_outputFilePlaying)
2365 {
2366 _engineStatisticsPtr->SetLastError(
2367 VE_ALREADY_PLAYING, kTraceError,
2368 "StartPlayingFileLocally() is already playing");
2369 return -1;
2370 }
2371
niklase@google.com470e71d2011-07-07 08:21:25 +00002372 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002373 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002374
2375 // Destroy the old instance
2376 if (_outputFilePlayerPtr)
2377 {
2378 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2379 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2380 _outputFilePlayerPtr = NULL;
2381 }
2382
2383 // Create the instance
2384 _outputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2385 _outputFilePlayerId,
2386 (const FileFormats)format);
2387
2388 if (_outputFilePlayerPtr == NULL)
2389 {
2390 _engineStatisticsPtr->SetLastError(
2391 VE_INVALID_ARGUMENT, kTraceError,
2392 "StartPlayingFileLocally() filePlayer format isnot correct");
2393 return -1;
2394 }
2395
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002396 const uint32_t notificationTime(0);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002397
2398 if (_outputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2399 volumeScaling,
2400 notificationTime,
2401 stopPosition, codecInst) != 0)
2402 {
2403 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2404 "StartPlayingFile() failed to "
2405 "start file playout");
2406 _outputFilePlayerPtr->StopPlayingFile();
2407 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2408 _outputFilePlayerPtr = NULL;
2409 return -1;
2410 }
2411 _outputFilePlayerPtr->RegisterModuleFileCallback(this);
2412 _outputFilePlaying = true;
niklase@google.com470e71d2011-07-07 08:21:25 +00002413 }
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002414
2415 if (RegisterFilePlayingToMixer() != 0)
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002416 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00002417
niklase@google.com470e71d2011-07-07 08:21:25 +00002418 return 0;
2419}
2420
2421int Channel::StopPlayingFileLocally()
2422{
2423 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2424 "Channel::StopPlayingFileLocally()");
2425
2426 if (!_outputFilePlaying)
2427 {
2428 _engineStatisticsPtr->SetLastError(
2429 VE_INVALID_OPERATION, kTraceWarning,
2430 "StopPlayingFileLocally() isnot playing");
2431 return 0;
2432 }
2433
niklase@google.com470e71d2011-07-07 08:21:25 +00002434 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002435 CriticalSectionScoped cs(&_fileCritSect);
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002436
2437 if (_outputFilePlayerPtr->StopPlayingFile() != 0)
2438 {
2439 _engineStatisticsPtr->SetLastError(
2440 VE_STOP_RECORDING_FAILED, kTraceError,
2441 "StopPlayingFile() could not stop playing");
2442 return -1;
2443 }
2444 _outputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2445 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2446 _outputFilePlayerPtr = NULL;
2447 _outputFilePlaying = false;
niklase@google.com470e71d2011-07-07 08:21:25 +00002448 }
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002449 // _fileCritSect cannot be taken while calling
2450 // SetAnonymousMixibilityStatus. Refer to comments in
2451 // StartPlayingFileLocally(const char* ...) for more details.
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002452 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, false) != 0)
2453 {
2454 _engineStatisticsPtr->SetLastError(
2455 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
henrike@webrtc.orgb37c6282011-10-31 23:53:04 +00002456 "StopPlayingFile() failed to stop participant from playing as"
2457 "file in the mixer");
henrike@webrtc.org066f9e52011-10-28 23:15:47 +00002458 return -1;
2459 }
niklase@google.com470e71d2011-07-07 08:21:25 +00002460
2461 return 0;
2462}
2463
2464int Channel::IsPlayingFileLocally() const
2465{
2466 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2467 "Channel::IsPlayingFileLocally()");
2468
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002469 return (int32_t)_outputFilePlaying;
niklase@google.com470e71d2011-07-07 08:21:25 +00002470}
2471
braveyao@webrtc.orgab129902012-06-04 03:26:39 +00002472int Channel::RegisterFilePlayingToMixer()
2473{
2474 // Return success for not registering for file playing to mixer if:
2475 // 1. playing file before playout is started on that channel.
2476 // 2. starting playout without file playing on that channel.
2477 if (!_playing || !_outputFilePlaying)
2478 {
2479 return 0;
2480 }
2481
2482 // |_fileCritSect| cannot be taken while calling
2483 // SetAnonymousMixabilityStatus() since as soon as the participant is added
2484 // frames can be pulled by the mixer. Since the frames are generated from
2485 // the file, _fileCritSect will be taken. This would result in a deadlock.
2486 if (_outputMixerPtr->SetAnonymousMixabilityStatus(*this, true) != 0)
2487 {
2488 CriticalSectionScoped cs(&_fileCritSect);
2489 _outputFilePlaying = false;
2490 _engineStatisticsPtr->SetLastError(
2491 VE_AUDIO_CONF_MIX_MODULE_ERROR, kTraceError,
2492 "StartPlayingFile() failed to add participant as file to mixer");
2493 _outputFilePlayerPtr->StopPlayingFile();
2494 FilePlayer::DestroyFilePlayer(_outputFilePlayerPtr);
2495 _outputFilePlayerPtr = NULL;
2496 return -1;
2497 }
2498
2499 return 0;
2500}
2501
pbos@webrtc.org92135212013-05-14 08:31:39 +00002502int Channel::ScaleLocalFilePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002503{
2504 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2505 "Channel::ScaleLocalFilePlayout(scale=%5.3f)", scale);
2506
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002507 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002508
2509 if (!_outputFilePlaying)
2510 {
2511 _engineStatisticsPtr->SetLastError(
2512 VE_INVALID_OPERATION, kTraceError,
2513 "ScaleLocalFilePlayout() isnot playing");
2514 return -1;
2515 }
2516 if ((_outputFilePlayerPtr == NULL) ||
2517 (_outputFilePlayerPtr->SetAudioScaling(scale) != 0))
2518 {
2519 _engineStatisticsPtr->SetLastError(
2520 VE_BAD_ARGUMENT, kTraceError,
2521 "SetAudioScaling() failed to scale the playout");
2522 return -1;
2523 }
2524
2525 return 0;
2526}
2527
2528int Channel::GetLocalPlayoutPosition(int& positionMs)
2529{
2530 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2531 "Channel::GetLocalPlayoutPosition(position=?)");
2532
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002533 uint32_t position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002534
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002535 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002536
2537 if (_outputFilePlayerPtr == NULL)
2538 {
2539 _engineStatisticsPtr->SetLastError(
2540 VE_INVALID_OPERATION, kTraceError,
2541 "GetLocalPlayoutPosition() filePlayer instance doesnot exist");
2542 return -1;
2543 }
2544
2545 if (_outputFilePlayerPtr->GetPlayoutPosition(position) != 0)
2546 {
2547 _engineStatisticsPtr->SetLastError(
2548 VE_BAD_FILE, kTraceError,
2549 "GetLocalPlayoutPosition() failed");
2550 return -1;
2551 }
2552 positionMs = position;
2553
2554 return 0;
2555}
2556
2557int Channel::StartPlayingFileAsMicrophone(const char* fileName,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002558 bool loop,
2559 FileFormats format,
2560 int startPosition,
2561 float volumeScaling,
2562 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002563 const CodecInst* codecInst)
2564{
2565 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2566 "Channel::StartPlayingFileAsMicrophone(fileNameUTF8[]=%s, "
2567 "loop=%d, format=%d, volumeScaling=%5.3f, startPosition=%d, "
2568 "stopPosition=%d)", fileName, loop, format, volumeScaling,
2569 startPosition, stopPosition);
2570
2571 if (_inputFilePlaying)
2572 {
2573 _engineStatisticsPtr->SetLastError(
2574 VE_ALREADY_PLAYING, kTraceWarning,
2575 "StartPlayingFileAsMicrophone() filePlayer is playing");
2576 return 0;
2577 }
2578
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002579 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002580
2581 // Destroy the old instance
2582 if (_inputFilePlayerPtr)
2583 {
2584 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2585 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2586 _inputFilePlayerPtr = NULL;
2587 }
2588
2589 // Create the instance
2590 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2591 _inputFilePlayerId, (const FileFormats)format);
2592
2593 if (_inputFilePlayerPtr == NULL)
2594 {
2595 _engineStatisticsPtr->SetLastError(
2596 VE_INVALID_ARGUMENT, kTraceError,
2597 "StartPlayingFileAsMicrophone() filePlayer format isnot correct");
2598 return -1;
2599 }
2600
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002601 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002602
2603 if (_inputFilePlayerPtr->StartPlayingFile(
2604 fileName,
2605 loop,
2606 startPosition,
2607 volumeScaling,
2608 notificationTime,
2609 stopPosition,
2610 (const CodecInst*)codecInst) != 0)
2611 {
2612 _engineStatisticsPtr->SetLastError(
2613 VE_BAD_FILE, kTraceError,
2614 "StartPlayingFile() failed to start file playout");
2615 _inputFilePlayerPtr->StopPlayingFile();
2616 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2617 _inputFilePlayerPtr = NULL;
2618 return -1;
2619 }
2620 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2621 _inputFilePlaying = true;
2622
2623 return 0;
2624}
2625
2626int Channel::StartPlayingFileAsMicrophone(InStream* stream,
pbos@webrtc.org92135212013-05-14 08:31:39 +00002627 FileFormats format,
2628 int startPosition,
2629 float volumeScaling,
2630 int stopPosition,
niklase@google.com470e71d2011-07-07 08:21:25 +00002631 const CodecInst* codecInst)
2632{
2633 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2634 "Channel::StartPlayingFileAsMicrophone(format=%d, "
2635 "volumeScaling=%5.3f, startPosition=%d, stopPosition=%d)",
2636 format, volumeScaling, startPosition, stopPosition);
2637
2638 if(stream == NULL)
2639 {
2640 _engineStatisticsPtr->SetLastError(
2641 VE_BAD_FILE, kTraceError,
2642 "StartPlayingFileAsMicrophone NULL as input stream");
2643 return -1;
2644 }
2645
2646 if (_inputFilePlaying)
2647 {
2648 _engineStatisticsPtr->SetLastError(
2649 VE_ALREADY_PLAYING, kTraceWarning,
2650 "StartPlayingFileAsMicrophone() is playing");
2651 return 0;
2652 }
2653
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002654 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002655
2656 // Destroy the old instance
2657 if (_inputFilePlayerPtr)
2658 {
2659 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2660 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2661 _inputFilePlayerPtr = NULL;
2662 }
2663
2664 // Create the instance
2665 _inputFilePlayerPtr = FilePlayer::CreateFilePlayer(
2666 _inputFilePlayerId, (const FileFormats)format);
2667
2668 if (_inputFilePlayerPtr == NULL)
2669 {
2670 _engineStatisticsPtr->SetLastError(
2671 VE_INVALID_ARGUMENT, kTraceError,
2672 "StartPlayingInputFile() filePlayer format isnot correct");
2673 return -1;
2674 }
2675
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002676 const uint32_t notificationTime(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00002677
2678 if (_inputFilePlayerPtr->StartPlayingFile(*stream, startPosition,
2679 volumeScaling, notificationTime,
2680 stopPosition, codecInst) != 0)
2681 {
2682 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2683 "StartPlayingFile() failed to start "
2684 "file playout");
2685 _inputFilePlayerPtr->StopPlayingFile();
2686 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2687 _inputFilePlayerPtr = NULL;
2688 return -1;
2689 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002690
niklase@google.com470e71d2011-07-07 08:21:25 +00002691 _inputFilePlayerPtr->RegisterModuleFileCallback(this);
2692 _inputFilePlaying = true;
2693
2694 return 0;
2695}
2696
2697int Channel::StopPlayingFileAsMicrophone()
2698{
2699 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2700 "Channel::StopPlayingFileAsMicrophone()");
2701
2702 if (!_inputFilePlaying)
2703 {
2704 _engineStatisticsPtr->SetLastError(
2705 VE_INVALID_OPERATION, kTraceWarning,
2706 "StopPlayingFileAsMicrophone() isnot playing");
2707 return 0;
2708 }
2709
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002710 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002711 if (_inputFilePlayerPtr->StopPlayingFile() != 0)
2712 {
2713 _engineStatisticsPtr->SetLastError(
2714 VE_STOP_RECORDING_FAILED, kTraceError,
2715 "StopPlayingFile() could not stop playing");
2716 return -1;
2717 }
2718 _inputFilePlayerPtr->RegisterModuleFileCallback(NULL);
2719 FilePlayer::DestroyFilePlayer(_inputFilePlayerPtr);
2720 _inputFilePlayerPtr = NULL;
2721 _inputFilePlaying = false;
2722
2723 return 0;
2724}
2725
2726int Channel::IsPlayingFileAsMicrophone() const
2727{
2728 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2729 "Channel::IsPlayingFileAsMicrophone()");
2730
2731 return _inputFilePlaying;
2732}
2733
pbos@webrtc.org92135212013-05-14 08:31:39 +00002734int Channel::ScaleFileAsMicrophonePlayout(float scale)
niklase@google.com470e71d2011-07-07 08:21:25 +00002735{
2736 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2737 "Channel::ScaleFileAsMicrophonePlayout(scale=%5.3f)", scale);
2738
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002739 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002740
2741 if (!_inputFilePlaying)
2742 {
2743 _engineStatisticsPtr->SetLastError(
2744 VE_INVALID_OPERATION, kTraceError,
2745 "ScaleFileAsMicrophonePlayout() isnot playing");
2746 return -1;
2747 }
2748
2749 if ((_inputFilePlayerPtr == NULL) ||
2750 (_inputFilePlayerPtr->SetAudioScaling(scale) != 0))
2751 {
2752 _engineStatisticsPtr->SetLastError(
2753 VE_BAD_ARGUMENT, kTraceError,
2754 "SetAudioScaling() failed to scale playout");
2755 return -1;
2756 }
2757
2758 return 0;
2759}
2760
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00002761int Channel::StartRecordingPlayout(const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +00002762 const CodecInst* codecInst)
2763{
2764 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2765 "Channel::StartRecordingPlayout(fileName=%s)", fileName);
2766
2767 if (_outputFileRecording)
2768 {
2769 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2770 "StartRecordingPlayout() is already recording");
2771 return 0;
2772 }
2773
2774 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002775 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002776 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2777
niklas.enbom@webrtc.org40197d72012-03-26 08:45:47 +00002778 if ((codecInst != NULL) &&
2779 ((codecInst->channels < 1) || (codecInst->channels > 2)))
niklase@google.com470e71d2011-07-07 08:21:25 +00002780 {
2781 _engineStatisticsPtr->SetLastError(
2782 VE_BAD_ARGUMENT, kTraceError,
2783 "StartRecordingPlayout() invalid compression");
2784 return(-1);
2785 }
2786 if(codecInst == NULL)
2787 {
2788 format = kFileFormatPcm16kHzFile;
2789 codecInst=&dummyCodec;
2790 }
2791 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2792 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2793 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2794 {
2795 format = kFileFormatWavFile;
2796 }
2797 else
2798 {
2799 format = kFileFormatCompressedFile;
2800 }
2801
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002802 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002803
2804 // Destroy the old instance
2805 if (_outputFileRecorderPtr)
2806 {
2807 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2808 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2809 _outputFileRecorderPtr = NULL;
2810 }
2811
2812 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2813 _outputFileRecorderId, (const FileFormats)format);
2814 if (_outputFileRecorderPtr == NULL)
2815 {
2816 _engineStatisticsPtr->SetLastError(
2817 VE_INVALID_ARGUMENT, kTraceError,
2818 "StartRecordingPlayout() fileRecorder format isnot correct");
2819 return -1;
2820 }
2821
2822 if (_outputFileRecorderPtr->StartRecordingAudioFile(
2823 fileName, (const CodecInst&)*codecInst, notificationTime) != 0)
2824 {
2825 _engineStatisticsPtr->SetLastError(
2826 VE_BAD_FILE, kTraceError,
2827 "StartRecordingAudioFile() failed to start file recording");
2828 _outputFileRecorderPtr->StopRecording();
2829 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2830 _outputFileRecorderPtr = NULL;
2831 return -1;
2832 }
2833 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2834 _outputFileRecording = true;
2835
2836 return 0;
2837}
2838
2839int Channel::StartRecordingPlayout(OutStream* stream,
2840 const CodecInst* codecInst)
2841{
2842 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2843 "Channel::StartRecordingPlayout()");
2844
2845 if (_outputFileRecording)
2846 {
2847 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
2848 "StartRecordingPlayout() is already recording");
2849 return 0;
2850 }
2851
2852 FileFormats format;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002853 const uint32_t notificationTime(0); // Not supported in VoE
niklase@google.com470e71d2011-07-07 08:21:25 +00002854 CodecInst dummyCodec={100,"L16",16000,320,1,320000};
2855
2856 if (codecInst != NULL && codecInst->channels != 1)
2857 {
2858 _engineStatisticsPtr->SetLastError(
2859 VE_BAD_ARGUMENT, kTraceError,
2860 "StartRecordingPlayout() invalid compression");
2861 return(-1);
2862 }
2863 if(codecInst == NULL)
2864 {
2865 format = kFileFormatPcm16kHzFile;
2866 codecInst=&dummyCodec;
2867 }
2868 else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
2869 (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
2870 (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
2871 {
2872 format = kFileFormatWavFile;
2873 }
2874 else
2875 {
2876 format = kFileFormatCompressedFile;
2877 }
2878
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002879 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002880
2881 // Destroy the old instance
2882 if (_outputFileRecorderPtr)
2883 {
2884 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2885 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2886 _outputFileRecorderPtr = NULL;
2887 }
2888
2889 _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
2890 _outputFileRecorderId, (const FileFormats)format);
2891 if (_outputFileRecorderPtr == NULL)
2892 {
2893 _engineStatisticsPtr->SetLastError(
2894 VE_INVALID_ARGUMENT, kTraceError,
2895 "StartRecordingPlayout() fileRecorder format isnot correct");
2896 return -1;
2897 }
2898
2899 if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream, *codecInst,
2900 notificationTime) != 0)
2901 {
2902 _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
2903 "StartRecordingPlayout() failed to "
2904 "start file recording");
2905 _outputFileRecorderPtr->StopRecording();
2906 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2907 _outputFileRecorderPtr = NULL;
2908 return -1;
2909 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00002910
niklase@google.com470e71d2011-07-07 08:21:25 +00002911 _outputFileRecorderPtr->RegisterModuleFileCallback(this);
2912 _outputFileRecording = true;
2913
2914 return 0;
2915}
2916
2917int Channel::StopRecordingPlayout()
2918{
2919 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
2920 "Channel::StopRecordingPlayout()");
2921
2922 if (!_outputFileRecording)
2923 {
2924 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
2925 "StopRecordingPlayout() isnot recording");
2926 return -1;
2927 }
2928
2929
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00002930 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00002931
2932 if (_outputFileRecorderPtr->StopRecording() != 0)
2933 {
2934 _engineStatisticsPtr->SetLastError(
2935 VE_STOP_RECORDING_FAILED, kTraceError,
2936 "StopRecording() could not stop recording");
2937 return(-1);
2938 }
2939 _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
2940 FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
2941 _outputFileRecorderPtr = NULL;
2942 _outputFileRecording = false;
2943
2944 return 0;
2945}
2946
2947void
2948Channel::SetMixWithMicStatus(bool mix)
2949{
2950 _mixFileWithMicrophone=mix;
2951}
2952
2953int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002954Channel::GetSpeechOutputLevel(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002955{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002956 int8_t currentLevel = _outputAudioLevel.Level();
2957 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002958 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2959 VoEId(_instanceId,_channelId),
2960 "GetSpeechOutputLevel() => level=%u", level);
2961 return 0;
2962}
2963
2964int
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002965Channel::GetSpeechOutputLevelFullRange(uint32_t& level) const
niklase@google.com470e71d2011-07-07 08:21:25 +00002966{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00002967 int16_t currentLevel = _outputAudioLevel.LevelFullRange();
2968 level = static_cast<int32_t> (currentLevel);
niklase@google.com470e71d2011-07-07 08:21:25 +00002969 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
2970 VoEId(_instanceId,_channelId),
2971 "GetSpeechOutputLevelFullRange() => level=%u", level);
2972 return 0;
2973}
2974
2975int
2976Channel::SetMute(bool enable)
2977{
wu@webrtc.org63420662013-10-17 18:28:55 +00002978 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002979 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2980 "Channel::SetMute(enable=%d)", enable);
2981 _mute = enable;
2982 return 0;
2983}
2984
2985bool
2986Channel::Mute() const
2987{
wu@webrtc.org63420662013-10-17 18:28:55 +00002988 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002989 return _mute;
2990}
2991
2992int
2993Channel::SetOutputVolumePan(float left, float right)
2994{
wu@webrtc.org63420662013-10-17 18:28:55 +00002995 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00002996 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
2997 "Channel::SetOutputVolumePan()");
2998 _panLeft = left;
2999 _panRight = right;
3000 return 0;
3001}
3002
3003int
3004Channel::GetOutputVolumePan(float& left, float& right) const
3005{
wu@webrtc.org63420662013-10-17 18:28:55 +00003006 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003007 left = _panLeft;
3008 right = _panRight;
3009 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3010 VoEId(_instanceId,_channelId),
3011 "GetOutputVolumePan() => left=%3.2f, right=%3.2f", left, right);
3012 return 0;
3013}
3014
3015int
3016Channel::SetChannelOutputVolumeScaling(float scaling)
3017{
wu@webrtc.org63420662013-10-17 18:28:55 +00003018 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003019 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3020 "Channel::SetChannelOutputVolumeScaling()");
3021 _outputGain = scaling;
3022 return 0;
3023}
3024
3025int
3026Channel::GetChannelOutputVolumeScaling(float& scaling) const
3027{
wu@webrtc.org63420662013-10-17 18:28:55 +00003028 CriticalSectionScoped cs(&volume_settings_critsect_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003029 scaling = _outputGain;
3030 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3031 VoEId(_instanceId,_channelId),
3032 "GetChannelOutputVolumeScaling() => scaling=%3.2f", scaling);
3033 return 0;
3034}
3035
niklase@google.com470e71d2011-07-07 08:21:25 +00003036int
3037Channel::RegisterExternalEncryption(Encryption& encryption)
3038{
3039 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3040 "Channel::RegisterExternalEncryption()");
3041
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003042 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003043
3044 if (_encryptionPtr)
3045 {
3046 _engineStatisticsPtr->SetLastError(
3047 VE_INVALID_OPERATION, kTraceError,
3048 "RegisterExternalEncryption() encryption already enabled");
3049 return -1;
3050 }
3051
3052 _encryptionPtr = &encryption;
3053
3054 _decrypting = true;
3055 _encrypting = true;
3056
3057 return 0;
3058}
3059
3060int
3061Channel::DeRegisterExternalEncryption()
3062{
3063 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3064 "Channel::DeRegisterExternalEncryption()");
3065
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003066 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003067
3068 if (!_encryptionPtr)
3069 {
3070 _engineStatisticsPtr->SetLastError(
3071 VE_INVALID_OPERATION, kTraceWarning,
3072 "DeRegisterExternalEncryption() encryption already disabled");
3073 return 0;
3074 }
3075
3076 _decrypting = false;
3077 _encrypting = false;
3078
3079 _encryptionPtr = NULL;
3080
3081 return 0;
3082}
3083
3084int Channel::SendTelephoneEventOutband(unsigned char eventCode,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003085 int lengthMs, int attenuationDb,
3086 bool playDtmfEvent)
niklase@google.com470e71d2011-07-07 08:21:25 +00003087{
3088 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3089 "Channel::SendTelephoneEventOutband(..., playDtmfEvent=%d)",
3090 playDtmfEvent);
3091
3092 _playOutbandDtmfEvent = playDtmfEvent;
3093
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003094 if (_rtpRtcpModule->SendTelephoneEventOutband(eventCode, lengthMs,
niklase@google.com470e71d2011-07-07 08:21:25 +00003095 attenuationDb) != 0)
3096 {
3097 _engineStatisticsPtr->SetLastError(
3098 VE_SEND_DTMF_FAILED,
3099 kTraceWarning,
3100 "SendTelephoneEventOutband() failed to send event");
3101 return -1;
3102 }
3103 return 0;
3104}
3105
3106int Channel::SendTelephoneEventInband(unsigned char eventCode,
3107 int lengthMs,
3108 int attenuationDb,
3109 bool playDtmfEvent)
3110{
3111 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3112 "Channel::SendTelephoneEventInband(..., playDtmfEvent=%d)",
3113 playDtmfEvent);
3114
3115 _playInbandDtmfEvent = playDtmfEvent;
3116 _inbandDtmfQueue.AddDtmf(eventCode, lengthMs, attenuationDb);
3117
3118 return 0;
3119}
3120
3121int
3122Channel::SetDtmfPlayoutStatus(bool enable)
3123{
3124 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3125 "Channel::SetDtmfPlayoutStatus()");
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003126 if (audio_coding_->SetDtmfPlayoutStatus(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003127 {
3128 _engineStatisticsPtr->SetLastError(
3129 VE_AUDIO_CODING_MODULE_ERROR, kTraceWarning,
3130 "SetDtmfPlayoutStatus() failed to set Dtmf playout");
3131 return -1;
3132 }
3133 return 0;
3134}
3135
3136bool
3137Channel::DtmfPlayoutStatus() const
3138{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003139 return audio_coding_->DtmfPlayoutStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00003140}
3141
3142int
3143Channel::SetSendTelephoneEventPayloadType(unsigned char type)
3144{
3145 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3146 "Channel::SetSendTelephoneEventPayloadType()");
andrew@webrtc.orgf81f9f82011-08-19 22:56:22 +00003147 if (type > 127)
niklase@google.com470e71d2011-07-07 08:21:25 +00003148 {
3149 _engineStatisticsPtr->SetLastError(
3150 VE_INVALID_ARGUMENT, kTraceError,
3151 "SetSendTelephoneEventPayloadType() invalid type");
3152 return -1;
3153 }
pbos@webrtc.org5b10d8f2013-07-11 15:50:07 +00003154 CodecInst codec = {};
pwestin@webrtc.org1da1ce02011-10-13 15:19:55 +00003155 codec.plfreq = 8000;
3156 codec.pltype = type;
3157 memcpy(codec.plname, "telephone-event", 16);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003158 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003159 {
henrika@webrtc.org4392d5f2013-04-17 07:34:25 +00003160 _rtpRtcpModule->DeRegisterSendPayload(codec.pltype);
3161 if (_rtpRtcpModule->RegisterSendPayload(codec) != 0) {
3162 _engineStatisticsPtr->SetLastError(
3163 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3164 "SetSendTelephoneEventPayloadType() failed to register send"
3165 "payload type");
3166 return -1;
3167 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003168 }
3169 _sendTelephoneEventPayloadType = type;
3170 return 0;
3171}
3172
3173int
3174Channel::GetSendTelephoneEventPayloadType(unsigned char& type)
3175{
3176 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3177 "Channel::GetSendTelephoneEventPayloadType()");
3178 type = _sendTelephoneEventPayloadType;
3179 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3180 VoEId(_instanceId,_channelId),
3181 "GetSendTelephoneEventPayloadType() => type=%u", type);
3182 return 0;
3183}
3184
niklase@google.com470e71d2011-07-07 08:21:25 +00003185int
3186Channel::UpdateRxVadDetection(AudioFrame& audioFrame)
3187{
3188 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3189 "Channel::UpdateRxVadDetection()");
3190
3191 int vadDecision = 1;
3192
andrew@webrtc.org63a50982012-05-02 23:56:37 +00003193 vadDecision = (audioFrame.vad_activity_ == AudioFrame::kVadActive)? 1 : 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00003194
3195 if ((vadDecision != _oldVadDecision) && _rxVadObserverPtr)
3196 {
3197 OnRxVadDetected(vadDecision);
3198 _oldVadDecision = vadDecision;
3199 }
3200
3201 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
3202 "Channel::UpdateRxVadDetection() => vadDecision=%d",
3203 vadDecision);
3204 return 0;
3205}
3206
3207int
3208Channel::RegisterRxVadObserver(VoERxVadCallback &observer)
3209{
3210 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3211 "Channel::RegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003212 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003213
3214 if (_rxVadObserverPtr)
3215 {
3216 _engineStatisticsPtr->SetLastError(
3217 VE_INVALID_OPERATION, kTraceError,
3218 "RegisterRxVadObserver() observer already enabled");
3219 return -1;
3220 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003221 _rxVadObserverPtr = &observer;
3222 _RxVadDetection = true;
3223 return 0;
3224}
3225
3226int
3227Channel::DeRegisterRxVadObserver()
3228{
3229 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3230 "Channel::DeRegisterRxVadObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003231 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003232
3233 if (!_rxVadObserverPtr)
3234 {
3235 _engineStatisticsPtr->SetLastError(
3236 VE_INVALID_OPERATION, kTraceWarning,
3237 "DeRegisterRxVadObserver() observer already disabled");
3238 return 0;
3239 }
3240 _rxVadObserverPtr = NULL;
3241 _RxVadDetection = false;
3242 return 0;
3243}
3244
3245int
3246Channel::VoiceActivityIndicator(int &activity)
3247{
3248 activity = _sendFrameType;
3249
3250 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003251 "Channel::VoiceActivityIndicator(indicator=%d)", activity);
niklase@google.com470e71d2011-07-07 08:21:25 +00003252 return 0;
3253}
3254
3255#ifdef WEBRTC_VOICE_ENGINE_AGC
3256
3257int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003258Channel::SetRxAgcStatus(bool enable, AgcModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003259{
3260 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3261 "Channel::SetRxAgcStatus(enable=%d, mode=%d)",
3262 (int)enable, (int)mode);
3263
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003264 GainControl::Mode agcMode = kDefaultRxAgcMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003265 switch (mode)
3266 {
3267 case kAgcDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003268 break;
3269 case kAgcUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003270 agcMode = rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003271 break;
3272 case kAgcFixedDigital:
3273 agcMode = GainControl::kFixedDigital;
3274 break;
3275 case kAgcAdaptiveDigital:
3276 agcMode =GainControl::kAdaptiveDigital;
3277 break;
3278 default:
3279 _engineStatisticsPtr->SetLastError(
3280 VE_INVALID_ARGUMENT, kTraceError,
3281 "SetRxAgcStatus() invalid Agc mode");
3282 return -1;
3283 }
3284
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003285 if (rx_audioproc_->gain_control()->set_mode(agcMode) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003286 {
3287 _engineStatisticsPtr->SetLastError(
3288 VE_APM_ERROR, kTraceError,
3289 "SetRxAgcStatus() failed to set Agc mode");
3290 return -1;
3291 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003292 if (rx_audioproc_->gain_control()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003293 {
3294 _engineStatisticsPtr->SetLastError(
3295 VE_APM_ERROR, kTraceError,
3296 "SetRxAgcStatus() failed to set Agc state");
3297 return -1;
3298 }
3299
3300 _rxAgcIsEnabled = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +00003301 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3302
3303 return 0;
3304}
3305
3306int
3307Channel::GetRxAgcStatus(bool& enabled, AgcModes& mode)
3308{
3309 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3310 "Channel::GetRxAgcStatus(enable=?, mode=?)");
3311
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003312 bool enable = rx_audioproc_->gain_control()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003313 GainControl::Mode agcMode =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003314 rx_audioproc_->gain_control()->mode();
niklase@google.com470e71d2011-07-07 08:21:25 +00003315
3316 enabled = enable;
3317
3318 switch (agcMode)
3319 {
3320 case GainControl::kFixedDigital:
3321 mode = kAgcFixedDigital;
3322 break;
3323 case GainControl::kAdaptiveDigital:
3324 mode = kAgcAdaptiveDigital;
3325 break;
3326 default:
3327 _engineStatisticsPtr->SetLastError(
3328 VE_APM_ERROR, kTraceError,
3329 "GetRxAgcStatus() invalid Agc mode");
3330 return -1;
3331 }
3332
3333 return 0;
3334}
3335
3336int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003337Channel::SetRxAgcConfig(AgcConfig config)
niklase@google.com470e71d2011-07-07 08:21:25 +00003338{
3339 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3340 "Channel::SetRxAgcConfig()");
3341
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003342 if (rx_audioproc_->gain_control()->set_target_level_dbfs(
niklase@google.com470e71d2011-07-07 08:21:25 +00003343 config.targetLeveldBOv) != 0)
3344 {
3345 _engineStatisticsPtr->SetLastError(
3346 VE_APM_ERROR, kTraceError,
3347 "SetRxAgcConfig() failed to set target peak |level|"
3348 "(or envelope) of the Agc");
3349 return -1;
3350 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003351 if (rx_audioproc_->gain_control()->set_compression_gain_db(
niklase@google.com470e71d2011-07-07 08:21:25 +00003352 config.digitalCompressionGaindB) != 0)
3353 {
3354 _engineStatisticsPtr->SetLastError(
3355 VE_APM_ERROR, kTraceError,
3356 "SetRxAgcConfig() failed to set the range in |gain| the"
3357 " digital compression stage may apply");
3358 return -1;
3359 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003360 if (rx_audioproc_->gain_control()->enable_limiter(
niklase@google.com470e71d2011-07-07 08:21:25 +00003361 config.limiterEnable) != 0)
3362 {
3363 _engineStatisticsPtr->SetLastError(
3364 VE_APM_ERROR, kTraceError,
3365 "SetRxAgcConfig() failed to set hard limiter to the signal");
3366 return -1;
3367 }
3368
3369 return 0;
3370}
3371
3372int
3373Channel::GetRxAgcConfig(AgcConfig& config)
3374{
3375 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3376 "Channel::GetRxAgcConfig(config=%?)");
3377
3378 config.targetLeveldBOv =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003379 rx_audioproc_->gain_control()->target_level_dbfs();
niklase@google.com470e71d2011-07-07 08:21:25 +00003380 config.digitalCompressionGaindB =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003381 rx_audioproc_->gain_control()->compression_gain_db();
niklase@google.com470e71d2011-07-07 08:21:25 +00003382 config.limiterEnable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003383 rx_audioproc_->gain_control()->is_limiter_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003384
3385 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3386 VoEId(_instanceId,_channelId), "GetRxAgcConfig() => "
3387 "targetLeveldBOv=%u, digitalCompressionGaindB=%u,"
3388 " limiterEnable=%d",
3389 config.targetLeveldBOv,
3390 config.digitalCompressionGaindB,
3391 config.limiterEnable);
3392
3393 return 0;
3394}
3395
3396#endif // #ifdef WEBRTC_VOICE_ENGINE_AGC
3397
3398#ifdef WEBRTC_VOICE_ENGINE_NR
3399
3400int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003401Channel::SetRxNsStatus(bool enable, NsModes mode)
niklase@google.com470e71d2011-07-07 08:21:25 +00003402{
3403 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3404 "Channel::SetRxNsStatus(enable=%d, mode=%d)",
3405 (int)enable, (int)mode);
3406
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003407 NoiseSuppression::Level nsLevel = kDefaultNsMode;
niklase@google.com470e71d2011-07-07 08:21:25 +00003408 switch (mode)
3409 {
3410
3411 case kNsDefault:
niklase@google.com470e71d2011-07-07 08:21:25 +00003412 break;
3413 case kNsUnchanged:
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003414 nsLevel = rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003415 break;
3416 case kNsConference:
3417 nsLevel = NoiseSuppression::kHigh;
3418 break;
3419 case kNsLowSuppression:
3420 nsLevel = NoiseSuppression::kLow;
3421 break;
3422 case kNsModerateSuppression:
3423 nsLevel = NoiseSuppression::kModerate;
3424 break;
3425 case kNsHighSuppression:
3426 nsLevel = NoiseSuppression::kHigh;
3427 break;
3428 case kNsVeryHighSuppression:
3429 nsLevel = NoiseSuppression::kVeryHigh;
3430 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003431 }
3432
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003433 if (rx_audioproc_->noise_suppression()->set_level(nsLevel)
niklase@google.com470e71d2011-07-07 08:21:25 +00003434 != 0)
3435 {
3436 _engineStatisticsPtr->SetLastError(
3437 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003438 "SetRxNsStatus() failed to set NS level");
niklase@google.com470e71d2011-07-07 08:21:25 +00003439 return -1;
3440 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003441 if (rx_audioproc_->noise_suppression()->Enable(enable) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003442 {
3443 _engineStatisticsPtr->SetLastError(
3444 VE_APM_ERROR, kTraceError,
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00003445 "SetRxNsStatus() failed to set NS state");
niklase@google.com470e71d2011-07-07 08:21:25 +00003446 return -1;
3447 }
3448
3449 _rxNsIsEnabled = enable;
3450 _rxApmIsEnabled = ((_rxAgcIsEnabled == true) || (_rxNsIsEnabled == true));
3451
3452 return 0;
3453}
3454
3455int
3456Channel::GetRxNsStatus(bool& enabled, NsModes& mode)
3457{
3458 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3459 "Channel::GetRxNsStatus(enable=?, mode=?)");
3460
3461 bool enable =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003462 rx_audioproc_->noise_suppression()->is_enabled();
niklase@google.com470e71d2011-07-07 08:21:25 +00003463 NoiseSuppression::Level ncLevel =
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003464 rx_audioproc_->noise_suppression()->level();
niklase@google.com470e71d2011-07-07 08:21:25 +00003465
3466 enabled = enable;
3467
3468 switch (ncLevel)
3469 {
3470 case NoiseSuppression::kLow:
3471 mode = kNsLowSuppression;
3472 break;
3473 case NoiseSuppression::kModerate:
3474 mode = kNsModerateSuppression;
3475 break;
3476 case NoiseSuppression::kHigh:
3477 mode = kNsHighSuppression;
3478 break;
3479 case NoiseSuppression::kVeryHigh:
3480 mode = kNsVeryHighSuppression;
3481 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003482 }
3483
3484 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3485 VoEId(_instanceId,_channelId),
3486 "GetRxNsStatus() => enabled=%d, mode=%d", enabled, mode);
3487 return 0;
3488}
3489
3490#endif // #ifdef WEBRTC_VOICE_ENGINE_NR
3491
3492int
3493Channel::RegisterRTPObserver(VoERTPObserver& observer)
3494{
3495 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3496 "Channel::RegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003497 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003498
3499 if (_rtpObserverPtr)
3500 {
3501 _engineStatisticsPtr->SetLastError(
3502 VE_INVALID_OPERATION, kTraceError,
3503 "RegisterRTPObserver() observer already enabled");
3504 return -1;
3505 }
3506
3507 _rtpObserverPtr = &observer;
3508 _rtpObserver = true;
3509
3510 return 0;
3511}
3512
3513int
3514Channel::DeRegisterRTPObserver()
3515{
3516 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3517 "Channel::DeRegisterRTPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003518 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003519
3520 if (!_rtpObserverPtr)
3521 {
3522 _engineStatisticsPtr->SetLastError(
3523 VE_INVALID_OPERATION, kTraceWarning,
3524 "DeRegisterRTPObserver() observer already disabled");
3525 return 0;
3526 }
3527
3528 _rtpObserver = false;
3529 _rtpObserverPtr = NULL;
3530
3531 return 0;
3532}
3533
3534int
3535Channel::RegisterRTCPObserver(VoERTCPObserver& observer)
3536{
3537 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3538 "Channel::RegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003539 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003540
3541 if (_rtcpObserverPtr)
3542 {
3543 _engineStatisticsPtr->SetLastError(
3544 VE_INVALID_OPERATION, kTraceError,
3545 "RegisterRTCPObserver() observer already enabled");
3546 return -1;
3547 }
3548
3549 _rtcpObserverPtr = &observer;
3550 _rtcpObserver = true;
3551
3552 return 0;
3553}
3554
3555int
3556Channel::DeRegisterRTCPObserver()
3557{
3558 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3559 "Channel::DeRegisterRTCPObserver()");
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00003560 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00003561
3562 if (!_rtcpObserverPtr)
3563 {
3564 _engineStatisticsPtr->SetLastError(
3565 VE_INVALID_OPERATION, kTraceWarning,
3566 "DeRegisterRTCPObserver() observer already disabled");
3567 return 0;
3568 }
3569
3570 _rtcpObserver = false;
3571 _rtcpObserverPtr = NULL;
3572
3573 return 0;
3574}
3575
3576int
3577Channel::SetLocalSSRC(unsigned int ssrc)
3578{
3579 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3580 "Channel::SetLocalSSRC()");
3581 if (_sending)
3582 {
3583 _engineStatisticsPtr->SetLastError(
3584 VE_ALREADY_SENDING, kTraceError,
3585 "SetLocalSSRC() already sending");
3586 return -1;
3587 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003588 if (_rtpRtcpModule->SetSSRC(ssrc) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003589 {
3590 _engineStatisticsPtr->SetLastError(
3591 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3592 "SetLocalSSRC() failed to set SSRC");
3593 return -1;
3594 }
3595 return 0;
3596}
3597
3598int
3599Channel::GetLocalSSRC(unsigned int& ssrc)
3600{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003601 ssrc = _rtpRtcpModule->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003602 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3603 VoEId(_instanceId,_channelId),
3604 "GetLocalSSRC() => ssrc=%lu", ssrc);
3605 return 0;
3606}
3607
3608int
3609Channel::GetRemoteSSRC(unsigned int& ssrc)
3610{
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003611 ssrc = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00003612 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3613 VoEId(_instanceId,_channelId),
3614 "GetRemoteSSRC() => ssrc=%lu", ssrc);
3615 return 0;
3616}
3617
3618int
3619Channel::GetRemoteCSRCs(unsigned int arrCSRC[15])
3620{
3621 if (arrCSRC == NULL)
3622 {
3623 _engineStatisticsPtr->SetLastError(
3624 VE_INVALID_ARGUMENT, kTraceError,
3625 "GetRemoteCSRCs() invalid array argument");
3626 return -1;
3627 }
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003628 uint32_t arrOfCSRC[kRtpCsrcSize];
3629 int32_t CSRCs(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003630 CSRCs = _rtpRtcpModule->CSRCs(arrOfCSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00003631 if (CSRCs > 0)
3632 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00003633 memcpy(arrCSRC, arrOfCSRC, CSRCs * sizeof(uint32_t));
niklase@google.com470e71d2011-07-07 08:21:25 +00003634 for (int i = 0; i < (int) CSRCs; i++)
3635 {
3636 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3637 VoEId(_instanceId, _channelId),
3638 "GetRemoteCSRCs() => arrCSRC[%d]=%lu", i, arrCSRC[i]);
3639 }
3640 } else
3641 {
3642 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3643 VoEId(_instanceId, _channelId),
3644 "GetRemoteCSRCs() => list is empty!");
3645 }
3646 return CSRCs;
3647}
3648
3649int
3650Channel::SetRTPAudioLevelIndicationStatus(bool enable, unsigned char ID)
3651{
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003652 if (rtp_audioproc_.get() == NULL) {
3653 rtp_audioproc_.reset(AudioProcessing::Create(VoEModuleId(_instanceId,
3654 _channelId)));
3655 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003656
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003657 if (rtp_audioproc_->level_estimator()->Enable(enable) !=
3658 AudioProcessing::kNoError) {
3659 _engineStatisticsPtr->SetLastError(VE_APM_ERROR, kTraceError,
3660 "Failed to enable AudioProcessing::level_estimator()");
3661 return -1;
3662 }
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00003663
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003664 _includeAudioLevelIndication = enable;
3665 if (enable) {
3666 rtp_header_parser_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel,
3667 ID);
3668 } else {
3669 rtp_header_parser_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
3670 }
3671 return _rtpRtcpModule->SetRTPAudioLevelIndicationStatus(enable, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003672}
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00003673
niklase@google.com470e71d2011-07-07 08:21:25 +00003674int
3675Channel::GetRTPAudioLevelIndicationStatus(bool& enabled, unsigned char& ID)
3676{
3677 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3678 VoEId(_instanceId,_channelId),
3679 "GetRTPAudioLevelIndicationStatus() => enabled=%d, ID=%u",
3680 enabled, ID);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003681 return _rtpRtcpModule->GetRTPAudioLevelIndicationStatus(enabled, ID);
niklase@google.com470e71d2011-07-07 08:21:25 +00003682}
3683
3684int
3685Channel::SetRTCPStatus(bool enable)
3686{
3687 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
3688 "Channel::SetRTCPStatus()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003689 if (_rtpRtcpModule->SetRTCPStatus(enable ?
niklase@google.com470e71d2011-07-07 08:21:25 +00003690 kRtcpCompound : kRtcpOff) != 0)
3691 {
3692 _engineStatisticsPtr->SetLastError(
3693 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3694 "SetRTCPStatus() failed to set RTCP status");
3695 return -1;
3696 }
3697 return 0;
3698}
3699
3700int
3701Channel::GetRTCPStatus(bool& enabled)
3702{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003703 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003704 enabled = (method != kRtcpOff);
3705 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3706 VoEId(_instanceId,_channelId),
3707 "GetRTCPStatus() => enabled=%d", enabled);
3708 return 0;
3709}
3710
3711int
3712Channel::SetRTCP_CNAME(const char cName[256])
3713{
3714 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3715 "Channel::SetRTCP_CNAME()");
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003716 if (_rtpRtcpModule->SetCNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003717 {
3718 _engineStatisticsPtr->SetLastError(
3719 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3720 "SetRTCP_CNAME() failed to set RTCP CNAME");
3721 return -1;
3722 }
3723 return 0;
3724}
3725
3726int
3727Channel::GetRTCP_CNAME(char cName[256])
3728{
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003729 if (_rtpRtcpModule->CNAME(cName) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003730 {
3731 _engineStatisticsPtr->SetLastError(
3732 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3733 "GetRTCP_CNAME() failed to retrieve RTCP CNAME");
3734 return -1;
3735 }
3736 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3737 VoEId(_instanceId, _channelId),
3738 "GetRTCP_CNAME() => cName=%s", cName);
3739 return 0;
3740}
3741
3742int
3743Channel::GetRemoteRTCP_CNAME(char cName[256])
3744{
3745 if (cName == NULL)
3746 {
3747 _engineStatisticsPtr->SetLastError(
3748 VE_INVALID_ARGUMENT, kTraceError,
3749 "GetRemoteRTCP_CNAME() invalid CNAME input buffer");
3750 return -1;
3751 }
leozwang@webrtc.org813e4b02012-03-01 18:34:25 +00003752 char cname[RTCP_CNAME_SIZE];
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003753 const uint32_t remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003754 if (_rtpRtcpModule->RemoteCNAME(remoteSSRC, cname) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003755 {
3756 _engineStatisticsPtr->SetLastError(
3757 VE_CANNOT_RETRIEVE_CNAME, kTraceError,
3758 "GetRemoteRTCP_CNAME() failed to retrieve remote RTCP CNAME");
3759 return -1;
3760 }
3761 strcpy(cName, cname);
3762 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3763 VoEId(_instanceId, _channelId),
3764 "GetRemoteRTCP_CNAME() => cName=%s", cName);
3765 return 0;
3766}
3767
3768int
3769Channel::GetRemoteRTCPData(
3770 unsigned int& NTPHigh,
3771 unsigned int& NTPLow,
3772 unsigned int& timestamp,
3773 unsigned int& playoutTimestamp,
3774 unsigned int* jitter,
3775 unsigned short* fractionLost)
3776{
3777 // --- Information from sender info in received Sender Reports
3778
3779 RTCPSenderInfo senderInfo;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003780 if (_rtpRtcpModule->RemoteRTCPStat(&senderInfo) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00003781 {
3782 _engineStatisticsPtr->SetLastError(
3783 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003784 "GetRemoteRTCPData() failed to retrieve sender info for remote "
niklase@google.com470e71d2011-07-07 08:21:25 +00003785 "side");
3786 return -1;
3787 }
3788
3789 // We only utilize 12 out of 20 bytes in the sender info (ignores packet
3790 // and octet count)
3791 NTPHigh = senderInfo.NTPseconds;
3792 NTPLow = senderInfo.NTPfraction;
3793 timestamp = senderInfo.RTPtimeStamp;
3794
3795 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3796 VoEId(_instanceId, _channelId),
3797 "GetRemoteRTCPData() => NTPHigh=%lu, NTPLow=%lu, "
3798 "timestamp=%lu",
3799 NTPHigh, NTPLow, timestamp);
3800
3801 // --- Locally derived information
3802
3803 // This value is updated on each incoming RTCP packet (0 when no packet
3804 // has been received)
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003805 playoutTimestamp = playout_timestamp_rtcp_;
niklase@google.com470e71d2011-07-07 08:21:25 +00003806
3807 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3808 VoEId(_instanceId, _channelId),
3809 "GetRemoteRTCPData() => playoutTimestamp=%lu",
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00003810 playout_timestamp_rtcp_);
niklase@google.com470e71d2011-07-07 08:21:25 +00003811
3812 if (NULL != jitter || NULL != fractionLost)
3813 {
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003814 // Get all RTCP receiver report blocks that have been received on this
3815 // channel. If we receive RTP packets from a remote source we know the
3816 // remote SSRC and use the report block from him.
3817 // Otherwise use the first report block.
3818 std::vector<RTCPReportBlock> remote_stats;
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003819 if (_rtpRtcpModule->RemoteRTCPStat(&remote_stats) != 0 ||
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003820 remote_stats.empty()) {
3821 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
3822 VoEId(_instanceId, _channelId),
3823 "GetRemoteRTCPData() failed to measure statistics due"
3824 " to lack of received RTP and/or RTCP packets");
3825 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00003826 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003827
wu@webrtc.org822fbd82013-08-15 23:38:54 +00003828 uint32_t remoteSSRC = rtp_receiver_->SSRC();
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003829 std::vector<RTCPReportBlock>::const_iterator it = remote_stats.begin();
3830 for (; it != remote_stats.end(); ++it) {
3831 if (it->remoteSSRC == remoteSSRC)
3832 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00003833 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003834
3835 if (it == remote_stats.end()) {
3836 // If we have not received any RTCP packets from this SSRC it probably
3837 // means that we have not received any RTP packets.
3838 // Use the first received report block instead.
3839 it = remote_stats.begin();
3840 remoteSSRC = it->remoteSSRC;
niklase@google.com470e71d2011-07-07 08:21:25 +00003841 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003842
xians@webrtc.org79af7342012-01-31 12:22:14 +00003843 if (jitter) {
3844 *jitter = it->jitter;
3845 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3846 VoEId(_instanceId, _channelId),
3847 "GetRemoteRTCPData() => jitter = %lu", *jitter);
3848 }
perkj@webrtc.orgce5990c2012-01-11 13:00:08 +00003849
xians@webrtc.org79af7342012-01-31 12:22:14 +00003850 if (fractionLost) {
3851 *fractionLost = it->fractionLost;
3852 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3853 VoEId(_instanceId, _channelId),
3854 "GetRemoteRTCPData() => fractionLost = %lu",
3855 *fractionLost);
3856 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003857 }
3858 return 0;
3859}
3860
3861int
pbos@webrtc.org92135212013-05-14 08:31:39 +00003862Channel::SendApplicationDefinedRTCPPacket(unsigned char subType,
niklase@google.com470e71d2011-07-07 08:21:25 +00003863 unsigned int name,
3864 const char* data,
3865 unsigned short dataLengthInBytes)
3866{
3867 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
3868 "Channel::SendApplicationDefinedRTCPPacket()");
3869 if (!_sending)
3870 {
3871 _engineStatisticsPtr->SetLastError(
3872 VE_NOT_SENDING, kTraceError,
3873 "SendApplicationDefinedRTCPPacket() not sending");
3874 return -1;
3875 }
3876 if (NULL == data)
3877 {
3878 _engineStatisticsPtr->SetLastError(
3879 VE_INVALID_ARGUMENT, kTraceError,
3880 "SendApplicationDefinedRTCPPacket() invalid data value");
3881 return -1;
3882 }
3883 if (dataLengthInBytes % 4 != 0)
3884 {
3885 _engineStatisticsPtr->SetLastError(
3886 VE_INVALID_ARGUMENT, kTraceError,
3887 "SendApplicationDefinedRTCPPacket() invalid length value");
3888 return -1;
3889 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003890 RTCPMethod status = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00003891 if (status == kRtcpOff)
3892 {
3893 _engineStatisticsPtr->SetLastError(
3894 VE_RTCP_ERROR, kTraceError,
3895 "SendApplicationDefinedRTCPPacket() RTCP is disabled");
3896 return -1;
3897 }
3898
3899 // Create and schedule the RTCP APP packet for transmission
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00003900 if (_rtpRtcpModule->SetRTCPApplicationSpecificData(
niklase@google.com470e71d2011-07-07 08:21:25 +00003901 subType,
3902 name,
3903 (const unsigned char*) data,
3904 dataLengthInBytes) != 0)
3905 {
3906 _engineStatisticsPtr->SetLastError(
3907 VE_SEND_ERROR, kTraceError,
3908 "SendApplicationDefinedRTCPPacket() failed to send RTCP packet");
3909 return -1;
3910 }
3911 return 0;
3912}
3913
3914int
3915Channel::GetRTPStatistics(
3916 unsigned int& averageJitterMs,
3917 unsigned int& maxJitterMs,
3918 unsigned int& discardedPackets)
3919{
niklase@google.com470e71d2011-07-07 08:21:25 +00003920 // The jitter statistics is updated for each received RTP packet and is
3921 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003922 if (_rtpRtcpModule->RTCP() == kRtcpOff) {
3923 // If RTCP is off, there is no timed thread in the RTCP module regularly
3924 // generating new stats, trigger the update manually here instead.
3925 StreamStatistician* statistician =
3926 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
3927 if (statistician) {
3928 // Don't use returned statistics, use data from proxy instead so that
3929 // max jitter can be fetched atomically.
3930 RtcpStatistics s;
3931 statistician->GetStatistics(&s, true);
3932 }
niklase@google.com470e71d2011-07-07 08:21:25 +00003933 }
3934
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003935 ChannelStatistics stats = statistics_proxy_->GetStats();
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00003936 const int32_t playoutFrequency = audio_coding_->PlayoutFrequency();
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00003937 if (playoutFrequency > 0) {
3938 // Scale RTP statistics given the current playout frequency
3939 maxJitterMs = stats.max_jitter / (playoutFrequency / 1000);
3940 averageJitterMs = stats.rtcp.jitter / (playoutFrequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00003941 }
3942
3943 discardedPackets = _numberOfDiscardedPackets;
3944
3945 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
3946 VoEId(_instanceId, _channelId),
3947 "GetRTPStatistics() => averageJitterMs = %lu, maxJitterMs = %lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00003948 " discardedPackets = %lu)",
niklase@google.com470e71d2011-07-07 08:21:25 +00003949 averageJitterMs, maxJitterMs, discardedPackets);
3950 return 0;
3951}
3952
henrika@webrtc.org8a2fc882012-08-22 08:53:55 +00003953int Channel::GetRemoteRTCPSenderInfo(SenderInfo* sender_info) {
3954 if (sender_info == NULL) {
3955 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3956 "GetRemoteRTCPSenderInfo() invalid sender_info.");
3957 return -1;
3958 }
3959
3960 // Get the sender info from the latest received RTCP Sender Report.
3961 RTCPSenderInfo rtcp_sender_info;
3962 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_sender_info) != 0) {
3963 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3964 "GetRemoteRTCPSenderInfo() failed to read RTCP SR sender info.");
3965 return -1;
3966 }
3967
3968 sender_info->NTP_timestamp_high = rtcp_sender_info.NTPseconds;
3969 sender_info->NTP_timestamp_low = rtcp_sender_info.NTPfraction;
3970 sender_info->RTP_timestamp = rtcp_sender_info.RTPtimeStamp;
3971 sender_info->sender_packet_count = rtcp_sender_info.sendPacketCount;
3972 sender_info->sender_octet_count = rtcp_sender_info.sendOctetCount;
3973 return 0;
3974}
3975
3976int Channel::GetRemoteRTCPReportBlocks(
3977 std::vector<ReportBlock>* report_blocks) {
3978 if (report_blocks == NULL) {
3979 _engineStatisticsPtr->SetLastError(VE_INVALID_ARGUMENT, kTraceError,
3980 "GetRemoteRTCPReportBlock()s invalid report_blocks.");
3981 return -1;
3982 }
3983
3984 // Get the report blocks from the latest received RTCP Sender or Receiver
3985 // Report. Each element in the vector contains the sender's SSRC and a
3986 // report block according to RFC 3550.
3987 std::vector<RTCPReportBlock> rtcp_report_blocks;
3988 if (_rtpRtcpModule->RemoteRTCPStat(&rtcp_report_blocks) != 0) {
3989 _engineStatisticsPtr->SetLastError(VE_RTP_RTCP_MODULE_ERROR, kTraceError,
3990 "GetRemoteRTCPReportBlocks() failed to read RTCP SR/RR report block.");
3991 return -1;
3992 }
3993
3994 if (rtcp_report_blocks.empty())
3995 return 0;
3996
3997 std::vector<RTCPReportBlock>::const_iterator it = rtcp_report_blocks.begin();
3998 for (; it != rtcp_report_blocks.end(); ++it) {
3999 ReportBlock report_block;
4000 report_block.sender_SSRC = it->remoteSSRC;
4001 report_block.source_SSRC = it->sourceSSRC;
4002 report_block.fraction_lost = it->fractionLost;
4003 report_block.cumulative_num_packets_lost = it->cumulativeLost;
4004 report_block.extended_highest_sequence_number = it->extendedHighSeqNum;
4005 report_block.interarrival_jitter = it->jitter;
4006 report_block.last_SR_timestamp = it->lastSR;
4007 report_block.delay_since_last_SR = it->delaySinceLastSR;
4008 report_blocks->push_back(report_block);
4009 }
4010 return 0;
4011}
4012
niklase@google.com470e71d2011-07-07 08:21:25 +00004013int
4014Channel::GetRTPStatistics(CallStatistics& stats)
4015{
niklase@google.com470e71d2011-07-07 08:21:25 +00004016 // --- Part one of the final structure (four values)
4017
4018 // The jitter statistics is updated for each received RTP packet and is
4019 // based on received packets.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00004020 RtcpStatistics statistics;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004021 StreamStatistician* statistician =
4022 rtp_receive_statistics_->GetStatistician(rtp_receiver_->SSRC());
4023 if (!statistician || !statistician->GetStatistics(
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004024 &statistics, _rtpRtcpModule->RTCP() == kRtcpOff)) {
4025 _engineStatisticsPtr->SetLastError(
4026 VE_CANNOT_RETRIEVE_RTP_STAT, kTraceWarning,
4027 "GetRTPStatistics() failed to read RTP statistics from the "
4028 "RTP/RTCP module");
niklase@google.com470e71d2011-07-07 08:21:25 +00004029 }
4030
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004031 stats.fractionLost = statistics.fraction_lost;
4032 stats.cumulativeLost = statistics.cumulative_lost;
4033 stats.extendedMax = statistics.extended_max_sequence_number;
4034 stats.jitterSamples = statistics.jitter;
niklase@google.com470e71d2011-07-07 08:21:25 +00004035
4036 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4037 VoEId(_instanceId, _channelId),
4038 "GetRTPStatistics() => fractionLost=%lu, cumulativeLost=%lu,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004039 " extendedMax=%lu, jitterSamples=%li)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004040 stats.fractionLost, stats.cumulativeLost, stats.extendedMax,
4041 stats.jitterSamples);
4042
4043 // --- Part two of the final structure (one value)
4044
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004045 uint16_t RTT(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004046 RTCPMethod method = _rtpRtcpModule->RTCP();
niklase@google.com470e71d2011-07-07 08:21:25 +00004047 if (method == kRtcpOff)
4048 {
4049 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4050 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004051 "GetRTPStatistics() RTCP is disabled => valid RTT "
niklase@google.com470e71d2011-07-07 08:21:25 +00004052 "measurements cannot be retrieved");
4053 } else
4054 {
4055 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004056 uint32_t remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004057 if (remoteSSRC > 0)
4058 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004059 uint16_t avgRTT(0);
4060 uint16_t maxRTT(0);
4061 uint16_t minRTT(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004062
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004063 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT, &maxRTT)
niklase@google.com470e71d2011-07-07 08:21:25 +00004064 != 0)
4065 {
4066 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4067 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004068 "GetRTPStatistics() failed to retrieve RTT from "
niklase@google.com470e71d2011-07-07 08:21:25 +00004069 "the RTP/RTCP module");
4070 }
4071 } else
4072 {
4073 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4074 VoEId(_instanceId, _channelId),
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004075 "GetRTPStatistics() failed to measure RTT since no "
niklase@google.com470e71d2011-07-07 08:21:25 +00004076 "RTP packets have been received yet");
4077 }
4078 }
4079
4080 stats.rttMs = static_cast<int> (RTT);
4081
4082 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4083 VoEId(_instanceId, _channelId),
4084 "GetRTPStatistics() => rttMs=%d", stats.rttMs);
4085
4086 // --- Part three of the final structure (four values)
4087
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004088 uint32_t bytesSent(0);
4089 uint32_t packetsSent(0);
4090 uint32_t bytesReceived(0);
4091 uint32_t packetsReceived(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004092
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00004093 if (statistician) {
4094 statistician->GetDataCounters(&bytesReceived, &packetsReceived);
4095 }
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004096
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004097 if (_rtpRtcpModule->DataCountersRTP(&bytesSent,
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004098 &packetsSent) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004099 {
4100 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4101 VoEId(_instanceId, _channelId),
4102 "GetRTPStatistics() failed to retrieve RTP datacounters =>"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004103 " output will not be complete");
niklase@google.com470e71d2011-07-07 08:21:25 +00004104 }
4105
4106 stats.bytesSent = bytesSent;
4107 stats.packetsSent = packetsSent;
4108 stats.bytesReceived = bytesReceived;
4109 stats.packetsReceived = packetsReceived;
4110
4111 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4112 VoEId(_instanceId, _channelId),
4113 "GetRTPStatistics() => bytesSent=%d, packetsSent=%d,"
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00004114 " bytesReceived=%d, packetsReceived=%d)",
niklase@google.com470e71d2011-07-07 08:21:25 +00004115 stats.bytesSent, stats.packetsSent, stats.bytesReceived,
4116 stats.packetsReceived);
4117
4118 return 0;
4119}
4120
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004121int Channel::SetFECStatus(bool enable, int redPayloadtype) {
4122 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4123 "Channel::SetFECStatus()");
niklase@google.com470e71d2011-07-07 08:21:25 +00004124
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00004125 if (enable) {
4126 if (redPayloadtype < 0 || redPayloadtype > 127) {
4127 _engineStatisticsPtr->SetLastError(
4128 VE_PLTYPE_ERROR, kTraceError,
4129 "SetFECStatus() invalid RED payload type");
4130 return -1;
4131 }
4132
4133 if (SetRedPayloadType(redPayloadtype) < 0) {
4134 _engineStatisticsPtr->SetLastError(
4135 VE_CODEC_ERROR, kTraceError,
4136 "SetSecondarySendCodec() Failed to register RED ACM");
4137 return -1;
4138 }
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004139 }
niklase@google.com470e71d2011-07-07 08:21:25 +00004140
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004141 if (audio_coding_->SetFECStatus(enable) != 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00004142 _engineStatisticsPtr->SetLastError(
4143 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4144 "SetFECStatus() failed to set FEC state in the ACM");
4145 return -1;
4146 }
4147 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004148}
4149
4150int
4151Channel::GetFECStatus(bool& enabled, int& redPayloadtype)
4152{
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004153 enabled = audio_coding_->FECStatus();
niklase@google.com470e71d2011-07-07 08:21:25 +00004154 if (enabled)
4155 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004156 int8_t payloadType(0);
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004157 if (_rtpRtcpModule->SendREDPayloadType(payloadType) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004158 {
4159 _engineStatisticsPtr->SetLastError(
4160 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4161 "GetFECStatus() failed to retrieve RED PT from RTP/RTCP "
4162 "module");
4163 return -1;
4164 }
4165 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4166 VoEId(_instanceId, _channelId),
4167 "GetFECStatus() => enabled=%d, redPayloadtype=%d",
4168 enabled, redPayloadtype);
4169 return 0;
4170 }
4171 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4172 VoEId(_instanceId, _channelId),
4173 "GetFECStatus() => enabled=%d", enabled);
4174 return 0;
4175}
4176
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004177void Channel::SetNACKStatus(bool enable, int maxNumberOfPackets) {
4178 // None of these functions can fail.
4179 _rtpRtcpModule->SetStorePacketsStatus(enable, maxNumberOfPackets);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +00004180 rtp_receive_statistics_->SetMaxReorderingThreshold(maxNumberOfPackets);
4181 rtp_receiver_->SetNACKStatus(enable ? kNackRtcp : kNackOff);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004182 if (enable)
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004183 audio_coding_->EnableNack(maxNumberOfPackets);
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004184 else
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004185 audio_coding_->DisableNack();
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004186}
4187
pwestin@webrtc.orgd30859e2013-06-06 21:09:01 +00004188// Called when we are missing one or more packets.
4189int Channel::ResendPackets(const uint16_t* sequence_numbers, int length) {
pwestin@webrtc.orgdb249952013-06-05 15:33:20 +00004190 return _rtpRtcpModule->SendNACK(sequence_numbers, length);
4191}
4192
niklase@google.com470e71d2011-07-07 08:21:25 +00004193int
niklase@google.com470e71d2011-07-07 08:21:25 +00004194Channel::StartRTPDump(const char fileNameUTF8[1024],
4195 RTPDirections direction)
4196{
4197 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4198 "Channel::StartRTPDump()");
4199 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4200 {
4201 _engineStatisticsPtr->SetLastError(
4202 VE_INVALID_ARGUMENT, kTraceError,
4203 "StartRTPDump() invalid RTP direction");
4204 return -1;
4205 }
4206 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4207 &_rtpDumpIn : &_rtpDumpOut;
4208 if (rtpDumpPtr == NULL)
4209 {
4210 assert(false);
4211 return -1;
4212 }
4213 if (rtpDumpPtr->IsActive())
4214 {
4215 rtpDumpPtr->Stop();
4216 }
4217 if (rtpDumpPtr->Start(fileNameUTF8) != 0)
4218 {
4219 _engineStatisticsPtr->SetLastError(
4220 VE_BAD_FILE, kTraceError,
4221 "StartRTPDump() failed to create file");
4222 return -1;
4223 }
4224 return 0;
4225}
4226
4227int
4228Channel::StopRTPDump(RTPDirections direction)
4229{
4230 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4231 "Channel::StopRTPDump()");
4232 if ((direction != kRtpIncoming) && (direction != kRtpOutgoing))
4233 {
4234 _engineStatisticsPtr->SetLastError(
4235 VE_INVALID_ARGUMENT, kTraceError,
4236 "StopRTPDump() invalid RTP direction");
4237 return -1;
4238 }
4239 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4240 &_rtpDumpIn : &_rtpDumpOut;
4241 if (rtpDumpPtr == NULL)
4242 {
4243 assert(false);
4244 return -1;
4245 }
4246 if (!rtpDumpPtr->IsActive())
4247 {
4248 return 0;
4249 }
4250 return rtpDumpPtr->Stop();
4251}
4252
4253bool
4254Channel::RTPDumpIsActive(RTPDirections direction)
4255{
4256 if ((direction != kRtpIncoming) &&
4257 (direction != kRtpOutgoing))
4258 {
4259 _engineStatisticsPtr->SetLastError(
4260 VE_INVALID_ARGUMENT, kTraceError,
4261 "RTPDumpIsActive() invalid RTP direction");
4262 return false;
4263 }
4264 RtpDump* rtpDumpPtr = (direction == kRtpIncoming) ?
4265 &_rtpDumpIn : &_rtpDumpOut;
4266 return rtpDumpPtr->IsActive();
4267}
4268
4269int
4270Channel::InsertExtraRTPPacket(unsigned char payloadType,
4271 bool markerBit,
4272 const char* payloadData,
4273 unsigned short payloadSize)
4274{
4275 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
4276 "Channel::InsertExtraRTPPacket()");
4277 if (payloadType > 127)
4278 {
4279 _engineStatisticsPtr->SetLastError(
4280 VE_INVALID_PLTYPE, kTraceError,
4281 "InsertExtraRTPPacket() invalid payload type");
4282 return -1;
4283 }
4284 if (payloadData == NULL)
4285 {
4286 _engineStatisticsPtr->SetLastError(
4287 VE_INVALID_ARGUMENT, kTraceError,
4288 "InsertExtraRTPPacket() invalid payload data");
4289 return -1;
4290 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004291 if (payloadSize > _rtpRtcpModule->MaxDataPayloadLength())
niklase@google.com470e71d2011-07-07 08:21:25 +00004292 {
4293 _engineStatisticsPtr->SetLastError(
4294 VE_INVALID_ARGUMENT, kTraceError,
4295 "InsertExtraRTPPacket() invalid payload size");
4296 return -1;
4297 }
4298 if (!_sending)
4299 {
4300 _engineStatisticsPtr->SetLastError(
4301 VE_NOT_SENDING, kTraceError,
4302 "InsertExtraRTPPacket() not sending");
4303 return -1;
4304 }
4305
4306 // Create extra RTP packet by calling RtpRtcp::SendOutgoingData().
4307 // Transport::SendPacket() will be called by the module when the RTP packet
4308 // is created.
4309 // The call to SendOutgoingData() does *not* modify the timestamp and
4310 // payloadtype to ensure that the RTP module generates a valid RTP packet
4311 // (user might utilize a non-registered payload type).
4312 // The marker bit and payload type will be replaced just before the actual
4313 // transmission, i.e., the actual modification is done *after* the RTP
4314 // module has delivered its RTP packet back to the VoE.
4315 // We will use the stored values above when the packet is modified
4316 // (see Channel::SendPacket()).
4317
4318 _extraPayloadType = payloadType;
4319 _extraMarkerBit = markerBit;
4320 _insertExtraRTPPacket = true;
4321
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004322 if (_rtpRtcpModule->SendOutgoingData(kAudioFrameSpeech,
niklase@google.com470e71d2011-07-07 08:21:25 +00004323 _lastPayloadType,
4324 _lastLocalTimeStamp,
stefan@webrtc.orgddfdfed2012-07-03 13:21:22 +00004325 // Leaving the time when this frame was
4326 // received from the capture device as
4327 // undefined for voice for now.
4328 -1,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004329 (const uint8_t*) payloadData,
niklase@google.com470e71d2011-07-07 08:21:25 +00004330 payloadSize) != 0)
4331 {
4332 _engineStatisticsPtr->SetLastError(
4333 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4334 "InsertExtraRTPPacket() failed to send extra RTP packet");
4335 return -1;
4336 }
4337
4338 return 0;
4339}
4340
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004341uint32_t
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004342Channel::Demultiplex(const AudioFrame& audioFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +00004343{
4344 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004345 "Channel::Demultiplex()");
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00004346 _audioFrame.CopyFrom(audioFrame);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004347 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004348 return 0;
4349}
4350
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004351// TODO(xians): This method borrows quite some code from
4352// TransmitMixer::GenerateAudioFrame(), refactor these two methods and reduce
4353// code duplication.
4354void Channel::Demultiplex(const int16_t* audio_data,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004355 int sample_rate,
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004356 int number_of_frames,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +00004357 int number_of_channels) {
xians@webrtc.org2f84afa2013-07-31 16:23:37 +00004358 // The highest sample rate that WebRTC supports for mono audio is 96kHz.
4359 static const int kMaxNumberOfFrames = 960;
4360 assert(number_of_frames <= kMaxNumberOfFrames);
4361
4362 // Get the send codec information for doing resampling or downmixing later on.
4363 CodecInst codec;
4364 GetSendCodec(codec);
4365 assert(codec.channels == 1 || codec.channels == 2);
4366 int support_sample_rate = std::min(32000,
4367 std::min(sample_rate, codec.plfreq));
4368
4369 // Downmix the data to mono if needed.
4370 const int16_t* audio_ptr = audio_data;
4371 if (number_of_channels == 2 && codec.channels == 1) {
4372 if (!mono_recording_audio_.get())
4373 mono_recording_audio_.reset(new int16_t[kMaxNumberOfFrames]);
4374
4375 AudioFrameOperations::StereoToMono(audio_data, number_of_frames,
4376 mono_recording_audio_.get());
4377 audio_ptr = mono_recording_audio_.get();
4378 }
4379
4380 // Resample the data to the sample rate that the codec is using.
4381 if (input_resampler_.InitializeIfNeeded(sample_rate,
4382 support_sample_rate,
4383 codec.channels)) {
4384 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4385 "Channel::Demultiplex() unable to resample");
4386 return;
4387 }
4388
4389 int out_length = input_resampler_.Resample(audio_ptr,
4390 number_of_frames * codec.channels,
4391 _audioFrame.data_,
4392 AudioFrame::kMaxDataSizeSamples);
4393 if (out_length == -1) {
4394 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, -1),
4395 "Channel::Demultiplex() resampling failed");
4396 return;
4397 }
4398
4399 _audioFrame.samples_per_channel_ = out_length / codec.channels;
4400 _audioFrame.timestamp_ = -1;
4401 _audioFrame.sample_rate_hz_ = support_sample_rate;
4402 _audioFrame.speech_type_ = AudioFrame::kNormalSpeech;
4403 _audioFrame.vad_activity_ = AudioFrame::kVadUnknown;
4404 _audioFrame.num_channels_ = codec.channels;
4405 _audioFrame.id_ = _channelId;
4406}
4407
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004408uint32_t
xians@google.com0b0665a2011-08-08 08:18:44 +00004409Channel::PrepareEncodeAndSend(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004410{
4411 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4412 "Channel::PrepareEncodeAndSend()");
4413
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004414 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004415 {
4416 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4417 "Channel::PrepareEncodeAndSend() invalid audio frame");
4418 return -1;
4419 }
4420
4421 if (_inputFilePlaying)
4422 {
4423 MixOrReplaceAudioWithFile(mixingFrequency);
4424 }
4425
wu@webrtc.org63420662013-10-17 18:28:55 +00004426 if (Mute())
niklase@google.com470e71d2011-07-07 08:21:25 +00004427 {
4428 AudioFrameOperations::Mute(_audioFrame);
4429 }
4430
4431 if (_inputExternalMedia)
4432 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004433 CriticalSectionScoped cs(&_callbackCritSect);
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004434 const bool isStereo = (_audioFrame.num_channels_ == 2);
niklase@google.com470e71d2011-07-07 08:21:25 +00004435 if (_inputExternalMediaCallbackPtr)
4436 {
4437 _inputExternalMediaCallbackPtr->Process(
4438 _channelId,
4439 kRecordingPerChannel,
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004440 (int16_t*)_audioFrame.data_,
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004441 _audioFrame.samples_per_channel_,
4442 _audioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +00004443 isStereo);
4444 }
4445 }
4446
4447 InsertInbandDtmfTone();
4448
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004449 if (_includeAudioLevelIndication)
4450 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004451 if (rtp_audioproc_->set_sample_rate_hz(_audioFrame.sample_rate_hz_) !=
4452 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004453 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004454 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4455 VoEId(_instanceId, _channelId),
4456 "Error setting AudioProcessing sample rate");
4457 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004458 }
4459
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004460 if (rtp_audioproc_->set_num_channels(_audioFrame.num_channels_,
4461 _audioFrame.num_channels_) !=
4462 AudioProcessing::kNoError)
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004463 {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004464 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4465 VoEId(_instanceId, _channelId),
4466 "Error setting AudioProcessing channels");
4467 return -1;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004468 }
4469
4470 // Performs level analysis only; does not affect the signal.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00004471 rtp_audioproc_->ProcessStream(&_audioFrame);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00004472 }
4473
niklase@google.com470e71d2011-07-07 08:21:25 +00004474 return 0;
4475}
4476
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004477uint32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004478Channel::EncodeAndSend()
4479{
4480 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4481 "Channel::EncodeAndSend()");
4482
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004483 assert(_audioFrame.num_channels_ <= 2);
4484 if (_audioFrame.samples_per_channel_ == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004485 {
4486 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4487 "Channel::EncodeAndSend() invalid audio frame");
4488 return -1;
4489 }
4490
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004491 _audioFrame.id_ = _channelId;
niklase@google.com470e71d2011-07-07 08:21:25 +00004492
4493 // --- Add 10ms of raw (PCM) audio data to the encoder @ 32kHz.
4494
4495 // The ACM resamples internally.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004496 _audioFrame.timestamp_ = _timeStamp;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004497 if (audio_coding_->Add10MsData((AudioFrame&)_audioFrame) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004498 {
4499 WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,_channelId),
4500 "Channel::EncodeAndSend() ACM encoding failed");
4501 return -1;
4502 }
4503
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004504 _timeStamp += _audioFrame.samples_per_channel_;
niklase@google.com470e71d2011-07-07 08:21:25 +00004505
4506 // --- Encode if complete frame is ready
4507
4508 // This call will trigger AudioPacketizationCallback::SendData if encoding
4509 // is done and payload is ready for packetization and transmission.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004510 return audio_coding_->Process();
niklase@google.com470e71d2011-07-07 08:21:25 +00004511}
4512
4513int Channel::RegisterExternalMediaProcessing(
4514 ProcessingTypes type,
4515 VoEMediaProcess& processObject)
4516{
4517 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4518 "Channel::RegisterExternalMediaProcessing()");
4519
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004520 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004521
4522 if (kPlaybackPerChannel == type)
4523 {
4524 if (_outputExternalMediaCallbackPtr)
4525 {
4526 _engineStatisticsPtr->SetLastError(
4527 VE_INVALID_OPERATION, kTraceError,
4528 "Channel::RegisterExternalMediaProcessing() "
4529 "output external media already enabled");
4530 return -1;
4531 }
4532 _outputExternalMediaCallbackPtr = &processObject;
4533 _outputExternalMedia = true;
4534 }
4535 else if (kRecordingPerChannel == type)
4536 {
4537 if (_inputExternalMediaCallbackPtr)
4538 {
4539 _engineStatisticsPtr->SetLastError(
4540 VE_INVALID_OPERATION, kTraceError,
4541 "Channel::RegisterExternalMediaProcessing() "
4542 "output external media already enabled");
4543 return -1;
4544 }
4545 _inputExternalMediaCallbackPtr = &processObject;
4546 _inputExternalMedia = true;
4547 }
4548 return 0;
4549}
4550
4551int Channel::DeRegisterExternalMediaProcessing(ProcessingTypes type)
4552{
4553 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4554 "Channel::DeRegisterExternalMediaProcessing()");
4555
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004556 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004557
4558 if (kPlaybackPerChannel == type)
4559 {
4560 if (!_outputExternalMediaCallbackPtr)
4561 {
4562 _engineStatisticsPtr->SetLastError(
4563 VE_INVALID_OPERATION, kTraceWarning,
4564 "Channel::DeRegisterExternalMediaProcessing() "
4565 "output external media already disabled");
4566 return 0;
4567 }
4568 _outputExternalMedia = false;
4569 _outputExternalMediaCallbackPtr = NULL;
4570 }
4571 else if (kRecordingPerChannel == type)
4572 {
4573 if (!_inputExternalMediaCallbackPtr)
4574 {
4575 _engineStatisticsPtr->SetLastError(
4576 VE_INVALID_OPERATION, kTraceWarning,
4577 "Channel::DeRegisterExternalMediaProcessing() "
4578 "input external media already disabled");
4579 return 0;
4580 }
4581 _inputExternalMedia = false;
4582 _inputExternalMediaCallbackPtr = NULL;
4583 }
4584
4585 return 0;
4586}
4587
roosa@google.com1b60ceb2012-12-12 23:00:29 +00004588int Channel::SetExternalMixing(bool enabled) {
4589 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4590 "Channel::SetExternalMixing(enabled=%d)", enabled);
4591
4592 if (_playing)
4593 {
4594 _engineStatisticsPtr->SetLastError(
4595 VE_INVALID_OPERATION, kTraceError,
4596 "Channel::SetExternalMixing() "
4597 "external mixing cannot be changed while playing.");
4598 return -1;
4599 }
4600
4601 _externalMixing = enabled;
4602
4603 return 0;
4604}
4605
niklase@google.com470e71d2011-07-07 08:21:25 +00004606int
4607Channel::ResetRTCPStatistics()
4608{
4609 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4610 "Channel::ResetRTCPStatistics()");
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004611 uint32_t remoteSSRC(0);
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004612 remoteSSRC = rtp_receiver_->SSRC();
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004613 return _rtpRtcpModule->ResetRTT(remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00004614}
4615
4616int
4617Channel::GetRoundTripTimeSummary(StatVal& delaysMs) const
4618{
4619 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4620 "Channel::GetRoundTripTimeSummary()");
4621 // Override default module outputs for the case when RTCP is disabled.
4622 // This is done to ensure that we are backward compatible with the
4623 // VoiceEngine where we did not use RTP/RTCP module.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004624 if (!_rtpRtcpModule->RTCP())
niklase@google.com470e71d2011-07-07 08:21:25 +00004625 {
4626 delaysMs.min = -1;
4627 delaysMs.max = -1;
4628 delaysMs.average = -1;
4629 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4630 "Channel::GetRoundTripTimeSummary() RTCP is disabled =>"
4631 " valid RTT measurements cannot be retrieved");
4632 return 0;
4633 }
4634
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004635 uint32_t remoteSSRC;
4636 uint16_t RTT;
4637 uint16_t avgRTT;
4638 uint16_t maxRTT;
4639 uint16_t minRTT;
niklase@google.com470e71d2011-07-07 08:21:25 +00004640 // The remote SSRC will be zero if no RTP packet has been received.
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004641 remoteSSRC = rtp_receiver_->SSRC();
niklase@google.com470e71d2011-07-07 08:21:25 +00004642 if (remoteSSRC == 0)
4643 {
4644 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4645 "Channel::GetRoundTripTimeSummary() unable to measure RTT"
4646 " since no RTP packet has been received yet");
4647 }
4648
4649 // Retrieve RTT statistics from the RTP/RTCP module for the specified
4650 // channel and SSRC. The SSRC is required to parse out the correct source
4651 // in conference scenarios.
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004652 if (_rtpRtcpModule->RTT(remoteSSRC, &RTT, &avgRTT, &minRTT,&maxRTT) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004653 {
4654 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4655 "GetRoundTripTimeSummary unable to retrieve RTT values"
4656 " from the RTCP layer");
4657 delaysMs.min = -1; delaysMs.max = -1; delaysMs.average = -1;
4658 }
4659 else
4660 {
4661 delaysMs.min = minRTT;
4662 delaysMs.max = maxRTT;
4663 delaysMs.average = avgRTT;
4664 }
4665 return 0;
4666}
4667
4668int
4669Channel::GetNetworkStatistics(NetworkStatistics& stats)
4670{
4671 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4672 "Channel::GetNetworkStatistics()");
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004673 ACMNetworkStatistics acm_stats;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004674 int return_value = audio_coding_->NetworkStatistics(&acm_stats);
tina.legrand@webrtc.org7a7a0082013-02-21 10:27:48 +00004675 if (return_value >= 0) {
4676 memcpy(&stats, &acm_stats, sizeof(NetworkStatistics));
4677 }
4678 return return_value;
niklase@google.com470e71d2011-07-07 08:21:25 +00004679}
4680
wu@webrtc.org24301a62013-12-13 19:17:43 +00004681void Channel::GetDecodingCallStatistics(AudioDecodingCallStats* stats) const {
4682 audio_coding_->GetDecodingCallStatistics(stats);
4683}
4684
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004685bool Channel::GetDelayEstimate(int* jitter_buffer_delay_ms,
4686 int* playout_buffer_delay_ms) const {
4687 if (_average_jitter_buffer_delay_us == 0) {
niklase@google.com470e71d2011-07-07 08:21:25 +00004688 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004689 "Channel::GetDelayEstimate() no valid estimate.");
4690 return false;
4691 }
4692 *jitter_buffer_delay_ms = (_average_jitter_buffer_delay_us + 500) / 1000 +
4693 _recPacketDelayMs;
4694 *playout_buffer_delay_ms = playout_delay_ms_;
4695 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4696 "Channel::GetDelayEstimate()");
4697 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00004698}
4699
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004700int Channel::SetInitialPlayoutDelay(int delay_ms)
4701{
4702 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4703 "Channel::SetInitialPlayoutDelay()");
4704 if ((delay_ms < kVoiceEngineMinMinPlayoutDelayMs) ||
4705 (delay_ms > kVoiceEngineMaxMinPlayoutDelayMs))
4706 {
4707 _engineStatisticsPtr->SetLastError(
4708 VE_INVALID_ARGUMENT, kTraceError,
4709 "SetInitialPlayoutDelay() invalid min delay");
4710 return -1;
4711 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004712 if (audio_coding_->SetInitialPlayoutDelay(delay_ms) != 0)
turaj@webrtc.org6388c3e2013-02-12 21:42:18 +00004713 {
4714 _engineStatisticsPtr->SetLastError(
4715 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4716 "SetInitialPlayoutDelay() failed to set min playout delay");
4717 return -1;
4718 }
4719 return 0;
4720}
4721
4722
niklase@google.com470e71d2011-07-07 08:21:25 +00004723int
4724Channel::SetMinimumPlayoutDelay(int delayMs)
4725{
4726 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4727 "Channel::SetMinimumPlayoutDelay()");
4728 if ((delayMs < kVoiceEngineMinMinPlayoutDelayMs) ||
4729 (delayMs > kVoiceEngineMaxMinPlayoutDelayMs))
4730 {
4731 _engineStatisticsPtr->SetLastError(
4732 VE_INVALID_ARGUMENT, kTraceError,
4733 "SetMinimumPlayoutDelay() invalid min delay");
4734 return -1;
4735 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004736 if (audio_coding_->SetMinimumPlayoutDelay(delayMs) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004737 {
4738 _engineStatisticsPtr->SetLastError(
4739 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
4740 "SetMinimumPlayoutDelay() failed to set min playout delay");
4741 return -1;
4742 }
4743 return 0;
4744}
4745
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004746void Channel::UpdatePlayoutTimestamp(bool rtcp) {
4747 uint32_t playout_timestamp = 0;
4748
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004749 if (audio_coding_->PlayoutTimestamp(&playout_timestamp) == -1) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004750 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4751 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4752 " timestamp from the ACM");
4753 _engineStatisticsPtr->SetLastError(
4754 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4755 "UpdatePlayoutTimestamp() failed to retrieve timestamp");
4756 return;
4757 }
4758
4759 uint16_t delay_ms = 0;
4760 if (_audioDeviceModulePtr->PlayoutDelay(&delay_ms) == -1) {
4761 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
4762 "Channel::UpdatePlayoutTimestamp() failed to read playout"
4763 " delay from the ADM");
4764 _engineStatisticsPtr->SetLastError(
4765 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4766 "UpdatePlayoutTimestamp() failed to retrieve playout delay");
4767 return;
4768 }
4769
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004770 int32_t playout_frequency = audio_coding_->PlayoutFrequency();
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004771 CodecInst current_recive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00004772 if (audio_coding_->ReceiveCodec(&current_recive_codec) == 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004773 if (STR_CASE_CMP("G722", current_recive_codec.plname) == 0) {
4774 playout_frequency = 8000;
4775 } else if (STR_CASE_CMP("opus", current_recive_codec.plname) == 0) {
4776 playout_frequency = 48000;
niklase@google.com470e71d2011-07-07 08:21:25 +00004777 }
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004778 }
4779
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00004780 jitter_buffer_playout_timestamp_ = playout_timestamp;
4781
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00004782 // Remove the playout delay.
4783 playout_timestamp -= (delay_ms * (playout_frequency / 1000));
4784
4785 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
4786 "Channel::UpdatePlayoutTimestamp() => playoutTimestamp = %lu",
4787 playout_timestamp);
4788
4789 if (rtcp) {
4790 playout_timestamp_rtcp_ = playout_timestamp;
4791 } else {
4792 playout_timestamp_rtp_ = playout_timestamp;
4793 }
4794 playout_delay_ms_ = delay_ms;
4795}
4796
4797int Channel::GetPlayoutTimestamp(unsigned int& timestamp) {
4798 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4799 "Channel::GetPlayoutTimestamp()");
4800 if (playout_timestamp_rtp_ == 0) {
4801 _engineStatisticsPtr->SetLastError(
4802 VE_CANNOT_RETRIEVE_VALUE, kTraceError,
4803 "GetPlayoutTimestamp() failed to retrieve timestamp");
4804 return -1;
4805 }
4806 timestamp = playout_timestamp_rtp_;
4807 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice,
4808 VoEId(_instanceId,_channelId),
4809 "GetPlayoutTimestamp() => timestamp=%u", timestamp);
4810 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00004811}
4812
4813int
4814Channel::SetInitTimestamp(unsigned int timestamp)
4815{
4816 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4817 "Channel::SetInitTimestamp()");
4818 if (_sending)
4819 {
4820 _engineStatisticsPtr->SetLastError(
4821 VE_SENDING, kTraceError, "SetInitTimestamp() already sending");
4822 return -1;
4823 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004824 if (_rtpRtcpModule->SetStartTimestamp(timestamp) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004825 {
4826 _engineStatisticsPtr->SetLastError(
4827 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4828 "SetInitTimestamp() failed to set timestamp");
4829 return -1;
4830 }
4831 return 0;
4832}
4833
4834int
4835Channel::SetInitSequenceNumber(short sequenceNumber)
4836{
4837 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4838 "Channel::SetInitSequenceNumber()");
4839 if (_sending)
4840 {
4841 _engineStatisticsPtr->SetLastError(
4842 VE_SENDING, kTraceError,
4843 "SetInitSequenceNumber() already sending");
4844 return -1;
4845 }
pwestin@webrtc.org2853dde2012-05-11 11:08:54 +00004846 if (_rtpRtcpModule->SetSequenceNumber(sequenceNumber) != 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00004847 {
4848 _engineStatisticsPtr->SetLastError(
4849 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
4850 "SetInitSequenceNumber() failed to set sequence number");
4851 return -1;
4852 }
4853 return 0;
4854}
4855
4856int
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004857Channel::GetRtpRtcp(RtpRtcp** rtpRtcpModule, RtpReceiver** rtp_receiver) const
niklase@google.com470e71d2011-07-07 08:21:25 +00004858{
4859 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
4860 "Channel::GetRtpRtcp()");
wu@webrtc.org822fbd82013-08-15 23:38:54 +00004861 *rtpRtcpModule = _rtpRtcpModule.get();
4862 *rtp_receiver = rtp_receiver_.get();
niklase@google.com470e71d2011-07-07 08:21:25 +00004863 return 0;
4864}
4865
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004866// TODO(andrew): refactor Mix functions here and in transmit_mixer.cc to use
4867// a shared helper.
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004868int32_t
pbos@webrtc.org92135212013-05-14 08:31:39 +00004869Channel::MixOrReplaceAudioWithFile(int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004870{
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004871 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004872 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004873
4874 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004875 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004876
4877 if (_inputFilePlayerPtr == NULL)
4878 {
4879 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4880 VoEId(_instanceId, _channelId),
4881 "Channel::MixOrReplaceAudioWithFile() fileplayer"
4882 " doesnt exist");
4883 return -1;
4884 }
4885
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004886 if (_inputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004887 fileSamples,
4888 mixingFrequency) == -1)
4889 {
4890 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4891 VoEId(_instanceId, _channelId),
4892 "Channel::MixOrReplaceAudioWithFile() file mixing "
4893 "failed");
4894 return -1;
4895 }
4896 if (fileSamples == 0)
4897 {
4898 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4899 VoEId(_instanceId, _channelId),
4900 "Channel::MixOrReplaceAudioWithFile() file is ended");
4901 return 0;
4902 }
4903 }
4904
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004905 assert(_audioFrame.samples_per_channel_ == fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004906
4907 if (_mixFileWithMicrophone)
4908 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004909 // Currently file stream is always mono.
4910 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004911 Utility::MixWithSat(_audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004912 _audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004913 fileBuffer.get(),
4914 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004915 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004916 }
4917 else
4918 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004919 // Replace ACM audio with file.
4920 // Currently file stream is always mono.
4921 // TODO(xians): Change the code when FilePlayer supports real stereo.
niklase@google.com470e71d2011-07-07 08:21:25 +00004922 _audioFrame.UpdateFrame(_channelId,
4923 -1,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004924 fileBuffer.get(),
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004925 fileSamples,
niklase@google.com470e71d2011-07-07 08:21:25 +00004926 mixingFrequency,
4927 AudioFrame::kNormalSpeech,
4928 AudioFrame::kVadUnknown,
4929 1);
4930
4931 }
4932 return 0;
4933}
4934
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004935int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00004936Channel::MixAudioWithFile(AudioFrame& audioFrame,
pbos@webrtc.org92135212013-05-14 08:31:39 +00004937 int mixingFrequency)
niklase@google.com470e71d2011-07-07 08:21:25 +00004938{
4939 assert(mixingFrequency <= 32000);
4940
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004941 scoped_array<int16_t> fileBuffer(new int16_t[640]);
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004942 int fileSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00004943
4944 {
mflodman@webrtc.org9a065d12012-03-07 08:12:21 +00004945 CriticalSectionScoped cs(&_fileCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00004946
4947 if (_outputFilePlayerPtr == NULL)
4948 {
4949 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4950 VoEId(_instanceId, _channelId),
4951 "Channel::MixAudioWithFile() file mixing failed");
4952 return -1;
4953 }
4954
4955 // We should get the frequency we ask for.
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004956 if (_outputFilePlayerPtr->Get10msAudioFromFile(fileBuffer.get(),
niklase@google.com470e71d2011-07-07 08:21:25 +00004957 fileSamples,
4958 mixingFrequency) == -1)
4959 {
4960 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
4961 VoEId(_instanceId, _channelId),
4962 "Channel::MixAudioWithFile() file mixing failed");
4963 return -1;
4964 }
4965 }
4966
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004967 if (audioFrame.samples_per_channel_ == fileSamples)
niklase@google.com470e71d2011-07-07 08:21:25 +00004968 {
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004969 // Currently file stream is always mono.
4970 // TODO(xians): Change the code when FilePlayer supports real stereo.
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004971 Utility::MixWithSat(audioFrame.data_,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004972 audioFrame.num_channels_,
braveyao@webrtc.orgd7131432012-03-29 10:39:44 +00004973 fileBuffer.get(),
4974 1,
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +00004975 fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004976 }
4977 else
4978 {
4979 WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,_channelId),
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004980 "Channel::MixAudioWithFile() samples_per_channel_(%d) != "
niklase@google.com470e71d2011-07-07 08:21:25 +00004981 "fileSamples(%d)",
andrew@webrtc.org63a50982012-05-02 23:56:37 +00004982 audioFrame.samples_per_channel_, fileSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00004983 return -1;
4984 }
4985
4986 return 0;
4987}
4988
4989int
4990Channel::InsertInbandDtmfTone()
4991{
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00004992 // Check if we should start a new tone.
niklase@google.com470e71d2011-07-07 08:21:25 +00004993 if (_inbandDtmfQueue.PendingDtmf() &&
4994 !_inbandDtmfGenerator.IsAddingTone() &&
4995 _inbandDtmfGenerator.DelaySinceLastTone() >
4996 kMinTelephoneEventSeparationMs)
4997 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00004998 int8_t eventCode(0);
4999 uint16_t lengthMs(0);
5000 uint8_t attenuationDb(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005001
5002 eventCode = _inbandDtmfQueue.NextDtmf(&lengthMs, &attenuationDb);
5003 _inbandDtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb);
5004 if (_playInbandDtmfEvent)
5005 {
5006 // Add tone to output mixer using a reduced length to minimize
5007 // risk of echo.
5008 _outputMixerPtr->PlayDtmfTone(eventCode, lengthMs - 80,
5009 attenuationDb);
5010 }
5011 }
5012
5013 if (_inbandDtmfGenerator.IsAddingTone())
5014 {
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005015 uint16_t frequency(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005016 _inbandDtmfGenerator.GetSampleRate(frequency);
5017
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005018 if (frequency != _audioFrame.sample_rate_hz_)
niklase@google.com470e71d2011-07-07 08:21:25 +00005019 {
5020 // Update sample rate of Dtmf tone since the mixing frequency
5021 // has changed.
5022 _inbandDtmfGenerator.SetSampleRate(
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005023 (uint16_t) (_audioFrame.sample_rate_hz_));
niklase@google.com470e71d2011-07-07 08:21:25 +00005024 // Reset the tone to be added taking the new sample rate into
5025 // account.
5026 _inbandDtmfGenerator.ResetTone();
5027 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005028
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005029 int16_t toneBuffer[320];
5030 uint16_t toneSamples(0);
niklase@google.com470e71d2011-07-07 08:21:25 +00005031 // Get 10ms tone segment and set time since last tone to zero
5032 if (_inbandDtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
5033 {
5034 WEBRTC_TRACE(kTraceWarning, kTraceVoice,
5035 VoEId(_instanceId, _channelId),
5036 "Channel::EncodeAndSend() inserting Dtmf failed");
5037 return -1;
5038 }
5039
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005040 // Replace mixed audio with DTMF tone.
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005041 for (int sample = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005042 sample < _audioFrame.samples_per_channel_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005043 sample++)
5044 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005045 for (int channel = 0;
5046 channel < _audioFrame.num_channels_;
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005047 channel++)
5048 {
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005049 const int index = sample * _audioFrame.num_channels_ + channel;
5050 _audioFrame.data_[index] = toneBuffer[sample];
niklas.enbom@webrtc.orgaf26f642011-11-16 12:41:36 +00005051 }
5052 }
andrew@webrtc.orgae1a58b2013-01-22 04:44:30 +00005053
andrew@webrtc.org63a50982012-05-02 23:56:37 +00005054 assert(_audioFrame.samples_per_channel_ == toneSamples);
niklase@google.com470e71d2011-07-07 08:21:25 +00005055 } else
5056 {
5057 // Add 10ms to "delay-since-last-tone" counter
5058 _inbandDtmfGenerator.UpdateDelaySinceLastTone();
5059 }
5060 return 0;
5061}
5062
niklase@google.com470e71d2011-07-07 08:21:25 +00005063void
5064Channel::ResetDeadOrAliveCounters()
5065{
5066 _countDeadDetections = 0;
5067 _countAliveDetections = 0;
5068}
5069
5070void
5071Channel::UpdateDeadOrAliveCounters(bool alive)
5072{
5073 if (alive)
5074 _countAliveDetections++;
5075 else
5076 _countDeadDetections++;
5077}
5078
5079int
5080Channel::GetDeadOrAliveCounters(int& countDead, int& countAlive) const
5081{
niklase@google.com470e71d2011-07-07 08:21:25 +00005082 return 0;
5083}
5084
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005085int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00005086Channel::SendPacketRaw(const void *data, int len, bool RTCP)
5087{
wu@webrtc.orgfb648da2013-10-18 21:10:51 +00005088 CriticalSectionScoped cs(&_callbackCritSect);
niklase@google.com470e71d2011-07-07 08:21:25 +00005089 if (_transportPtr == NULL)
5090 {
5091 return -1;
5092 }
5093 if (!RTCP)
5094 {
5095 return _transportPtr->SendPacket(_channelId, data, len);
5096 }
5097 else
5098 {
5099 return _transportPtr->SendRTCPPacket(_channelId, data, len);
5100 }
5101}
5102
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005103// Called for incoming RTP packets after successful RTP header parsing.
5104void Channel::UpdatePacketDelay(uint32_t rtp_timestamp,
5105 uint16_t sequence_number) {
5106 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,_channelId),
5107 "Channel::UpdatePacketDelay(timestamp=%lu, sequenceNumber=%u)",
5108 rtp_timestamp, sequence_number);
niklase@google.com470e71d2011-07-07 08:21:25 +00005109
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005110 // Get frequency of last received payload
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005111 int rtp_receive_frequency = audio_coding_->ReceiveFrequency();
niklase@google.com470e71d2011-07-07 08:21:25 +00005112
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005113 CodecInst current_receive_codec;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005114 if (audio_coding_->ReceiveCodec(&current_receive_codec) != 0) {
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005115 return;
5116 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005117
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005118 // Update the least required delay.
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005119 least_required_delay_ms_ = audio_coding_->LeastRequiredDelayMs();
turaj@webrtc.orge46c8d32013-05-22 20:39:43 +00005120
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005121 if (STR_CASE_CMP("G722", current_receive_codec.plname) == 0) {
5122 // Even though the actual sampling rate for G.722 audio is
5123 // 16,000 Hz, the RTP clock rate for the G722 payload format is
5124 // 8,000 Hz because that value was erroneously assigned in
5125 // RFC 1890 and must remain unchanged for backward compatibility.
5126 rtp_receive_frequency = 8000;
5127 } else if (STR_CASE_CMP("opus", current_receive_codec.plname) == 0) {
5128 // We are resampling Opus internally to 32,000 Hz until all our
5129 // DSP routines can operate at 48,000 Hz, but the RTP clock
5130 // rate for the Opus payload format is standardized to 48,000 Hz,
5131 // because that is the maximum supported decoding sampling rate.
5132 rtp_receive_frequency = 48000;
5133 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005134
turaj@webrtc.org167b6df2013-12-13 21:05:07 +00005135 // |jitter_buffer_playout_timestamp_| updated in UpdatePlayoutTimestamp for
5136 // every incoming packet.
5137 uint32_t timestamp_diff_ms = (rtp_timestamp -
5138 jitter_buffer_playout_timestamp_) / (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005139
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005140 uint16_t packet_delay_ms = (rtp_timestamp - _previousTimestamp) /
5141 (rtp_receive_frequency / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +00005142
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005143 _previousTimestamp = rtp_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +00005144
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005145 if (timestamp_diff_ms > (2 * kVoiceEngineMaxMinPlayoutDelayMs)) {
5146 timestamp_diff_ms = 0;
5147 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005148
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005149 if (timestamp_diff_ms == 0) return;
niklase@google.com470e71d2011-07-07 08:21:25 +00005150
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005151 if (packet_delay_ms >= 10 && packet_delay_ms <= 60) {
5152 _recPacketDelayMs = packet_delay_ms;
5153 }
niklase@google.com470e71d2011-07-07 08:21:25 +00005154
pwestin@webrtc.org1de01352013-04-11 20:23:35 +00005155 if (_average_jitter_buffer_delay_us == 0) {
5156 _average_jitter_buffer_delay_us = timestamp_diff_ms * 1000;
5157 return;
5158 }
5159
5160 // Filter average delay value using exponential filter (alpha is
5161 // 7/8). We derive 1000 *_average_jitter_buffer_delay_us here (reduces
5162 // risk of rounding error) and compensate for it in GetDelayEstimate()
5163 // later.
5164 _average_jitter_buffer_delay_us = (_average_jitter_buffer_delay_us * 7 +
5165 1000 * timestamp_diff_ms + 500) / 8;
niklase@google.com470e71d2011-07-07 08:21:25 +00005166}
5167
5168void
5169Channel::RegisterReceiveCodecsToRTPModule()
5170{
5171 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,_channelId),
5172 "Channel::RegisterReceiveCodecsToRTPModule()");
5173
5174
5175 CodecInst codec;
pbos@webrtc.org6141e132013-04-09 10:09:10 +00005176 const uint8_t nSupportedCodecs = AudioCodingModule::NumberOfCodecs();
niklase@google.com470e71d2011-07-07 08:21:25 +00005177
5178 for (int idx = 0; idx < nSupportedCodecs; idx++)
5179 {
5180 // Open up the RTP/RTCP receiver for all supported codecs
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005181 if ((audio_coding_->Codec(idx, &codec) == -1) ||
wu@webrtc.org822fbd82013-08-15 23:38:54 +00005182 (rtp_receiver_->RegisterReceivePayload(
5183 codec.plname,
5184 codec.pltype,
5185 codec.plfreq,
5186 codec.channels,
5187 (codec.rate < 0) ? 0 : codec.rate) == -1))
niklase@google.com470e71d2011-07-07 08:21:25 +00005188 {
5189 WEBRTC_TRACE(
5190 kTraceWarning,
5191 kTraceVoice,
5192 VoEId(_instanceId, _channelId),
5193 "Channel::RegisterReceiveCodecsToRTPModule() unable"
5194 " to register %s (%d/%d/%d/%d) to RTP/RTCP receiver",
5195 codec.plname, codec.pltype, codec.plfreq,
5196 codec.channels, codec.rate);
5197 }
5198 else
5199 {
5200 WEBRTC_TRACE(
5201 kTraceInfo,
5202 kTraceVoice,
5203 VoEId(_instanceId, _channelId),
5204 "Channel::RegisterReceiveCodecsToRTPModule() %s "
wu@webrtc.orgfcd12b32011-09-15 20:49:50 +00005205 "(%d/%d/%d/%d) has been added to the RTP/RTCP "
niklase@google.com470e71d2011-07-07 08:21:25 +00005206 "receiver",
5207 codec.plname, codec.pltype, codec.plfreq,
5208 codec.channels, codec.rate);
5209 }
5210 }
5211}
5212
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005213int Channel::ApmProcessRx(AudioFrame& frame) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005214 // Register the (possibly new) frame parameters.
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005215 if (rx_audioproc_->set_sample_rate_hz(frame.sample_rate_hz_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005216 assert(false);
5217 LOG_FERR1(LS_ERROR, set_sample_rate_hz, frame.sample_rate_hz_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005218 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005219 if (rx_audioproc_->set_num_channels(frame.num_channels_,
5220 frame.num_channels_) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005221 assert(false);
5222 LOG_FERR2(LS_ERROR, set_num_channels, frame.num_channels_,
5223 frame.num_channels_);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005224 }
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +00005225 if (rx_audioproc_->ProcessStream(&frame) != 0) {
andrew@webrtc.org6c264cc2013-10-04 17:54:09 +00005226 assert(false);
5227 LOG_FERR0(LS_ERROR, ProcessStream);
andrew@webrtc.org50419b02012-11-14 19:07:54 +00005228 }
5229 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00005230}
5231
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005232int Channel::SetSecondarySendCodec(const CodecInst& codec,
5233 int red_payload_type) {
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005234 // Sanity check for payload type.
5235 if (red_payload_type < 0 || red_payload_type > 127) {
5236 _engineStatisticsPtr->SetLastError(
5237 VE_PLTYPE_ERROR, kTraceError,
5238 "SetRedPayloadType() invalid RED payload type");
5239 return -1;
5240 }
5241
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005242 if (SetRedPayloadType(red_payload_type) < 0) {
5243 _engineStatisticsPtr->SetLastError(
5244 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5245 "SetSecondarySendCodec() Failed to register RED ACM");
5246 return -1;
5247 }
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005248 if (audio_coding_->RegisterSecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005249 _engineStatisticsPtr->SetLastError(
5250 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5251 "SetSecondarySendCodec() Failed to register secondary send codec in "
5252 "ACM");
5253 return -1;
5254 }
5255
5256 return 0;
5257}
5258
5259void Channel::RemoveSecondarySendCodec() {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005260 audio_coding_->UnregisterSecondarySendCodec();
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005261}
5262
5263int Channel::GetSecondarySendCodec(CodecInst* codec) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005264 if (audio_coding_->SecondarySendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005265 _engineStatisticsPtr->SetLastError(
5266 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5267 "GetSecondarySendCodec() Failed to get secondary sent codec from ACM");
5268 return -1;
5269 }
5270 return 0;
5271}
5272
turaj@webrtc.org8c8ad852013-01-31 18:20:17 +00005273// Assuming this method is called with valid payload type.
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005274int Channel::SetRedPayloadType(int red_payload_type) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005275 CodecInst codec;
5276 bool found_red = false;
5277
5278 // Get default RED settings from the ACM database
5279 const int num_codecs = AudioCodingModule::NumberOfCodecs();
5280 for (int idx = 0; idx < num_codecs; idx++) {
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005281 audio_coding_->Codec(idx, &codec);
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005282 if (!STR_CASE_CMP(codec.plname, "RED")) {
5283 found_red = true;
5284 break;
5285 }
5286 }
5287
5288 if (!found_red) {
5289 _engineStatisticsPtr->SetLastError(
5290 VE_CODEC_ERROR, kTraceError,
5291 "SetRedPayloadType() RED is not supported");
5292 return -1;
5293 }
5294
turaj@webrtc.org9d532fd2013-01-31 18:34:19 +00005295 codec.pltype = red_payload_type;
andrew@webrtc.orgeb524d92013-09-23 23:02:24 +00005296 if (audio_coding_->RegisterSendCodec(codec) < 0) {
turaj@webrtc.org42259e72012-12-11 02:15:12 +00005297 _engineStatisticsPtr->SetLastError(
5298 VE_AUDIO_CODING_MODULE_ERROR, kTraceError,
5299 "SetRedPayloadType() RED registration in ACM module failed");
5300 return -1;
5301 }
5302
5303 if (_rtpRtcpModule->SetSendREDPayloadType(red_payload_type) != 0) {
5304 _engineStatisticsPtr->SetLastError(
5305 VE_RTP_RTCP_MODULE_ERROR, kTraceError,
5306 "SetRedPayloadType() RED registration in RTP/RTCP module failed");
5307 return -1;
5308 }
5309 return 0;
5310}
5311
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00005312} // namespace voe
5313} // namespace webrtc